Powrót do strony głównej

Raspberry Pi i licznik MIR S-05: BLE GATT

Deweloperzy otrzymują instrukcję podłączenia Raspberry Pi do licznika MIR S-05.10 przez Bluetooth. Opisano serwisy GATT, reverse protokołu przez logi HCI Android, skrypty bleak do odczytu wskazań. Nadaje się do integracji z systemami domu inteligentnego.

Integracja BLE licznika MIR S-05 z Raspberry Pi Zero
Advertisement 728x90

Integracja licznika MIR C-05.10 przez Bluetooth z Raspberry Pi: GATT i inżynieria wsteczna

Raspberry Pi Zero 2W z wbudowanym modułem Bluetooth umożliwia odczyt wskazań licznika MIR C-05.10-230-5(80)-G2Z1B-KNQ-S-D bez konieczności użycia głowicy optycznej USB. Interfejs wykorzystuje profil GATT działający w oparciu o BLE. Na początku instalujemy pakiety niezbędne do obsługi Bluetooth:

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

W narzędziu bluetoothctl uruchamiamy skanowanie (scan on), parowanie (pair MAC), dodajemy urządzenie do zaufanych (trust MAC) oraz nawiązujemy połączenie (connect MAC). Liczniki widoczne są w systemie jako C05-numer_seryjny.

Po pomyślnym połączeniu dostępne stają się usługi GATT. Główna usługa dla SPP-over-BLE to 4880c12c-fdcb-4077-8920-a450d7f9b907 z charakterystyką fec26ec4-6d71-4442-9f81-55bc21d658d6 (notify/write without response). Usługa Silicon Labs OTA jest pomijana.

Google AdInline article slot

Odczyt podstawowych charakterystyk GATT

Skrypt wykorzystujący bibliotekę bleak skanuje dostępne charakterystyki i aktywuje powiadomienia:

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())

Wynik działania skryptu ujawnia dane: producent NPO\"MIR\"\", model C05, numer seryjny 50912525161818, wersja oprogramowania v2.81.9.0. Pozostałe charakterystyki wymagają uwierzytelnienia (READ_NOT_PERMITTED).

Inżynieria wsteczna protokołu na podstawie logów HCI z Androida

Do analizy ruchu sieciowego wykorzystujemy urządzenie z Androidem z uprawnieniami roota. Aktywujemy menu programisty, logi HCI snoop oraz debugowanie USB. Po sparowaniu z aplikacją „MIR DP” logi pobieramy za pomocą adb bugreport lub:

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

Binarny plik btsnoop_hci.log poddajemy analizie (np. w Wiresharku lub z wykorzystaniem sztucznej inteligencji). Pozwala to odtworzyć sekwencję poleceń BLE służących do inicjalizacji i odczytu wskazań: całkowitego zużycia, taryf T1/T2, daty i godziny, natężenia prądu oraz napięcia.

Skrypt do sekwencyjnego odpytywania licznika

Protokół wymaga wysyłania osobnych żądań przez BLE. Przykładowy skrypt:

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

"""
Odczyt wskazań z licznika MIR C-05 przez BLE.
1. Podłączenie i inicjalizacja.
2. Notify.
3. Sekwencyjne komendy odczytu.
"""

# Tutaj komendy z logów HCI: write-without-response na fec26ec4...

Skrypt przeprowadza inicjalizację usług, aktywuje powiadomienia (notify) oraz wysyła zapytania. Otrzymane odpowiedzi są parsowane do jednostek kWh, A i V.

Google AdInline article slot

Kluczowe informacje:

  • Połączenie BLE jest stabilne i nie wymaga ponownego parowania.
  • Charakterystyki GATT są zabezpieczone; wymagany jest kod PIN od dostawcy.
  • Logi HCI stanowią klucz do zrozumienia protokołu SPP-over-BLE.
  • Integracja z Home Assistant możliwa jest przez MQTT lub bezpośrednie wywołanie skryptu.
  • Sekwencyjne odpytywanie jest obowiązkowe: wysyłanie pakietowe powoduje zerwanie połączenia.

— Editorial Team

Advertisement 728x90

Czytaj dalej