суббота, 15 мая 2021 г.

Чтение данных с ваттметра DT3010 по Bluetooth

Сегодня мучаем ваттметр с блютузом, у меня таких работает два: один мониторит выработку солнечными панелями на аккумуляторы, второй потребление домом энергии от аккумуляторной сборки.

Требуется программно из консоли Debian прочитать все данные.
На телефоне есть E-test, графики строит, в эксель пишет, но этого мало. Надо приконнектить к RPi Zero W и собирать данные постоянно, а не только когда телефон рядом.

Из софта потребуется в основном только bluetoothctl.

Запускаем малину, утилиту и шаримся в эфире
pi@raspberrypi:~ $ bluetoothctl
[NEW] Controller B8:27:EB:DB:0A:5D raspberrypi [default]
[NEW] Device C9:CA:4E:52:92:95 JZ-B5W2
[NEW] Device 46:D4:C5:1E:B3:EC Armor_3W

При запуске выдает список уже известных устройств: мобилка, блютус аудиоресивер; запускаем сканирование новых устройств

[bluetooth]# scan
Missing on/off argument
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:DB:0A:5D Discovering: yes
[NEW] Device 47:71:F7:A7:24:8E DT3010-BLE

При сканировании ваттметр определяется как 2 устройства: BLE и SPP.

[bluetooth]# devices
Device C9:CA:4E:52:92:95 JZ-B5W2
Device 46:D4:C5:1E:B3:EC Armor_3W
Device 47:71:F7:A7:24:8E DT3010-BLE
[NEW] Device 47:71:F7:A6:24:8E DT3010-SPP

Попытка спариться с SPP дает

Failed to pair: org.bluez.Error.AuthenticationFailed

Включаем агент

[bluetooth]# agent on
[bluetooth]# trust 47:71:F7:A6:24:8E
Changing 47:71:F7:A6:24:8E trust succeeded
[DT3010-SPP]# pair 47:71:F7:A6:24:8E
Attempting to pair with 47:71:F7:A6:24:8E
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 47:71:F7:A6:24:8E Paired: yes
Pairing successful
но коннекта не дает
[bluetooth]# connect 47:71:F7:A6:24:8E
Attempting to connect to 47:71:F7:A6:24:8E
[CHG] Device 47:71:F7:A6:24:8E Connected: yes
[CHG] Device 47:71:F7:A6:24:8E ServicesResolved: yes
Failed to connect: org.bluez.Error.NotAvailable
[CHG] Device 47:71:F7:A6:24:8E ServicesResolved: no
[CHG] Device 47:71:F7:A6:24:8E Connected: no
[bluetooth]# info 47:71:F7:A6:24:8E
Device 47:71:F7:A6:24:8E
        Name: DT3010-SPP
        Alias: DT3010-SPP
        Class: 0x001f00
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: no
        LegacyPairing: no
        UUID: Serial Port               (00001101-0000-1000-8000-00805f9b34fb)
лан пофиг..
Приложение E-Test один хрен коннектится к BLE так что сконцентрируемся на нем.

С BLE спариваемся без всяких паролей, ну можно предварительно trust <MAC> сделать.
Выводится список сервисов, из них по сути только один рабочий и имеет ценные данные.
Вывести список сервисов можно также командой list-attributes

[bluetooth]# pair 47:71:F7:A7:24:8E
Attempting to pair with 47:71:F7:A7:24:8E
[CHG] Device 47:71:F7:A7:24:8E Connected: yes
[NEW] Primary Service
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000a
        00001801-0000-1000-8000-00805f9b34fb
        Generic Attribute Profile
[NEW] Characteristic
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000a/char000b
        00002a05-0000-1000-8000-00805f9b34fb
        Service Changed
[NEW] Descriptor
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000a/char000b/desc000d
        00002902-0000-1000-8000-00805f9b34fb
        Client Characteristic Configuration
[NEW] Primary Service
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e
        0000ffe0-0000-1000-8000-00805f9b34fb
        Unknown
[NEW] Characteristic
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f
        0000ffe1-0000-1000-8000-00805f9b34fb
        Unknown
[NEW] Descriptor
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f/desc0011
        00002902-0000-1000-8000-00805f9b34fb
        Client Characteristic Configuration
[NEW] Characteristic
        /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char0012
        0000ffe2-0000-1000-8000-00805f9b34fb
        Unknown
[CHG] Device 47:71:F7:A7:24:8E UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device 47:71:F7:A7:24:8E UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device 47:71:F7:A7:24:8E UUIDs: 0000ffe0-0000-1000-8000-00805f9b34fb
[CHG] Device 47:71:F7:A7:24:8E ServicesResolved: yes
[CHG] Device 47:71:F7:A7:24:8E Appearance: 0x0002
[CHG] Device 47:71:F7:A7:24:8E Icon: unknown
Второй ваттметр за пределами дома, связь не ахти, из-за чего wifi, и как следствие ssh-консоль, подвисает на малине в режиме сканирования. Делаем scan off и проблемы нет

Для чтения данных из сервиса нужно после коннекта к девайсу выбрать атрибут и выполнить read, а можно сразу notify on и данные сами посыпятся с обновлением раз в секунду
[DT3010-BLE]# select-attribute /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f
[DT3010-BLE:/service000e/char000f]# read
[DT3010-BLE:/service000e/char000f]# notify on
Но ни тот, ни другой вариант неудобен.
read дает только часть данных (кстати иногда первую, иногда вторую, иногда вообще умирает и не работает), а при notify они валятся в неудобоваримом месиве-массиве.

