ГлавнаяАкадемияNode-RED: установка, flows, msg/JSON, отладка → Работа с нодами MQTT In и MQTT Out

Работа с нодами MQTT In и MQTT Out

Урок 2 · Node-RED: установка, flows, msg/JSON, отладка · 30 мин · theory

Введение в ноды 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 in`: Нода-подписчик. Она «слушает» указанные топики на MQTT-брокере и при получении нового сообщения создает в потоке Node-RED объект `msg`, содержащий данные из этого сообщения. Это основной способ получения команд и данных от внешних систем.
  • `mqtt out`: Нода-издатель. Она принимает объект `msg` из потока Node-RED и публикует его содержимое (payload) в указанный MQTT-топик. Это основной способ отправки телеметрии, состояний и уведомлений во внешние системы.
  • Антипаттерны MQTT: Опасность "Бесконечной петли"

    При работе с этими нодами новички часто совершают критическую ошибку — публикацию в тот же топик, на который оформлена подписка.

    ⚠️ Пример "как делать нельзя":

    Вы создаете флоу, где `mqtt in` слушает топик `home/light/state`, а `mqtt out` отправляет данные в этот же топик `home/light/state` без какой-либо фильтрации. Это приводит к бесконечному циклу:

  • Нода `mqtt in` получает сообщение.
  • Оно проходит через логику и попадает в `mqtt out`.
  • `mqtt out` публикует его в брокер.
  • `mqtt in` тут же видит это «новое» сообщение и снова отправляет его в поток.
  • Это мгновенно перегружает процессор контроллера HI и забивает очередь сообщений брокера.

    Способы предотвращения:

    Понимание принципов работы этих нод и соблюдение гигиены топиков является фундаментальным навыком для любого инженера, работающего с платформой HI.

    Настройка подключения к MQTT-брокеру

    Прежде чем использовать ноды `mqtt in` и `mqtt out`, необходимо настроить соединение с MQTT-брокером. В Node-RED это делается через специальную конфигурационную ноду (config node). Эта нода создается один раз и затем используется всеми MQTT-нодами в вашем проекте, что обеспечивает централизованное управление подключением.

    Создание и настройка ноды mqtt-broker

  • Перетащите на холст любую MQTT-ноду (например, `mqtt in`).
  • Дважды кликните по ней, чтобы открыть окно настроек.
  • В поле "Server" выберите "Add new 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).

    Настройка во вкладке Messages конфигурационной ноды:

  • Birth Message:
  • * Topic: `hi/controllers/main/status`

    * Payload: `{"status": "online", "ts": 1678886400000}` (JSON-строка)

    * QoS: `1`

    * Retain: `true` (чтобы новые подписчики сразу узнали статус)

  • Last Will Message:
  • * 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`

    * `a string`: Полезная нагрузка будет строкой.

    * `a Buffer`: Полезная нагрузка будет бинарным буфером (для работы с файлами, изображениями).

    * `a parsed JSON object`: Node-RED попытается автоматически распарсить строку полезной нагрузки как JSON. Если парсинг не удался, сообщение будет отброшено и возникнет ошибка (которую можно поймать нодой `Catch`). Это предпочтительный вариант для работы со структурированными данными.

    Использование Wildcards (групповых символов)

    MQTT позволяет гибко подписываться на целые иерархии топиков с помощью двух специальных символов:

    * Подписка на `hi/floor1/+/light/main/state` позволит получать состояния главного света из всех комнат на первом этаже (`livingroom`, `kitchen`, `bedroom`). * Подписка на `hi/floor1/livingroom/#` позволит получать все сообщения, касающиеся гостиной: и свет, и климат, и датчики.

    При использовании 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`

    1. Задать статически: Вписать топик прямо в это поле, например, `hi/system/events/log`. В этом случае все сообщения, приходящие в эту ноду, будут опубликованы в этот конкретный топик.

    2. Оставить пустым: Если поле пустое, нода возьмет топик из свойства `msg.topic` входящего сообщения. Это позволяет динамически управлять топиком публикации в самом потоке, что является более гибким подходом.

    * `false` (по умолчанию): Сообщение будет доставлено только тем, кто подписан на топик в данный момент.

    * `true`: Брокер сохранит это сообщение как «последнее известное» для данного топика. Любой новый клиент, подписавшийся на этот топик, немедленно получит это сохраненное сообщение. Идеально подходит для публикации состояний устройств (`ON`/`OFF`, `23.5 °C`), чтобы новые клиенты (например, только что запущенное мобильное приложение) сразу знали текущее состояние системы.

    Практический пример отправки команды

    Предположим, нам нужно отправить команду на включение света.

  • Создаем ноду `inject`, которая формирует команду. В `msg.payload` мы поместим саму команду (`ON`), а в `msg.topic` — целевой топик.
  •     // Внутри ноды 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;

  • Подключаем выход этой ноды ко входу ноды `mqtt out`, у которой поле Topic оставлено пустым.
  • Нода `mqtt out` получит `msg`, увидит `msg.topic` и `msg.payload` и опубликует payload `"ON"` в топик `hi/floor1/livingroom/light/main/set`.
  • Если `payload` является объектом JavaScript, нода `mqtt out` автоматически преобразует его в строку JSON перед отправкой. Это стандартное и очень удобное поведение.

    Антипаттерны: Бесконечная петля (Loop)

    Самая опасная ошибка новичка — создание «мертвой петли» сообщений.

    Пример «как делать нельзя»:

    Представьте поток, где `mqtt in` подписана на топик `livingroom/lamp`, а её выход напрямую или через вычислительную логику соединен с `mqtt out`, которая публикует в тот же самый топик `livingroom/lamp`.

    Что произойдет:
  • Сообщение приходит из MQTT в Node-RED.
  • Node-RED обрабатывает его и тут же отправляет обратно в MQTT в тот же топик.
  • `mqtt in` видит новое сообщение в топике и снова берет его в обработку.
  • Цикл повторяется бесконечно (сотни раз в секунду), вызывая 100% нагрузку на CPU и падение брокера или Node-RED.
  • Как предотвратить:

    Практический кейс: Двусторонний обмен данными

    Рассмотрим классический сценарий «замкнутого контура» управления: мы отправляем команду на исполнительное устройство и получаем от него подтверждение о смене состояния. Это гарантирует, что наше представление о состоянии системы (в Node-RED) всегда соответствует реальности.

    > 💡 Подсказка: Разделяйте логику: используйте ноды `mqtt out` для отправки команд и отдельные ноды `mqtt in` для получения состояний. Это делает поток (`flow`) более читаемым и легким в отладке по сравнению с созданием сложных циклических конструкций, где одно и то же сообщение проходит через ноды много раз.

    Задача: Управлять реле, подключенным к другому устройству (например, ESP8266 или другому контроллеру HI), через MQTT.

    Шаг 1: Создание потока отправки команды

  • Создадим две ноды `inject` для имитации кнопок "ВКЛ" и "ВЫКЛ".
  • * Кнопка "ВКЛ": `msg.payload` (string) = `ON`.

    * Кнопка "ВЫКЛ": `msg.payload` (string) = `OFF`.

  • Обе ноды `inject` подключим к ноде `change`, которая устанавливает целевой топик: `Set msg.topic to "hi/relays/r-01/set"`.
  • Выход ноды `change` подключим к ноде `mqtt out`. У этой ноды поле Topic должно быть пустым, QoS `= 1`, Retain `= false`.
  • [Inject: "ON"] --+
    

    |--> [Change: set topic] --> [mqtt out]

    [Inject: "OFF"] --+

    Шаг 2: Создание потока получения состояния

  • На том же или другом холсте создадим ноду `mqtt in`.
  • Настроим ее на подписку:
  • * Topic: `hi/relays/r-01/state`

    * QoS: `1`

    * Output: `a string`

  • Подключим к выходу ноды `mqtt in` ноду `debug` с выводом `msg.payload`. Также можно подключить ее к UI-элементу (например, `ui_text` или `ui_switch`) для визуализации состояния.
  • [mqtt in: .../state] --> [Debug: show payload]
    

    Шаг 3: Логика на стороне исполнителя (гипотетическая)

    Исполнительное устройство (другой контроллер или микроконтроллер) реализует следующую логику:

  • Подписывается на топик `hi/relays/r-01/set`.
  • При получении сообщения `"ON"`:
  • * Физически замыкает реле.

    * Публикует сообщение `"ON"` в топик `hi/relays/r-01/state` с флагом `retain=true`.

  • При получении сообщения `"OFF"`:
  • * Физически размыкает реле.

    * Публикует сообщение `"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-взаимодействий, помимо встроенной ноды `debug`, настоятельно рекомендуется использовать внешние утилиты, такие как MQTT Explorer. Этот инструмент позволяет в реальном времени видеть все сообщения, проходящие через брокер, и быстро диагностировать проблемы со структурой топиков или форматом данных.

    Что дальше?

    До сих пор мы работали в основном с простыми строковыми данными в `payload`. Однако реальная мощь MQTT раскрывается при передаче структурированных данных. В следующем уроке мы подробно разберем, как работать с форматом JSON в MQTT-сообщениях для передачи нескольких параметров в одном сообщении, что является стандартом для сложных систем автоматизации.