홈으로 돌아가기

Raspberry Pi와 MIR S-05 계량기: BLE GATT

Bluetooth를 통해 Raspberry Pi를 MIR S-05.10 계량기에 연결하는 개발자 지침. GATT 서비스 설명, Android HCI 로그를 통한 프로토콜 reverse, 판독값 읽기를 위한 bleak 스크립트. 스마트 홈 시스템 통합에 적합.

Raspberry Pi Zero와 MIR S-05 계량기의 BLE 통합
Advertisement 728x90

라즈베리 파이와 MIR C-05.10 전력량기 블루투스 연동: GATT 및 리버스 엔지니어링

라즈베리 파이 Zero 2W는 내장 블루투스 모듈을 활용해 USB 광학 프로브 없이도 MIR C-05.10-230-5(80)-G2Z1B-KNQ-S-D 전력량기 데이터를 직접 읽어올 수 있습니다. 해당 인터페이스는 BLE 기반 GATT 프로파일을 사용합니다. 먼저 필요한 블루투스 패키지를 설치합니다.

sudo apt update
sudo apt install -y bluez bluez-tools bluetooth python3-pip
python3 -m pip install --break-system-packages bleak
sudo systemctl enable bluetooth
sudo systemctl restart bluetooth

bluetoothctl 유틸리티에서 스캔을 시작하고(scan on), 기기와 페어링한 뒤(pair MAC), 신뢰할 수 있는 기기로 등록(trust MAC)하고 연결합니다(connect MAC). 기기 목록에는 C05-시리얼번호 형식으로 표시됩니다.

연결이 완료되면 GATT 서비스에 접근할 수 있습니다. SPP-over-BLE의 주요 서비스는 4880c12c-fdcb-4077-8920-a450d7f9b907이며, fec26ec4-6d71-4442-9f81-55bc21d658d6 특성(notify/write without response)을 제공합니다. Silicon Labs OTA 서비스는 무시해도 무방합니다.

Google AdInline article slot

기본 GATT 특성 읽기

bleak 라이브러리를 활용한 파이썬 스크립트로 사용 가능한 특성을 스캔하고 알림을 활성화할 수 있습니다.

import asyncio
from bleak import BleakClient

ADDR = "E4:06:BF:87:CD:69"

CHARS = [
    "00002a29-0000-1000-8000-00805f9b34fb",
    "00002a24-0000-1000-8000-00805f9b34fb",
    "00002a25-0000-1000-8000-00805f9b34fb",
    "00002a27-0000-1000-8000-00805f9b34fb",
    "00002a26-0000-1000-8000-00805f9b34fb",
    "2bb1d64f-451a-4541-ac89-24df683309dc",
    "d24a5138-1448-48ea-a983-f7df274c6d89",
    "4335a5be-fbbd-464e-8659-1a4212239e3e",
    "b3f7e595-2951-42fa-879e-0d9dfa5e846e",
    "fec26ec4-6d71-4442-9f81-55bc21d658d6",
    "f7bf3564-fb6d-4e53-88a4-5e37e0326063",
]

def fmt(data: bytes) -> str:
    try:
        txt = data.decode("utf-8", errors="strict")
        return f'hex={data.hex(" ")} | utf8={txt!r}'
    except Exception:
        return f'hex={data.hex(" ")}' 

async def main():
    def cb(sender, data):
        print(f"NOTIFY {sender}: {fmt(bytes(data))}")

    async with BleakClient(ADDR, timeout=20.0) as client:
        print("connected:", client.is_connected)

        for uuid in CHARS:
            try:
                data = await client.read_gatt_char(uuid)
                print(f"READ {uuid}: {fmt(bytes(data))}")
            except Exception as e:
                print(f"READ {uuid}: ERROR: {e}")

        try:
            await client.start_notify("fec26ec4-6d71-4442-9f81-55bc21d658d6", cb)
            print("notify enabled on fec26...")
        except Exception as e:
            print("notify fec26 error:", e)

        await asyncio.sleep(10)

asyncio.run(main())

출력 결과에서 제조사(NPO "MIR"), 모델명(C05), 시리얼 번호(50912525161818), 펌웨어 버전(v2.81.9.0) 등의 기기 정보를 확인할 수 있습니다. 나머지 특성들은 인증이 필요하며 접근 시 READ_NOT_PERMITTED 오류가 발생합니다.

안드로이드 HCI 로그를 활용한 프로토콜 리버스 엔지니어링

통신 트래픽을 분석하려면 루팅된 안드로이드 기기가 필요합니다. 개발자 옵션을 활성화한 뒤 블루투스 HCI 스누프 로깅과 USB 디버깅을 켭니다. 공식 'MIR DP' 앱과 페어링한 후 adb bugreport 또는 아래 명령어로 로그를 추출합니다.

Google AdInline article slot
adb shell su -c "cp /data/misc/bluetooth/logs/btsnoop_hci.log /sdcard/Download/btsnoop_hci.log && chmod 666 /sdcard/Download/btsnoop_hci.log"
adb pull /sdcard/Download/btsnoop_hci.log

바이너리 형식의 btsnoop_hci.log 파일은 Wireshark나 AI 기반 분석 도구로 파싱할 수 있습니다. 이를 통해 초기화 및 데이터 조회에 사용되는 정확한 BLE 명령어 시퀀스(총 전력 사용량, T1/T2 요금제 검침값, 날짜/시간, 전류, 전압 등)를 파악할 수 있습니다.

검침 데이터 순차 폴링 스크립트

이 프로토콜은 각 데이터 포인트별로 개별 BLE 요청을 보내야 합니다. 다음은 스크립트 템플릿입니다.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
BLE를 통한 MIR C-05 전력량기 데이터 읽기.
1. 연결 및 초기화.
2. 알림 활성화.
3. 순차 읽기 명령 전송.
"""

# HCI 로그에서 추출한 명령어를 여기에 삽입: write-without-response to fec26ec4...

해당 스크립트는 서비스 초기화 처리, 알림 활성화, 읽기 요청 전송을 담당합니다. 응답 데이터는 kWh, A, V 등의 표준 단위로 파싱됩니다.

Google AdInline article slot

핵심 요약:

  • BLE 연결은 재페어링 없이도 안정적으로 유지됩니다.
  • GATT 특성은 보호되어 있으며, 전체 접근을 위해서는 벤더 전용 PIN이 필요합니다.
  • SPP-over-BLE 프로토콜을 디코딩하려면 HCI 로그 분석이 필수적입니다.
  • MQTT 브리지 또는 직접 스크립트 실행을 통해 Home Assistant와 원활하게 연동할 수 있습니다.
  • 순차 폴링이 필수적이며, 일괄 요청을 보낼 경우 연결이 끊어집니다.

— Editorial Team

Advertisement 728x90

다음 읽기