расшифровка hex-байт следующая (первая строка - номера байтов, вторая - значения)
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
# ff 55 01 02 00 00 88 00 05 f5 00 0d 29 00 00 00 2f 00 00 64 00 00 00 00 00 15 00 00 00 00 05 00 00 00 00 2c

байты 1,2,3,4 на обоих моих ваттметрах одинаковые и не меняются со временем.
байты 5, 21, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35 - ничего кроме нулей не видел
байт 6 думаю тоже по более высокую напругу идет
байт 7, напряжение. здесь 88h-> 137d, т.е. 13.7В
байты 8(?), 9(!), 10(!) - ток. здесь 5F5h -> 1525d (1.525A)
байты 11,12,13 - емкость. здесь D29h -> 3369d (33.69 Ah)
байт 17 и думаю 14,15,16 - киловаттчасы. здесь 2Fh -> 47d (0.47 kWh)
18, 19, 20 - цена киловаттчаса, здесь 64h -> 100d (1.00 USD)
26 термометр, 15h -> 21d (21°)
31 время подсветки в секундах, 5сек

Направления тока к сожалению я не нашел, хотя железяка и показывает ток на дисплее в любом направлении, будто там диодный мост стоит, но без знака. Надеялся найти знак хотя бы в данных, не нашел. Флага горит ли в данный момент подсветка - тоже.

А вот как соединяться с SPP
root@raspberrypi:/home/pi# hcitool scan
Scanning ...
        47:71:F7:A6:24:8E       DT3010-SPP
root@raspberrypi:/home/pi# rfcomm connect rfcomm0 47:71:F7:A6:24:8E
Connected /dev/rfcomm0 to 47:71:F7:A6:24:8E on channel 1
Press CTRL-C for hangup
ни на какой ввод не реагирует.
а в консоли bluetoothctl при этом активируется коннект к SPP! сам.
правда атрибутов там нет и ничего интересного вообще

занятные команды

busctl tree org.bluez - выводит дерево сервисов блютус устройств
dbus-send --system --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E org.freedesktop.DBus.Introspectable.Introspect

еще можно по D-Bus такие штуки делать (предварительно приконнектиться в bluetoothctl)
dbus-send --print-reply=literal --system --dest=org.bluez /org/bluez/hci0/dev_C3_41_A6_C8_93_42 org.freedesktop.DBus.Properties.Get string:"org.bluez.Battery1" string:"Percentage"
много интересного
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E org.freedesktop.DBus.Introspectable.Introspect
пример получения всех  свойств
dbus-send --print-reply=literal --system --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E org.freedesktop.DBus.Properties.GetAll string:"org.bluez.Device1"
а вот вариант для сервиса service000e/char000f
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.freedesktop.DBus.Introspectable.Introspect
dbus-send --print-reply=literal --system --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.freedesktop.DBus.Properties.GetAll string:"org.bluez.GattCharacteristic1"
dbus-send --print-reply=literal --system --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.freedesktop.DBus.Properties.Get string:"org.bluez.GattCharacteristic1" string:"Value"

только данные не обновляются между запросами dbus-send, кешируются, походу.
если дернуть read в bluetoothctl, то обновятся

если в одной консоли запустить
dbus-monitor --system  "sender=org.bluez, path=/org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f, member=PropertiesChanged"
или (если неизвестны все параметры), то
dbus-monitor --system  "sender=org.bluez"
а в другой консоли войти в bluetoothctl, приконнектиться к девайсу. выбрать атрибут и запустить notify on, то dbus-monitor начнет выдавать данные

пробовал управлять всем через dbus
предварительно коннектимся
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E org.bluez.Device1.Connect
флаг смотрим, true
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E org.freedesktop.DBus.Properties.Get string:"org.bluez.Device1" string:"Connected"
запускаем notify
dbus-send --system --print-reply=literal  --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.bluez.GattCharacteristic1.StartNotify
в мониторе видим приход сообщения "Notifying"=true, потом пару раз данные пришли, а потом "Notifying"=false 
отключается почему-то, причем повторный вызов StartNotify не помогает, StopNotify дает ошибку "No notify session started", повторить получение данных можно только через реконнект.
а просто дергать какой-нить
dbus-send --print-reply=literal --system --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.freedesktop.DBus.Properties.Get string:"org.bluez.GattCharacteristic1" string:"Value"
бессмысленно. во-первых эти данные в dbus закешированы, всегда выдается последнее значение, во-вторых там вообще не все данные, только часть, обычно последняя.

значит надо дергать 
dbus-send --system --print-reply=literal  --dest=org.bluez /org/bluez/hci0/dev_47_71_F7_A7_24_8E/service000e/char000f org.bluez.GattCharacteristic1.ReadValue
и внеапно напарываемся на то, что параметр для ReadValue типа dict:string:variant сформировать не выйдет, dbus-send такого не поддерживает.
.. аллес...

хотяя.. вот тут говорят есть патч
https://stackoverflow.com/questions/8846671/how-to-use-a-variant-dictionary-asv-in-dbus-send?rq=1
омг.. на RPi Zero я еще исходники не компилял.
нуегонах, в общем, этот D-Bus, и блютус туда же вдогонку, неудобно.

следующий пост будет про чтение данных по проводу (UART)

для затравки:

Комментариев нет:

Отправить комментарий