Работа с нодами MQTT In и MQTT Out
Введение в ноды MQTT в Node-RED
ведение в ноды MQTT в Node-RED
🔗 Связанный материал: Данный урок предполагает, что вы уже знакомы с основами протокола MQTT, включая такие понятия как брокер, топики, Publish/Subscribe и QoS. Для повторения этой информации обратитесь к уроку COURSE-06-M08-L01: Основы MQTT.
Протокол MQTT (Message Queuing Telemetry Transport) является нервной системой современной автоматизации, особенно в экосистеме контроллеров HI. Благодаря своей легковесности и архитектуре издатель-подписчик (Publish/Subscribe), он идеально подходит для обмена данными между разнородными устройствами: от датчиков и реле до мобильных приложений и облачных сервисов. Контроллер HI выступает в роли центрального хаба, собирая телеметрию и распределяя команды управления, и MQTT является ключевым протоколом для этой коммуникации.
В среде Node-RED, которая является ядром программной логики контроллера HI, взаимодействие с миром MQTT реализуется через два основных узла (ноды) из стандартной палитры:
Антипаттерны MQTT: Опасность "Бесконечной петли"
При работе с этими нодами новички часто совершают критическую ошибку — публикацию в тот же топик, на который оформлена подписка.
⚠️ Пример "как делать нельзя":
Вы создаете флоу, где `mqtt in` слушает топик `home/light/state`, а `mqtt out` отправляет данные в этот же топик `home/light/state` без какой-либо фильтрации. Это приводит к бесконечному циклу:
Это мгновенно перегружает процессор контроллера HI и забивает очередь сообщений брокера.
Способы предотвращения:- Разделение топиков (Best Practice): Используйте разные топики для команд и состояний (например, `.../set` для управления и `.../state` для обратной связи).
- Проверка изменений (RBE): Используйте ноду `filter` (report by exception), чтобы пропускать сообщение дальше только в том случае, если его значение реально изменилось.
- Флаги блокировки: Установка признака `msg.nopublish` внутри функций перед отправкой на выход, если сообщение не требует повторной публикации.
Понимание принципов работы этих нод и соблюдение гигиены топиков является фундаментальным навыком для любого инженера, работающего с платформой HI.
Настройка подключения к MQTT-брокеру
Прежде чем использовать ноды `mqtt in` и `mqtt out`, необходимо настроить соединение с MQTT-брокером. В Node-RED это делается через специальную конфигурационную ноду (config node). Эта нода создается один раз и затем используется всеми MQTT-нодами в вашем проекте, что обеспечивает централизованное управление подключением.
Создание и настройка ноды mqtt-broker
Откроется окно конфигурации подключения. Рассмотрим его ключевые параметры:
| Вкладка | Параметр | Описание | Пример для контроллера HI |
| :---------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| Connection | Server | IP-адрес или доменное имя MQTT-брокера. | `127.0.0.1` (если брокер запущен на самом контроллере) или `192.168.1.10` (адрес выделенного сервера в локальной сети). |
| Connection | Port | TCP-порт брокера. Стандартный порт — `1883` для незащищенного соединения и `8883` для соединения с использованием TLS (SSL). | `1883` |
| Connection | Client ID | Уникальный идентификатор клиента в рамках одного брокера. Если два клиента подключатся с одинаковым ID, брокер будет постоянно разрывать соединение с одним из них. | `hi-controller-living-room` или `hi-node-red-main`. |
| Security | Username | Имя пользователя для аутентификации на брокере, если она включена. | `hi_controller` |
| Security | Password | Пароль для указанного имени пользователя. | `YourS3cureP@ssw0rd` |
| Connection | TLS | Конфигурация защищенного соединения. Требует загрузки сертификатов. Используется для шифрования трафика между контроллером и брокером. | Зависит от настроек брокера. |
⚠️ Внимание: Критически важно использовать уникальный Client ID для каждого устройства, подключаемого к брокеру. Дублирование Client ID приводит к постоянным обрывам соединения («flapping connection») и нестабильной работе всей системы. Хорошей практикой является использование серийного номера устройства или его проектного имени в качестве Client ID.
Мониторинг статуса: Birth и Last Will and Testament (LWT)
Для создания надежной системы необходимо знать, находится ли контроллер в сети. MQTT предоставляет для этого элегантный механизм — "Завещание" (LWT) и "Сообщение о рождении" (Birth Message).
- Birth Message (Сообщение о рождении): Это сообщение, которое клиент (наш контроллер HI) публикует в специальный топик сразу после успешного подключения к брокеру. Обычно оно содержит информацию о том, что устройство онлайн.
- Last Will and Testament (LWT, Завещание): Это сообщение, которое клиент настраивает при подключении. Если клиент неожиданно отключается (сбой питания, обрыв сети) и не отправляет команду `DISCONNECT`, брокер автоматически публикует это сообщение от его имени.
Настройка во вкладке Messages конфигурационной ноды:
* Topic: `hi/controllers/main/status`
* Payload: `{"status": "online", "ts": 1678886400000}` (JSON-строка)
* QoS: `1`
* Retain: `true` (чтобы новые подписчики сразу узнали статус)
* Topic: `hi/controllers/main/status`
* Payload: `{"status": "offline", "ts": 1678886500000}` (JSON-строка)
* QoS: `1`
* Retain: `true`
Такая конфигурация позволяет любой другой системе (например, панели визуализации или системе верхнего уровня) просто подписаться на топик `hi/controllers/main/status` и всегда знать актуальное состояние контроллера.
---
Получение данных: Нода MQTT In
Нода `mqtt in` является «ушами» вашего контроллера в мире MQTT. Она подписывается на один или несколько топиков и генерирует сообщение в потоке Node-RED каждый раз, когда в этот топик приходит новое сообщение.
> 💡 Подсказка: Всегда подключайте ноду `debug` к выходу `mqtt in` на этапе разработки. Установите в настройках `debug` вывод всего объекта сообщения (`complete msg object`), чтобы видеть и `msg.payload`, и `msg.topic`. Это незаменимо при отладке подписок с использованием групповых символов (wildcards).
Конфигурация ноды `mqtt in`
- Server: Выберите ранее созданную конфигурационную ноду `mqtt-broker`.
- Action: `Subscribe to a single topic`.
- Topic: Здесь указывается топик, на который нужно подписаться. Например, `hi/floor1/livingroom/light/main/set`.
- QoS: Качество обслуживания. Обычно `0` или `1` для получения команд.
- Output: Определяет, в каком формате `msg.payload` будет представлен в потоке Node-RED.
* `a Buffer`: Полезная нагрузка будет бинарным буфером (для работы с файлами, изображениями).
* `a parsed JSON object`: Node-RED попытается автоматически распарсить строку полезной нагрузки как JSON. Если парсинг не удался, сообщение будет отброшено и возникнет ошибка (которую можно поймать нодой `Catch`). Это предпочтительный вариант для работы со структурированными данными.
Использование Wildcards (групповых символов)
MQTT позволяет гибко подписываться на целые иерархии топиков с помощью двух специальных символов:
- `+` (плюс): Заменяет один уровень в иерархии топиков.
- `#` (решетка): Заменяет один или несколько уровней в конце иерархии. Должен быть последним символом в топике.
При использовании wildcards свойство `msg.topic` становится критически важным, так как оно содержит конкретный топик, из которого пришло сообщение. Это позволяет использовать одну ноду `mqtt in` и ноду `switch` для маршрутизации сообщений в разные ветки логики.
Пример:Нода `mqtt in` подписана на топик `hi/sensors/+/temperature`.
Если с датчика в офисе придет сообщение в топик `hi/sensors/office101/temperature` с payload `23.5`, то на выходе `mqtt in` появится объект `msg`:
{
"topic": "hi/sensors/office101/temperature",
"payload": "23.5",
"qos": 0,
"retain": false,
"_msgid": "..."
}
Этот объект затем можно обработать: из `msg.topic` извлечь ID датчика (`office101`), а из `msg.payload` — значение температуры.
---
Отправка данных: Нода MQTT Out
тправка данных: Нода MQTT Out
Нода `mqtt out` — это «голос» вашего контроллера. Она берет входящий `msg` и публикует его `payload` в MQTT-топик.
> 🔗 Связанный материал: Для формирования корректной и масштабируемой структуры топиков (например, разделение на суффиксы `.../set` для команд и `.../state` для статусов) обратитесь к материалам урока COURSE-06-M08-L02: Проектирование структуры топиков MQTT.
Конфигурация ноды `mqtt out`
- Server: Выберите ту же конфигурационную ноду `mqtt-broker`.
- Topic: Здесь есть два варианта:
2. Оставить пустым: Если поле пустое, нода возьмет топик из свойства `msg.topic` входящего сообщения. Это позволяет динамически управлять топиком публикации в самом потоке, что является более гибким подходом.
- QoS: Качество обслуживания. `0` — "отправил и забыл", `1` — "гарантированная доставка как минимум один раз". Для отправки состояний рекомендуется `QoS=1`.
- Retain: Флаг удержания сообщения.
* `true`: Брокер сохранит это сообщение как «последнее известное» для данного топика. Любой новый клиент, подписавшийся на этот топик, немедленно получит это сохраненное сообщение. Идеально подходит для публикации состояний устройств (`ON`/`OFF`, `23.5 °C`), чтобы новые клиенты (например, только что запущенное мобильное приложение) сразу знали текущее состояние системы.
Практический пример отправки команды
Предположим, нам нужно отправить команду на включение света.
// Внутри ноды function или change, готовящей сообщение
msg.topic = "hi/floor1/livingroom/light/main/set";
msg.payload = "ON";
return msg;
Или, если `payload` должен быть в формате JSON:
msg.topic = "hi/floor1/livingroom/light/main/set";
msg.payload = {
"state": "ON",
"brightness": 100
};
return msg;
Если `payload` является объектом JavaScript, нода `mqtt out` автоматически преобразует его в строку JSON перед отправкой. Это стандартное и очень удобное поведение.
Антипаттерны: Бесконечная петля (Loop)
Самая опасная ошибка новичка — создание «мертвой петли» сообщений.
Пример «как делать нельзя»:Представьте поток, где `mqtt in` подписана на топик `livingroom/lamp`, а её выход напрямую или через вычислительную логику соединен с `mqtt out`, которая публикует в тот же самый топик `livingroom/lamp`.
Что произойдет:- Разделяйте топики: Используйте `/set` для команд и `/state` для статусов. Подписывайтесь на один, публикуйте в другой.
- Проверка изменений (RBE): Используйте ноду `filter` (rbe), чтобы пропускать сообщение дальше только в том случае, если значение реально изменилось.
- Поле msg.from: При сложной логике добавляйте в объект сообщения признак отправителя и фильтруйте его перед публикацией.
Практический кейс: Двусторонний обмен данными
Рассмотрим классический сценарий «замкнутого контура» управления: мы отправляем команду на исполнительное устройство и получаем от него подтверждение о смене состояния. Это гарантирует, что наше представление о состоянии системы (в Node-RED) всегда соответствует реальности.
> 💡 Подсказка: Разделяйте логику: используйте ноды `mqtt out` для отправки команд и отдельные ноды `mqtt in` для получения состояний. Это делает поток (`flow`) более читаемым и легким в отладке по сравнению с созданием сложных циклических конструкций, где одно и то же сообщение проходит через ноды много раз.
Задача: Управлять реле, подключенным к другому устройству (например, ESP8266 или другому контроллеру HI), через MQTT.- Топик для команд: `hi/relays/r-01/set`
- Топик для состояния: `hi/relays/r-01/state`
Шаг 1: Создание потока отправки команды
* Кнопка "ВКЛ": `msg.payload` (string) = `ON`.
* Кнопка "ВЫКЛ": `msg.payload` (string) = `OFF`.
[Inject: "ON"] --+
|--> [Change: set topic] --> [mqtt out]
[Inject: "OFF"] --+
Шаг 2: Создание потока получения состояния
* Topic: `hi/relays/r-01/state`
* QoS: `1`
* Output: `a string`
[mqtt in: .../state] --> [Debug: show payload]
Шаг 3: Логика на стороне исполнителя (гипотетическая)
Исполнительное устройство (другой контроллер или микроконтроллер) реализует следующую логику:
* Физически замыкает реле.
* Публикует сообщение `"ON"` в топик `hi/relays/r-01/state` с флагом `retain=true`.
* Физически размыкает реле.
* Публикует сообщение `"OFF"` в топик `hi/relays/r-01/state` с флагом `retain=true`.
Как это работает вместе?
Когда вы нажимаете кнопку "ВКЛ" в Node-RED, `mqtt out` отправляет `ON` в топик `.../set`. Исполнитель получает команду, включает реле и публикует `ON` в топик `.../state`. Нода `mqtt in` в нашем контроллере HI получает это сообщение о состоянии, и мы видим в `debug`, что реле действительно включилось. Этот замкнутый контур подтверждает, что команда была не только отправлена, но и выполнена. Разделение на топики `set` и `state` предотвращает "эхо" и зацикливание, обеспечивая чистоту и предсказуемость логики.
---
Итоги и лучшие практики
В этом уроке мы рассмотрели фундаментальные инструменты для работы с протоколом MQTT в Node-RED — ноды `mqtt in` и `mqtt out`. Уверенное владение ими открывает двери для интеграции контроллера HI с практически любым устройством или сервисом в современной экосистеме IoT.
📋 Ключевые понятия:
- Конфигурационная нода `mqtt-broker` является центральной точкой для настройки подключения.
- Уникальный Client ID — залог стабильного соединения.
- LWT и Birth Message необходимы для мониторинга доступности контроллера в сети.
- `mqtt in` подписывается на топики, используя wildcards (`+`, `#`) для гибкости. `msg.topic` содержит конкретный топик, из которого пришло сообщение.
- `mqtt out` публикует сообщения, позволяя динамически задавать топик через `msg.topic`.
- Флаг Retain используется для публикации состояний, чтобы новые подписчики сразу узнавали текущий статус.
- Разделение топиков на `.../set` (команды) и `.../state` (состояния) является лучшей практикой для создания надежных систем управления.
Для отладки MQTT-взаимодействий, помимо встроенной ноды `debug`, настоятельно рекомендуется использовать внешние утилиты, такие как MQTT Explorer. Этот инструмент позволяет в реальном времени видеть все сообщения, проходящие через брокер, и быстро диагностировать проблемы со структурой топиков или форматом данных.
Что дальше?
До сих пор мы работали в основном с простыми строковыми данными в `payload`. Однако реальная мощь MQTT раскрывается при передаче структурированных данных. В следующем уроке мы подробно разберем, как работать с форматом JSON в MQTT-сообщениях для передачи нескольких параметров в одном сообщении, что является стандартом для сложных систем автоматизации.