BLE 원격 제어 연구과제 제안을 준비하고 있다. 안드로이드에서 블루투스로 장치를 직접 제어하는 프로토타입 앱을 만드는 중이다. 서버 쪽만 하다가 이것을 하니 전제가 다른 것이 많았다.
Table of contents
Open Table of contents
배경 — 연결이 기본 상태가 아니다
서버 개발에서는 요청을 보내면 가는 것이 기본이고 끊기는 것이 예외 상황이다. BLE 는 반대로 연결되어 있는 상태가 특별하다.
장치가 꺼져 있을 수도 있고 거리가 멀어지면 끊기고 다른 앱이 이미 붙어 있을 수도 있다. 그래서 명령 하나를 보내는 코드가 확인과 BluetoothLeScanner 검색과 connectGatt() 연결과 전송과 재시도까지 다섯 단계가 되고 각 단계가 각각 실패한다.
증상 — 오류 없이 멈추는 순서 위반
앱을 켜자마자 명령을 보내게 했더니 아무 반응이 없었다. 검색과 연결과 discoverServices() 와 특성 조회를 거쳐야 writeCharacteristic() 으로 읽고 쓸 수 있는 순서가 있었다.
앞 단계가 끝나기 전에 다음을 부르면 실패한다. 오류가 나지 않고 그냥 아무 일도 안 일어나는 경우가 있었다. 각 단계가 끝났는지 BluetoothGattCallback 으로 확인하고 다음으로 가게 고쳤다. 코드가 길어졌지만 다른 방법을 찾지 못했다.
조치 — 한 번에 보낼 수 있는 크기
명령이 길어지면 한 번에 못 보내고 그 상한이 장치마다 다르다. 두 가지 방법이 있었다. 하나는 requestMtu() 로 협상해서 늘리는 데 기대는 것이다. 다른 하나는 작게 나눠 보내는 것을 기본으로 두고 받는 쪽에서 이어 붙이는 것이다. 뒤쪽을 골랐다. 이유는 협상이 안 되는 장치가 시험 장비 중에 있었기 때문이다. 대신 순번과 전체 개수를 앞에 붙이고 재전송 규칙을 정해야 하는 것을 감수했다.
중간이 유실되면 받는 쪽이 순번으로 알 수 있는데 그 재전송 규칙을 정하는 데 시간이 꽤 걸렸다.
기기마다 갈리는 동작
같은 코드인데 기기마다 다르게 동작했다. 검색이 빠른 기기와 느린 기기가 있어서 시간 제한을 짧게 잡으면 느린 쪽에서 못 찾는다.
끊고 바로 다시 연결하면 실패하는 기기가 있어서 잠깐 기다렸다가 해야 했다. 앱을 지웠다 깔아도 예전 연결 정보가 남는 기기도 있었다. 이런 것을 미리 아는 방법을 못 찾아서 여러 기기에서 직접 해 보는 수밖에 없었다.
주의 — 검색에 필요한 위치 권한
BLE 장치를 검색하는 데 ACCESS_FINE_LOCATION 권한이 필요하다는 것이 뜻밖이었다. Android 공식 문서대로 Android 11 이하에서는 스캔 결과가 사용자 위치를 추정하는 데 쓰일 수 있어서 그렇게 묶여 있었다.
사용자에게는 이 요구가 이상하게 보인다. 이유를 설명하는 화면을 넣었는데도 거부하는 경우가 있었다. 거부하면 검색만 막히는 것이 아니라 전체가 아무 반응 없이 멈추고 그 이유가 화면에 나오지 않는다.
정리
- 연결되어 있는 것이 특별한 상태다
- 명령 하나를 보내는 데 다섯 단계가 필요하고 각각 실패한다
- 순서를 어기면 오류 없이 아무 일도 안 일어난다
- 각 단계의 완료를
BluetoothGattCallback으로 확인하고 다음으로 간다 - 한 번에 보낼 수 있는 크기가 장치마다 다르다
- 나눠 보내면 순번과 재전송 규칙이 필요하다
- 기기마다 검색 속도와 재연결 동작이 다르다
- 검색에
ACCESS_FINE_LOCATION이 필요하고 거부되면 전체가 멈춘다