- PVSM.RU - https://www.pvsm.ru -
Janus MQTT Proxy — это сервис, который я написал на Go в качестве хобби-проекта. Он подключается к MQTT-брокеру и подписывается на все события, а клиенты, в свою очередь, подключаются к proxy и общаются с ним как с MQTT-брокером.
Он позволяет:
В MQTT нет стандарта для структуры топиков и содержимого пакетов. Например, в каких-то сервисах включение лампочки выполняется отправкой 1 в топик /my/lamp/on, а где-то нужно отправить On в топик /my/lamp. Чтобы корректно связать между собой два таких сервиса, нужно явно указывать одному из них, что нужно отсылать и куда. Если топиков много, тогда конфиг будет огромным и совершенно нечитаемым.
Janus MQTT позволяет оставить сервисы как есть: каждый работает с топиками так, как ему удобно, а весь конфиг конвертации MQTT-пакетов сосредоточен в одном единственном месте. Причём чем больше разных сервисов/устройств вы используете, тем такой подход удобнее.
В идеале каждый сервис должен брать свою конфигурацию просто из структуры топиков. Допустим, среди них есть топик /light/main. «Ага, — должен подумать сервис, — значит, я могу включать и выключать свет, отправляя сообщения в этот топик». К сожалению, таких сообразительных сервисов я пока не встречал.
Что касается безопасности, то любая конфигурация умного дома состоит из модулей, как физических, так и программных. С помощью Janus MQTT мы можем дать этим устройствам/модулям доступ только туда, куда нужно. Это, кстати, не только улучшит безопасность, но и снизит уровень хаоса — никаких публикаций в топики с неизвестных клиентов.
Чтобы было понятнее, как использовать сервис, я разберу небольшую часть моего конфига — ту, которая описывает управление освещением.
У Janus MQTT есть основной конфиг, который содержит основные настройки и список пользователей. Для каждого пользователя задаётся пароль и отдельный конфиг преобразований — самое интересное происходит именно в нём:
broker_to_client: # настройка преобразования пакетов от брокера к клиенту
# описание устройств для MQTT discovery.
- topic: ^/devices/wb-gpio/controls/LIGHT_([^/]*)/meta/type$
template: /homeassistant/light/{{.f1}}/config
val_map:
switch: >-
{
"command_topic":"/light/{{.f1}}/state",
"state_topic":"/light/{{.f1}}/state",
"name":"{{.f1}}"
}
- topic: ^/devices/wb-gpio/controls/LIGHT_([^/]*)$
template: /light/{{.f1}}/state
val_map: {0: OFF, 1: ON}
client_to_broker: # настройка преобразования пакетов от клиента к брокеру
- topic: ^/light/([^/]*)/state$
template: /devices/wb-gpio/controls/LIGHT_{{.f1}}/on
val_map: {OFF: 0, ON: 1}
Каждое правило содержит регулярное выражение, которое извлекает данные из топика. Затем эти данные могут быть подставлены в шаблон названия нового топика и в шаблон пакета.
Любопытно, что в этой конфигурации для отправки команд и чтения состояния мой Home Assistant использует один и тот же топик, а уже внутри прокси эти топики разделяются на два.
Хак для MQTT discovery работает так: среди топиков Wiren Board есть специальные сервисные топики, которые описывают тип устройства. Насколько я понимаю, они используются только в стандартном интерфейсе управления. Они есть у каждой лампы и все равны switch. Все эти события retained и приходят один раз — в момент подключения. Я просто беру и подменяю все такие пакеты JSON-структурой, которая нужна для того, чтобы MQTT discovery подхватил эти устройства.
Сервис написан на Go и построен на базе библиотеки paho.mqtt.golang. Эта библиотека реализует MQTT-клиент для работы с брокером. Использовать её в качестве сервера никто не предполагал, поэтому его пришлось писать самому, используя части MQTT-клиента.
Принцип работы очевидный: выдаём себя за брокера, принимаем пакеты от клиентов, изменяем их и отправляем настоящему брокеру. То же самое в обратную сторону. Т.е. получаем такой MITM.
Самые интересные штуки:
Обработка MQTT-пакетов от клиентов описана в функции client.serveIncoming, она запускается в горутине и читает из TCP-сокета. В этой функции описана высокоуровневая логика обработки MQTT-пакетов от клиентов:
Автоматы отправки сообщений в клиент и от клиента нужны только для поддержки различных уровней QoS. Всего в MQTT три уровня QoS:
Как мне кажется, уровень 1 и тем более уровень 2 не имеют большого смысла дома, но, тем не менее, реализовать их было интересно (уровень 2 я немного не доделал, поэтому пока что обрезаю весь QoS уровнем 1, протокол это позволяет).
Обработка publish-пакета от клиента с QOS=2
Обработка publish-пакета от брокера с QOS=2
Janus MQTT я использую для организации взаимодействия между тремя компонентами:
Содержит кучу разных реле и датчиков. В нём же крутятся основные скрипты управления всем. На нём работает MQTT-брокер.
Реализует oAuth для аутентификации и шлюз для взаимодействия с API умного дома Яндекса. Я решил не тратить на это время и взял готовый компонент. Изначально его написал munrexio, потом bawdiest обернул в докер, а я немножко поправил.
Пока что в конфиге одна единственная лампочка, но зато самая важная:
$ mosquitto_sub -h localhost -u yandex2mqtt -P yandex2mqtt -t '#' -v
/light/LIVING_TABLE/state 1
Фронтенд. Собирает статку и рисует разные графики. Позволяет управлять как светом, так и отоплением.
Заниматься настройкой Home Assistant мне не хочется, мне нужно, чтобы я запустил его и там сразу появились все мои устройства.
К счастью, в Home Assistant есть MQTT Discovery — это специальный режим, когда Home Assistant получает конфиг устройств прямо из MQTT. Там нужно создать специальные топики с JSON-структурами, описывающими устройства.
В итоге весь конфиг Home Assistant сводится к:
mqtt:
username: !env_var MQTT_USER
password: !env_var MQTT_PASS
broker: !env_var MQTT_HOST
discovery: true
discovery_prefix: /homeassistant
Конфиг Janus MQTT для Home Assistant самый сложный. Однако он уложился в 100 строчек, при том что описывает 17 групп освещения, 6 термостатов с обратной связью по состоянию (вкл/выкл) и по температуре в комнате и 5 тёплых полов. Часть этого конфига приведена выше. Полный конфиг можно посмотреть тут [1].
Все сервисы работают в докере на NanoPi и описаны в docker-compose.yml.
У меня сервис безостановочно работает с января, была пара мелких багов, которые я поправил, но в целом всё хорошо.
Весь докеробраз сервиса весит порядка 10 Mб. Слава Golang!
Сервис можно скачать/посмотреть тут :
https://github.com/phoenix-mstu/janus-mqtt-proxy [2].
Файл docker-compose можно посмотреть тут:
https://github.com/phoenix-mstu/smart_home/tree/master/raspberry [3].
И самое интересное, сервис можно пощупать вот тут: 52.59.242.204:26927, логин/пароль — habr/hrabr, протокол — MQTT, конечно же. Там настроен проброс порта в мою локалку. Специально для статьи запущен отдельный инстанс сервиса в докере со специальным конфигом [4], там можно:
В качестве брокера выступает мой основной брокер-сервер — посмотрим, сломается или нет. Я, конечно, предпринял ряд мер для безопасности. Понятно, что DoS-атаку оно не выдержит — вы просто забьёте узкий канал. Будьте разумны.
Автор: Григорий Кузовников
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/umny-j-dom/352170
Ссылки в тексте:
[1] тут: https://github.com/phoenix-mstu/go-modifying-mqtt-proxy/blob/master/sample_configs/my_wirenboard_to_homeassistant.yaml
[2] https://github.com/phoenix-mstu/janus-mqtt-proxy: https://github.com/phoenix-mstu/janus-mqtt-proxy
[3] https://github.com/phoenix-mstu/smart_home/tree/master/raspberry: https://github.com/phoenix-mstu/smart_home/tree/master/raspberry
[4] конфигом: https://github.com/phoenix-mstu/janus-mqtt-proxy/blob/master/sample_configs/habr_filters.yaml
[5] Источник: https://habr.com/ru/post/497234/?utm_source=habrahabr&utm_medium=rss&utm_campaign=497234
Нажмите здесь для печати.