MQTT (Phase Broker)¶
Альтернатива HTTP-heartbeat'у. Плата подписывается на MQTT-топик и получает команды push'ем с малой задержкой (десятки мс vs 15 сек у heartbeat'а).
Зачем¶
| Задача | HTTP heartbeat | MQTT |
|---|---|---|
| Toggle реле с Алисы | 0–15 сек задержка | < 1 сек |
| Live-обновления состояния в UI | 0–15 сек | мгновенно |
| Управление с Home Assistant | через cloud API | напрямую к плате |
| Простой self-hosted клиент | нужно писать REST-клиент | стандартный MQTT-client |
Минусы MQTT: ещё одно открытое соединение, TLS-handshake, keep-alive. На ESP8266 с активным mesh может упереться в RAM.
Архитектура¶
плата ─── mqtts://emqx.cloud.kavlev.ru:8883 ─── EMQX broker
│
├── topic: kavlev/<project>/<uuid>/cmd ← cloud команды
├── topic: kavlev/<project>/<uuid>/state ← плата шлёт
├── topic: kavlev/<project>/<uuid>/ack ← ack команд
└── LWT: kavlev/<project>/<uuid>/lwt ← disconnected
Phase Broker — наше имя для EMQX-инстанса в облаке. EMQX 5.x, MQTT 5.0, TLS обязательный.
Шаг 1. Включить в облаке¶
Интеграции проекта → MQTT → Включить.
Получите:
| Параметр | Пример |
|---|---|
| Broker host | emqx.cloud.kavlev.ru |
| Broker port | 8883 (mqtts) |
| TLS | Required |
Также автоматически создаются credentials для каждой платы проекта:
| Параметр | Что |
|---|---|
| Username | device_<uuid> |
| Password | Случайные 32 байта (видны один раз в UI) |
| ACL | publish/subscribe только на kavlev/<project>/<uuid>/* |
Шаг 2. Прописать на плате¶
В настройках MQTT платы (раздел появится когда MQTT включён в проекте):
| Поле | Значение |
|---|---|
| Broker URL | mqtts://emqx.cloud.kavlev.ru:8883 |
| Username | device_<ваш_uuid> |
| Password | Тот случайный, который выдало облако |
| CA cert | Загрузить опционально (или использовать встроенный bundle) |
После сохранения плата:
- Открывает TLS-соединение с брокером.
- Подписывается на
kavlev/<project>/<uuid>/cmd. - Публикует current state в
kavlev/<project>/<uuid>/state(retained). - Устанавливает LWT
disconnectedнаkavlev/<project>/<uuid>/lwt(retained).
С этого момента команды идут push'ем. HTTP-heartbeat продолжает работать как fallback (на случай если MQTT отвалился).
Топики¶
| Топик | Direction | Payload | Retained |
|---|---|---|---|
kavlev/<p>/<d>/state |
plate → cloud | {devices: [...], tasks: [...], uptime_sec, fw_version} |
yes |
kavlev/<p>/<d>/cmd |
cloud → plate | {id: 44, type: "set_relay", payload: {...}, cmd_id: "xyz"} |
no |
kavlev/<p>/<d>/ack |
plate → cloud | {cmd_id: "xyz", id: 44, status: "applied"} |
no |
kavlev/<p>/<d>/lwt |
broker → cloud | disconnected |
yes |
cmd_id — UUID команды, плата использует для дедупликации: если получит ту же команду повторно (например, после reconnect'а) — выполнит один раз.
Self-hosted клиент¶
Если хотите подключиться к плате напрямую (например, из Home Assistant):
Создать «virtual device» в проекте¶
В интеграциях → MQTT → + Создать клиент. Введите имя (home-assistant, например).
Получите credentials с ACL на kavlev/<project>/+/state (read-only на все state-топики проекта) и (опционально) kavlev/<project>/+/cmd (write).
Подключиться¶
# Home Assistant configuration.yaml
mqtt:
broker: emqx.cloud.kavlev.ru
port: 8883
username: ha_client_xyz
password: !secret kavlev_mqtt_password
certificate: auto
sensor:
- name: "Temperature kitchen"
state_topic: "kavlev/<project>/<plate_uuid>/state"
value_template: "{{ value_json.devices | selectattr('name', 'equalto', 'kitchen-temp') | map(attribute='value') | first }}"
unit_of_measurement: "°C"
switch:
- name: "Light kitchen"
state_topic: "kavlev/<project>/<plate_uuid>/state"
command_topic: "kavlev/<project>/<plate_uuid>/cmd"
value_template: "{{ value_json.devices | selectattr('id', 'equalto', 5) | map(attribute='state') | first | string | upper }}"
payload_on: '{"type":"set_relay","payload":{"device_id":5,"state":true},"cmd_id":"{{ as_timestamp(now()) }}"}'
payload_off: '{"type":"set_relay","payload":{"device_id":5,"state":false},"cmd_id":"{{ as_timestamp(now()) }}"}'
Безопасность¶
- TLS обязательный. Plain
mqtt://1883отключён на брокере. - Per-device credentials. Платы получают разные username/password. Утечка одного не компрометирует остальные.
- ACL ограничивает каждую плату только своими топиками. Плата
Aне может публиковать в топик платыB. - Cloud-side aerobic checks. Каждое сообщение в
/cmd-топике подписывается HMAC-SHA256 в payload — плата проверит подпись перед выполнением (защита если cloud-side скомпрометирован).
Что делать если MQTT отвалился¶
- Плата продолжает работать через HTTP-heartbeat (fallback).
- Через ~30 секунд плата попробует переподключиться к брокеру.
- В RAM-логе будут видны MQTT-ошибки (TLS, auth, и т.д.).
- В облаке статус платы —
mqtt offline, http active.
Если MQTT не критичен — можно временно выключить его в настройках платы → плата перестанет тратить ресурсы на reconnect-попытки.
Лимиты¶
| Параметр | Значение |
|---|---|
| Max connections per project | 50 (платы + клиенты) |
| Max msg size | 256 КБ |
| QoS supported | 0, 1 (не 2) |
| Retained on state topic | да, последний state-снапшот |
| Subscriptions per plate | 1 (только /cmd) |