К содержимому

Инструкции: IoT и умный дом

Как устроен обмен сообщениями MQTT: топики, полезная нагрузка, QoS

MQTT держит на себе связь датчиков, реле и панелей в большинстве самодельных умных домов. Разберём, как по нему ходят сообщения и почему порядок в топиках важнее, чем кажется.

редакция «Топика»~5 мин

Разделы материала

Три участника: издатель, подписчик и брокер

В классической схеме «клиент — сервер» устройство обращается к конкретному адресу и ждёт ответа. В MQTT всё иначе. Каждое устройство — клиент, который держит одно постоянное соединение с брокером. Термометр на балконе ничего не знает о панели на телефоне: он просто публикует сообщение «температура такая-то» в свой топик. Панель, в свою очередь, не знает о термометре: она подписана на топик и получает всё, что туда приходит.

Такое разделение даёт два важных свойства. Во-первых, можно добавлять новых получателей, не трогая прошивку датчика: захотели писать историю в базу — подписали ещё одного клиента. Во-вторых, устройства могут находиться за разными роутерами и даже не видеть друг друга, им достаточно доступа к брокеру. О том, где этот брокер поселить, подробно рассказывает материал про домашний брокер.

Топики: адрес сообщения

Топик — строка, разделённая косыми чертами на уровни. Брокер не требует их заранее объявлять: топик появляется в момент первой публикации. Это удобно и опасно одновременно — опечатка в прошивке молча создаёт новый канал, и сообщения уходят в никуда.

Как строить иерархию

Хорошая схема идёт от общего к частному: дом, помещение, устройство, параметр. Возьмём условную квартиру в городе N с датчиками в кухне и детской:

kvartira/kuhnya/termometr/temperatura
kvartira/kuhnya/termometr/vlazhnost
kvartira/detskaya/rele-svet/sostoyanie
kvartira/detskaya/rele-svet/komanda

Обратите внимание на пару «состояние» и «команда» у реле. Устройство сообщает, что оно сейчас делает, в один топик, а слушает приказы в другом. Если смешать их, панель будет получать собственные команды как «состояние» и показывать неправду.

Маски подписки

Подписчик может указать не один топик, а шаблон:

  • + заменяет ровно один уровень: kvartira/+/termometr/temperatura — температура из всех комнат;
  • # заменяет все уровни до конца и ставится только последним: kvartira/kuhnya/# — всё, что происходит на кухне.

Маски работают только при подписке. Публиковать в топик со знаком + или # нельзя.

Про регистр и пробелы

Топики чувствительны к регистру: Kuhnya и kuhnya — два разных канала. Пробелы формально допустимы, но мешают при отладке из командной строки. Проще всего писать латиницей в нижнем регистре, разделяя слова дефисом.

Полезная нагрузка: что лежит внутри

Протоколу безразлично содержимое сообщения — это просто набор байтов. Договорённость о формате целиком на вашей стороне. Встречаются два подхода.

Одно значение — один топик. В сообщении только число или слово: 21.5, ON. Это просто, легко читается в отладке и удобно для панелей, где каждый элемент привязан к своему топику.

Структура в одном топике. Устройство отправляет JSON с несколькими полями:

{"temperatura": 21.5, "vlazhnost": 44, "batareya": 87, "ts": "2026-11-02T08:15:00Z"}

Так меньше сообщений и все показания приходят согласованными. Но каждому получателю придётся разбирать JSON и знать имена полей. Выберите один подход для всего дома и придерживайтесь его: смешанная схема быстро превращается в головоломку.

Качество доставки: QoS 0, 1 и 2

Уровень QoS задаётся отдельно для публикации и для подписки; действует меньший из двух.

Уровни QoS в MQTT
УровеньЧто гарантируетКогда подходит
QoS 0«Отправил и забыл», сообщение может потерятьсячастые показания датчиков, где потеря одного значения не важна
QoS 1доставка хотя бы один раз, возможны дубликоманды реле и события, которые нельзя пропустить
QoS 2ровно одна доставка за счёт четырёх шагов обменасчётчики и операции, где дубль даст неверный результат

Для большинства домашних задач хватает нулевого и первого уровня. Второй дороже по трафику и задержке, а слабые микроконтроллеры не всегда его поддерживают.

Retained, last will и keepalive

Retained — флаг «запомнить». Брокер хранит последнее сообщение с этим флагом в топике и сразу отдаёт его каждому новому подписчику. Без него панель после перезапуска будет показывать пустоту до следующего показания датчика. Ставьте retained на состояния, а не на команды: иначе реле при каждом переподключении будет заново выполнять старый приказ.

Last will — «завещание». При подключении клиент оставляет брокеру сообщение, которое тот опубликует, если связь оборвётся без штатного прощания. Обычно это offline в топике вида kvartira/kuhnya/termometr/status, а при удачном подключении устройство само публикует туда online с флагом retained. Так панель честно показывает, что датчик пропал.

Keepalive — интервал, в течение которого клиент обязан подать признак жизни. Если он молчит дольше, брокер считает соединение разорванным и публикует завещание. Слишком короткий интервал разряжает батарейные устройства, слишком длинный — заставляет долго ждать сигнала о пропаже.

Чек-лист перед первым датчиком

  • Схема топиков записана: дом / помещение / устройство / параметр.
  • Для каждого исполнительного устройства есть отдельные топики состояния и команды.
  • Выбран единый формат нагрузки — одиночное значение или JSON.
  • Состояния публикуются с retained, команды — без него.
  • У каждого устройства настроено завещание и топик статуса.
  • Определён уровень QoS для показаний и для команд.
  • Есть способ подписаться на # и посмотреть весь трафик при отладке.

Типичные ошибки

  1. Топик по имени модели устройства. Через год датчик меняют на другой, и вся автоматика, завязанная на старое имя, ломается. Называйте топики по месту и смыслу.
  2. Retained на командах. Свет включается сам после каждого перезапуска брокера — классический симптом.
  3. Ведущая косая черта. Топик /kvartira/kuhnya содержит пустой первый уровень и не совпадает с kvartira/kuhnya. Отсюда «невидимые» сообщения.
  4. Всё в одном топике. Когда весь дом публикует в общий канал, каждый подписчик получает лишнее и вынужден фильтровать.
  5. Отладка без подписки на всё. Пока не увидишь реальный поток сообщений, трудно понять, кто ошибся — датчик или панель.

Когда обмен налажен, показания можно выводить на экран: подходящий элемент для этого подскажут материалы про стрелочный индикатор и график показаний.

Вопросы и ответы

Нужен ли интернет, чтобы MQTT работал дома?

Нет. Если брокер стоит в домашней сети, датчики и панель обмениваются сообщениями локально. Интернет понадобится только для доступа снаружи.

Сколько топиков может быть у одного устройства?

Сколько угодно: протокол не ограничивает их число. Разумно держать по одному топику на параметр плюс топики статуса и команд.

Можно ли писать топики кириллицей?

Стандарт допускает UTF-8, но часть прошивок и утилит работает с кириллицей неуверенно. Транслит в нижнем регистре избавит от сюрпризов.

Почему панель показывает старое значение после перезагрузки датчика?

Скорее всего, сработал retained: брокер отдал последнее сохранённое состояние. Это нормально, если устройство после старта публикует свежее значение.