[Raspberrypi/Linux] RaspberryPi/Linux 에서 블루투스 저전력(BLE) 서버 예제
카테고리: Server
라즈베리파이 설정
라즈베리파이 설정법 입니다. BlueZ 라이브러리를 사용하는 예제 입니다.
BlueZ란 Linux의 공식 블루투스 프로토콜 스택 입니다.
BLE와 클래식을 모두 지원하며, bluetoothd 라는 데몬(서비스)를 통해 장치를 제어합니다.
설치 후, 버전을 확인하여 설치가 되었는지 확인합니다.
bluetoothctl -v
# 또는
dpkg -s bluez | grep Version
라즈베리파이 OS에 패키지 설치
- 라즈베리 파이는 3B버전 부터 블루투스 모듈이 내장되어 별도 동글이 필요 없습니다.
- 블루투스 관련 펌웨어/드라이버가 포함되어 있기 때문에, 위 명령으로 BlueZ를 설치하면 대부분 동작합니다.
- bluez : 블루투스 프로토콜 스택
- bluez-tools :
bluetoothctl
,hciconfig
등의 명령어를 포함
sudo apt-get update
sudo apt-get install -y bluez bluez-tools
BLuetooth 데몬 활성화 / 확인
데몬은 백그라운드에서 돌아가는 서비스를 말합니다. 다음 명령어들로 상태를 확인 합니다.
systemctl status bluetooth
- 상태가 active(running) 이면 정상.
- 만약
inactive
,failed
가 뜨면 다음의 명령어를 입력 합니다.
sudo systemctl start bluetooth
sudo systemctl enable bluetooth # 부팅 시 자동 시작
Bluetoothctl 명령어로 설정하기
bluetoothctl 은 bluetooth 설정을 담당하는 명령어 입니다.
bluetoothctl
다음 명령어를 치면 터미널의 경로가 [bluetooth]
로 바뀌게 됩니다.
show
명령어를 치면 현재 블루투스의 상태를 확인할 수 있습니다.
[bluetooth]# show
상태를 보고 필요한 것들을 아래의 명령어를 참고해서 켜줍니다.
[bluetooth]# power on # 어댑터 전원 켜기
[bluetooth]# power off # 어댑터 전원 끄기
[bluetooth]# pairable on # 페어링 허용
[bluetooth]# pairable off
[bluetooth]# discoverable on # 장치 검색(Discoverable) 허용
[bluetooth]# discoverable off
[bluetooth]# agent on # 페어링 에이전트 활성화
[bluetooth]# default-agent # 기본 에이전트로 설정
여기서 중요한 것은 만약 discoverable
이 off 가 되어있다면, 블루투스를 아무리 검색해도 검색이 되지 않으니 반드시 켜줘야 합니다.
BLE를 활용한 서버(Peripheral) 구축하기
예제는 정말 많이 머리를 박았습니다. 그러다가 bluez-peripheral 라이브러리의 공식 문서를 보고 해결하였습니다.
우선, 패키지들을 설치해 줍니다.
sudo apt-get install -y python3 python3-pip
pip install bluez-peripheral
다음은 서버에서 BLE로 클라이언트에게 1초마다 hello
라는 문자를 보내는 예제 입니다.
# hello_service.py
from bluez_peripheral.gatt.service import Service
from bluez_peripheral.gatt.characteristic import characteristic, CharacteristicFlags as CharFlags
import asyncio
class HelloService(Service):
def __init__(self):
super().__init__("180D", True) # Heart Rate Service UUID
@characteristic("2A37", CharFlags.NOTIFY)
def hello_characteristic(self, options):
pass
async def update_hello(self):
while True:
message = "Hello!"
self.hello_characteristic.changed(message.encode("utf-8"))
print(f"[Server] Notified: {message}")
await asyncio.sleep(1)
# main.py
import asyncio
from bluez_peripheral.util import get_message_bus, Adapter
from bluez_peripheral.advert import Advertisement
from bluez_peripheral.agent import NoIoAgent
from hello_service import HelloService
async def main():
bus = await get_message_bus()
service = HelloService()
await service.register(bus)
agent = NoIoAgent()
await agent.register(bus)
adapter = await Adapter.get_first(bus)
advert = Advertisement("MyBLE", ["180D"], 0x0340, 60)
await advert.register(bus, adapter)
await service.update_hello()
await bus.wait_for_disconnect()
if __name__ == "__main__":
asyncio.run(main())
이렇게 하고, 아래의 명령어로 main.py를 실행시킵니다.
python main.py
자주 발생하는 문제들
Discoverable이 자동으로 꺼짐
- 일부 배포판에서
discoverable-timeout
이 설정되어 있음. sudo bluetoothctl discoverable on
을 실행해도 일정 시간 후 꺼질 수 있으니,sudo vim /etc/bluetooth/main.conf
에서DiscoverableTimeout = 0
으로 설정해볼 수 있습니다. (재부팅 후 적용)
연결 시 Permission Denied 혹은 Unreachable
- 관리자 권한으로 실행하지 않은 경우.
- 또는 OS 업데이트/BlueZ 버전 차이로 인해 페어링/보안 정책이 바뀌었을 수 있음.
다른 장치가 BLE 스캐닝 시 장치가 안 뜸
hciconfig
나bluetoothctl show
에서POWERED: yes
인지,DISCOVERABLE: yes
인지 재확인.advertise
명령이나bluez_peripheral
같은 방법으로 광고를 올바르게 켰는지 체크.GATT 서비스 검색 실패
- 기기가 광고는 하고 있으나 GATT 서버가 제대로 올라오지 않았거나, 서비스 UUID가 잘못되었는지 확인.
- Windows/Android/iOS BLE 스캐너 앱(nRF Connect, LightBlue 등)으로 GATT 서비스를 확인해 보는 게 좋습니다.
라즈베리 파이 OS 업데이트 후 동작 달라짐
- BlueZ 버전이 변경되면서, 기존 설정이 달라졌을 수 있음.
/etc/bluetooth/main.conf
나systemd
서비스 설정을 다시 확인해야 합니다.
클라이언트 코드
클라이언트 코드는 다음 링크를 참고해 주세요.
댓글 남기기