[Raspi] 블루투스로 LED 제어하기

블루투스 모듈 설치

!sudo apt-get install bluez libbluetooth-dev pi-bluetooth

시리얼포트등록

!sudo nano /lib/systemd/system/bluetooth.service
# ExecStart=/usr/lib/bluetooth/bluetoothd -C 로 수정
!sudo systemctl daemon-reload  # 설정 수정사항 재로딩
!sudo systemctl restart bluetooth # 블루투스 서비스 재실행
!sudo systemctl enable bluetooth # 재부팅 시 서비스 자동 등록

pybluez 모듈 설치

!sudo pip3 install pybluez pybleno

bluetoothctl > 블루투스 쉘 접속 + paring
* HC-06 블루투스 모듈은 자체 페어링(마스터 자동 연결) 기능이 지원되기 때문에 선제적으로 페어링을 해주지 않아도 된다.

sudo bluetoothctl
[bluetooth] discoverable on
[bluetooth] scan on
[bluetooth] agent on
[bluetooth] pair <MAC>

블루투스 소켓 통신

import bluetooth

server_socket=bluetooth.BluetoothSocket(bluetooth.RFCOMM)
port = 1
server_socket.bind(("",port)) # bind(host, port) > 포트 맵핑
server_socket.listen(1) # bind 완료 후 listening:  클라이언트가 바인드된 포트로 연결을 할 때까지 기다리는 블럭킹 함수
client_socket,address = server_socket.accept() # tuple(소켓, 주소정보) 리턴
while 1:
    data = client_socket.recv(1024)
    msg = data.decode()[:-2]
    print("Received: %s" % msg)
    client_socket.sendall(data)
    if (len(msg) == 6):
        print ("Quit")
        break
client_socket.close()
server_socket.close()

소켓 통신에서 Server는 보통 최초의 수신자가 되는 노드를 의미한다. 따라서 Server socket을 만들고 port를 mapping한(binding) 다음 클라이언트가 접속하기를 기다리게(listening) 된다.

클라이언트로부터 연결 요청이 들어오면 listen() 함수가 리턴하게 되는데, 따라서 listen()의 다음 행에는 해당 연결을 받아들이기 위한 accept() 메소드를 호출하는 부분이 주로 오게 된다.

accept() 메소드는 tuple(클라이언트 소켓, 주소 정보) 를 리턴한다. 이 때의 소켓은 처음 소켓과는 별개의 객체로 클라이언트와 연결이 구성되어 실제로 데이터를 주고 받을 수 있는 창구 역할을 한다.

이 소켓은 연결이 들어와서 listen, accept가 호출될 때마다 생성될 수 있기 때문에 연결이 구성된 소켓을 멀티스레드로 처리한다면 1:N 연결도 처리할 수 있다.

소켓으로부터 데이터를 읽을 때는 sock.recv(), 보낼때는 sock.sendall() (* send() 메소드의 경우 리턴값이 존재, 실제 전송된 바이트 수를 리턴)을 사용한다.
recv(bufsize) : 최대 bufsize 바이트 만큼의 데이터틀 읽어온다. 데이터가 없다면 상대방이 데이터를 보내줄때까지 대기한다.
읽어들인 데이터는 bytes 타입의 바이트 시퀀스이며, 데이터를 보낼때에도 바이트시퀀스를 보내야 한다. 만약 문자열을 주고 받고 싶다면 해당 문자열을 인코딩/디코딩해서 전달해야 한다.

소켓 역시 외부 리소스를 열어서 사용하는 것이므로 닫는 것이 중요하다. 서버와 클라이언트 모두 소켓을 닫아야 한다. 참고로 소켓 객체는 컨텍스트 매니저 프로토콜을 지원하므로 with 구문과 함께 사용하면 안전하게 닫히는 것을 보장할 수 있다.

클라이언트가 서버와 통신하는 방법도 비슷하다. 다만 클라이언트는 바인드나 리스닝의 과정이 필요없다. 클라이언트는 능동적으로 서버에 연결하며, 연결된 소켓으로 항상 1:1로 서버와 통신한다. 연결은 connect()를 사용하며 이때 사용하는 인자는 bind()와 동일하다. 리턴값은 없다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다