Некоторое время назад наткнулся на интересный мультиметр за вполне адекватные деньги, который на борту имеет Bluetooth. Для чего это нужно? При обычных сценариях использования это лишнее, но когда ты иногда ведешь стримы и хочешь вывести в трансляцию показания, чтобы не тратить время на подбор угла в кадре, или когда наблюдаешь за длительным процессом подключение к ПК может оказаться полезным.
От производителя есть официальное приложение под Android. Полного функционала не знаю, но графики рисовать оно умеет. Есть удаленное управление мультиметром (менять режимы или включать заморозку значения или относительные измерения). Теоретически могло бы и работать с несколькими мультиметрами одновременно, но данного функционала не было обнаружено.
Беглый осмотр официального приложения показал, что для получения данных с мультиметра не обязательно его спаривать со смартфоном. Отсутствие привязки к устройству позволит без сброса настроек пользоваться как сматфоном, так и компьютером. Ранее я упоминал возможность управления и некоторые могли подумать, что это уязвимость. С одной стороны согласен, с другой проблем быть не должно. По умолчанию, радио канал выключен, чтобы не тратить батарейки. Управление очень сильно ограничено, так как основные функции переключаются механически, а не электронно. Не возникнет ситуации, когда из измерения напряжения переключат в измерение тока и устроят короткое замыкание.
Так как ранее я имел небольшой опыт работы с Buetooth Low Energy устройствами (ESP32, как «клиент», так и «сервер»), на телефоне установлено приложение nRF Connect, которое является достаточно продвинутым и полезным «отладчиком»/читалкой/писалкой/эмулятором BLE устройств. Обнаружение устройства, подключение вопросов не вызывает. Но в явном виде данных об измерениях не обнаружено. Все параметры, на изменение которых можно было подписаться, ничего не передают. Подозрительно, но ок.
Для чего нужен режим разработчика в Android? Чтобы иметь доступ к логам. А раз есть официальное приложение и функция записи обмена, то задача становится сильно проще. Включаем snoop-логи HCI Bluetooth в меню разработчика, перезагружаем Bluetooth или телефон (иначе запись не начнется), открываем родное приложение, жмем кнопочки. После общения не забываем выключать логирование, чтобы не насиловать флешку (особенно при использовании беспроводных наушников). Остается только выдернуть логи через ADB и рассмотреть их в Wireshark.
Судя по инструкциям в сети логи должны лежать по пути /sdcard/btsnoop_hci.log или /data/misc/bluetooth/logs/. В моем случае карты нет, а доступ в /data запрещен. Но их можно получить командой adb bugreport. В результате формируется ZIP архив, в котором будут интересующие файлы.
В первую очередь надо оставить только пакеты между телефоном и мультиметром. Это сделать достаточно легко. Находим любой пакет с мультиметром, жмем правой кнопкой по полю, содержащему адрес устройства и выбираем его в качестве фильтра «Выбранное».

В результате вверху окна прописывается фильтр вида _ws.col.def_src == "JingxunSoftw_xx:xx:xx (UT60BT)", но лучше использовать не это поле, а развернуть заголовки пакета и

В таком случае строка будет уже другого формата: bluetooth.src == e8:d0:3c:xx:xx:xx. Сейчас фильтр оставляет только те пакеты, которые идут от мультиметра к телефону, а обратные отбрасываются. Надо расширить фильтр, добавив в него копию MAC адреса, но уже как получателя: bluetooth.src == e8:d0:3c:xx:xx:xx or bluetooth.dst == e8:d0:3c:xx:xx:xx. Теперь видно весь обмен.
Что искать в дампе? Раз чтение уже было опробовано на этапе nRF Connect и не дало никаких результатов, то приложение, наверное, прописывает что-то для начала работы. Следующее, что требуется посмотреть внимательно — пакеты типа NOTIFY. Это сообщения от устройства об изменении значения какого-то параметра. Обычно именно таким способом передают данные в BLE.

И действительно в захвате наблюдается небольшой обмен, чтение различных параметров и дальше только пакеты типа NOTIFY, в которых содержатся результаты измерения.
Wireshark хорош тем, что умеет хорошо парсить пакеты и отображать интересующие параметры в виде дерева. На скриншоте выше видно значение.
- HEX:
abcd1004302020302e303030000000000802f2 - ASCII:
????? 0.000???, где вопросительный знак — символ, который не конвертируется в строку корректно.
Получается, что результат измерения у нас доступен в виде текста без необходимости конвертировать во float или ещё что-либо.
Если развернуть немного глубже, то видим, что данные лежат в параметре UUID 495353431e4d4bd9ba6123c647249616. Именно на него нужно подписаться для получения результатов измерений. Запомним этот идентификатор.

Как говорилось ранее, просто подписка ничего не дает. Данные не обновляются. Значит где-то перед началом потока пакетов NOTIFY должна быть запись в какой-то параметр, после которой мультиметр начинает активно посылать данные. Ищем.

Вот интересующие нас пакеты. Как раз прямо перед началом потока. В первом пакете от телефона к мультиметру идет команда на запись, где включается подписка на изменения для указанного выше UUID.

Во втором пакете от мультиметра к телефону приходит подтверждение записи.

Далее идет запись в UUID 495353436daa4d02abf619569aca69fe магической константы abcd035f01da. Что она означает неизвестно.

Однако… В ответ прилетает ошибка.

После этого прилетает первый пакет NOTIFY, но радоваться рано. Он ещё не содержит результатов измерений. В нем пришла строка ??UT60BT??. Это же значение я и наблюдал в nRF Connect, когда пытался подписываться на обновления.
Далее от телефона идет команда на запись (без подтверждения). Wireshark не отображает UUID, в который идет запись, но это тот же идентификатор, что и в неудачной попытке выше. Только в этот раз магическая константа уже другая: abcd035d01d8.

И сразу после этого в пакетах NOTIFY идут данные измерений. Уже неплохо, осталось только повторить. Для начала с телефона, а потом уже и на компьютере при помощи аналога nRF Connect или сразу на QT или Python. Описывать процесс не буду, но в Microsoft Store для Windows 10 нашлось какое-то приложение для обмена с BLE устройствами. На QT тоже получилось общаться. Правда парсер значений я на тот момент не делал, так как была проблема поважнее.
Проблема поважнее — магические константы. Я понятия не имею что это за значения, как они формируются, уникальны ли они для устройства… Поэтому был куплен второй мультиметр, чтобы изучить этот вопрос. Далее делаем год перерыва и… Так как я умудрился потерять исходники заготовки на QT (они в бекапах точно есть, вопрос только где именно), а нейронки сейчас достаточно развиты, чтобы сделать набросок скрипта на Python, включаем режим вайб кодера. Правим заготовку от нейронки до нужного нам состояния и проверяем совместимость. Константа подходит к обоим экземплярам, что не может не радовать.
На данном этапе это все, что готов рассказать, скрипт на питоне вполне отрабатывает, но нужно ещё распарсить остальные байты, в которых закодирован текущий режим работы. Плюс удаленное нажатие кнопок я даже не пытался захватывать. В идеале попытаться ковырнуть оригинальное приложение на предмет формирования констант и обозначения режимов работы, но подобного опыта не имею. Проект заброшен, так как сам я почти перестал выходить с трансляциями в интернет, но иногда я про него вспоминаю. Так что это скорее очередная закладка для себя через год-два, чтобы вспомнить алгоритм действий. Если у кого есть подобный мультиметр и ему реально нужен софт для компьютера, то это может замотивировать меня заняться проектом. А пока лежит на полочке.