블루투스 로우 에너지(BLE)는 최소한의 전력으로 근거리 무선 통신이 가능한 기술입니다. 일반적인 블루투스와 비교했을 때 전력 소비가 매우 적어, 작은 배터리로도 몇 개월에서 몇 년까지 작동할 수 있습니다. 이번 포스팅에서는 BLE 온도 센서 디바이스를 예로 들어, BLE 프로토콜 스택의 주요 구성 요소와 실제로그를 바탕으로 해당 내용을 분석해보겠습니다.
BLE 프로토콜 스택 분석
블루투스 로우 에너지(BLE) 프로토콜의 구조와 통신 과정을 실제로 이해하기 위해, 파이썬을 활용한 간단한 분석 코드를 개발했습니다. 이 코드는 BLE 디바이스의 서비스 구조, 특성값, 그리고 보안 메커니즘을 탐색할 수 있게 해주어, 복잡한 BLE 스택을 단계별로 이해할 수 있도록 도와줍니다.
import asyncio
from bleak import BleakClient, BleakScanner
TARGET_DEVICE_NAME = "NXP_TEMP"
TARGET_DEVICE_ADDRESS = "00:60:37:1C:A3:66"
async def scan_and_connect():
device = await BleakScanner.find_device_by_address(TARGET_DEVICE_ADDRESS, timeout=20.0)
if device is None:
print(f"Could not find device with address {TARGET_DEVICE_ADDRESS}")
return None
return device
async def print_device_info(client, device):
print(f"Connected: {client.is_connected}")
print(f"Device name: {device.name}")
print(f"Device address: {device.address}")
for service in client.services:
print(f"\nService: {service.uuid}")
for char in service.characteristics:
print(f" Characteristic: {char.uuid}")
print(f" Properties: {', '.join(char.properties)}")
if "read" in char.properties:
try:
value = await client.read_gatt_char(char.uuid)
print(f" Value: {value}")
except Exception as e:
print(f" Error reading value: {str(e)}")
else:
print(" Value: Not readable")
for descriptor in char.descriptors:
print(f" Descriptor: {descriptor.uuid}")
try:
value = await client.read_gatt_descriptor(descriptor.handle)
print(f" Value: {value}")
except Exception as e:
print(f" Error reading descriptor: {str(e)}")
async def main():
print(f"Scanning for {TARGET_DEVICE_NAME} ({TARGET_DEVICE_ADDRESS})...")
device = await scan_and_connect()
if device:
try:
async with BleakClient(device) as client:
print(f"Connected to {device.name}")
await print_device_info(client, device)
except Exception as e:
print(f"Error: {str(e)}")
else:
print("Device not found.")
if __name__ == "__main__":
asyncio.run(main())
- 파이썬의 asyncio는 비동기 방식으로 프로그램을 실행할 수 있게 해주는 도구입니다. BLE 장치와 통신할 때 데이터를 보내고 받는 동안 다른 작업을 처리할 수 있어, 마치 여러 가지 일을 동시에 하는 것처럼 효율적으로 작동합니다. 예를 들어 한 장치로부터 데이터를 받으면서 동시에 다른 장치를 검색할 수 있습니다.
- bleak는 블루투스 통신을 쉽게 할 수 있게 도와주는 파이썬 패키지입니다. 복잡한 블루투스 통신을 간단한 명령어로 처리할 수 있게 해주며, Windows, Mac, Linux 등 어떤 컴퓨터에서든 같은 방식으로 사용할 수 있습니다. 마치 스마트폰에서 블루투스 이어폰을 연결하는 것처럼 쉽게 BLE 장치와 연결할 수 있습니다.
- 우리가 연결하고자 하는 BLE 장치의 이름과 주소를 프로그램에 미리 입력해둡니다. 이는 마치 전화번호부에 연락처를 저장해두고 필요할 때 바로 찾아 전화를 거는 것과 비슷합니다. TARGET_DEVICE_NAME은 장치의 이름이고, TARGET_DEVICE_ADDRESS는 장치의 고유 주소입니다.
- BleakScanner로 주변의 BLE 장치들을 찾아보는데, 특히 우리가 원하는 주소를 가진 장치를 찾을 때까지 20초 동안 계속 살펴봅니다. 이는 마치 어두운 방에서 손전등을 비춰가며 특정 물건을 찾는 것과 비슷합니다. 20초 안에 찾지 못하면 검색을 멈춥니다.
- 장치와 연결되면, 그 장치가 가지고 있는 모든 정보를 자세히 살펴보고 출력합니다. 서비스는 장치가 제공하는 기능들이고, 특성은 각 기능의 세부 데이터이며, 설명자는 이러한 데이터들에 대한 부가 설명입니다. 마치 새로 산 전자기기의 모든 기능과 설정을 하나씩 확인하는 것과 같습니다.
이 프로그램은 비동기 프로그래밍 기반의 파이썬 코드를 작성하여 BLE 디바이스를 스캔하고, 연결하며, 각종 서비스와 특성값을 읽어들이는 과정을 구현했습니다. 이를 통해 BLE 프로토콜의 핵심 구성 요소들을 실제 동작하는 코드로 확인할 수 있으며, 프로토콜 스택의 각 계층이 어떻게 상호작용하는지 명확하게 파악할 수 있습니다.
실행 테스트 로그
우리가 개발한 Python 기반 BLE 분석 도구를 실행한 결과, 디바이스의 전체 서비스 구조와 특성값, 그리고 보안 상태를 포함하는 상세한 로그 데이터를 수집할 수 있었습니다. 이 로그는 디바이스의 Generic Attribute, Generic Access, Device Information 등 핵심 서비스들의 구성과 각 특성값들의 권한 설정, 그리고 실제 데이터 읽기/쓰기 과정에서 발생하는 다양한 프로토콜 동작을 상세히 보여줍니다. 이제 이 로그를 단계별로 분석하면서 BLE 프로토콜의 주요 구성 요소들이 실제로 어떻게 동작하는지, 그리고 디바이스와의 통신 과정에서 어떤 보안 메커니즘이 적용되는지 자세히 살펴보도록 하겠습니다.
Scanning for IOT_TEMP (00:60:37:1C:A3:66)...
Connected to IOT_TEMP
Connected: True
Device name: IOT_TEMP
Device address: 00:60:37:1C:A3:66
Service: 00001801-0000-1000-8000-00805f9b34fb
Characteristic: 00002a05-0000-1000-8000-00805f9b34fb
Properties: indicate
Value: Not readable
Descriptor: 00002902-0000-1000-8000-00805f9b34fb
Value: bytearray(b'\x02\x00')
Service: 00001800-0000-1000-8000-00805f9b34fb
Characteristic: 00002a00-0000-1000-8000-00805f9b34fb
Properties: read
Value: bytearray(b'NXP_BLE_TEMP')
Characteristic: 00002bf5-0000-1000-8000-00805f9b34fb
Properties: read
Value: bytearray(b'\x01\x03')
Service: 01ff0200-ba5e-f4ee-5ca1-eb1e5e4b1ce0
Characteristic: 00002a6e-0000-1000-8000-00805f9b34fb
Properties: notify
Value: Not readable
Descriptor: 00002904-0000-1000-8000-00805f9b34fb
Error reading descriptor: Could not read Descriptor value for 000F: Protocol Error 0x05: Insufficient Authentication
Descriptor: 00002902-0000-1000-8000-00805f9b34fb
Error reading descriptor: Could not read Descriptor value for 0010: Protocol Error 0x05: Insufficient Authentication
Service: 0000180f-0000-1000-8000-00805f9b34fb
Characteristic: 00002a19-0000-1000-8000-00805f9b34fb
Properties: read, notify
Error reading value: Could not read characteristic handle 19: Protocol Error 0x05: Insufficient Authentication
Descriptor: 00002904-0000-1000-8000-00805f9b34fb
Error reading descriptor: Could not read Descriptor value for 0015: Protocol Error 0x05: Insufficient Authentication
Descriptor: 00002902-0000-1000-8000-00805f9b34fb
Error reading descriptor: Could not read Descriptor value for 0016: Protocol Error 0x05: Insufficient Authentication
Service: 0000180a-0000-1000-8000-00805f9b34fb
Characteristic: 00002a29-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 25: Protocol Error 0x05: Insufficient Authentication
Characteristic: 00002a24-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 27: Protocol Error 0x05: Insufficient Authentication
Characteristic: 00002a25-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 29: Protocol Error 0x05: Insufficient Authentication
Characteristic: 00002a27-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 31: Protocol Error 0x05: Insufficient Authentication
Characteristic: 00002a26-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 33: Protocol Error 0x05: Insufficient Authentication
Characteristic: 00002a28-0000-1000-8000-00805f9b34fb
Properties: read
Error reading value: Could not read characteristic handle 35: Protocol Error 0x05: Insufficient Authentication
위 BLE 프로토콜 로그를 단계별로 분석해보겠습니다.
1. 초기 연결 정보
BLE 장치 IOT_TEMP(00:60:37:1C:A3:66)와 성공적으로 연결되었으며, 주소의 앞부분 00:60:37은 제조사인 NXP Semiconductors를 나타내는 고유 식별자(OUI)입니다.
2. Generic Attribute Service (00001801)
Generic Attribute Service(00001801)는 BLE의 기본 서비스로, indicate 속성을 통해 디바이스의 서비스 변경 사항을 자동으로 알려받을 수 있습니다.
3. Generic Access Service (00001800)
Generic Access Service(00001800)는 디바이스의 기본 정보를 제공하는 서비스로, 읽기 가능한 디바이스 이름(NXP_BLE_TEMP)과 추가 설정 정보(01 03)를 포함하고 있습니다.
4. 커스텀 온도 서비스 (01ff0200)
커스텀 서비스(01ff0200)는 notify 속성을 통해 온도 데이터의 실시간 변화를 전송받을 수 있으나, 데이터 접근을 위해서는 보안 인증이 필요한 특수 목적의 서비스입니다.
5. 배터리 서비스 (0000180f)
Battery Service(0000180f)는 read와 notify 속성을 통해 배터리 상태를 확인하고 변화를 감지할 수 있지만, 이 정보에 접근하기 위해서는 보안 인증이 필요합니다.
6. 디바이스 정보 서비스 (0000180a)
Device Information Service(0000180a)는 제조사, 모델번호, 시리얼번호와 같은 디바이스의 상세 정보를 제공하며, 모든 특성이 읽기 가능하도록 설계되어 있으나 보안을 위해 인증 과정이 요구됩니다.
대부분의 중요한 정보는 "Insufficient Authentication" 오류가 발생했는데, 이는 보안을 위해 적절한 인증 과정이 필요하다는 것을 의미합니다.