`msg.payload`: основной контейнер данных
Роль msg.payload в потоках Node-RED
В экосистеме Node-RED объект сообщения `msg` является универсальной единицей информации, кровью, циркулирующей по артериям потоков. Но если сам `msg` — это конверт, то `msg.payload` — это его основное содержимое. Именно в этом свойстве, по общепринятому соглашению, передаются полезные данные от одного узла к другому.
> 🔗 Связанный материал: Полная структура объекта `msg`, включая `topic` и другие стандартные свойства, подробно рассмотрена в предыдущем уроке "Анатомия объекта `msg`: payload, topic и другие свойства" (COURSE-06-M02-L01).
Большинство стандартных и сторонних узлов в Node-RED спроектированы так, чтобы по умолчанию считывать данные из `msg.payload` и записывать результат своей работы также в `msg.payload`. Например:
- Узел `mqtt in` помещает тело полученного MQTT-сообщения в `msg.payload`.
- Узел `http request` помещает ответ от сервера в `msg.payload`.
- Узел `function` получает `msg` на вход и может как угодно модифицировать `msg.payload` перед отправкой на выход.
- Узел `debug` по умолчанию выводит в панель отладки именно содержимое `msg.payload`.
Такая конвенция критически важна для создания совместимых и читаемых потоков. Когда инженер открывает чужой или свой старый проект, он может с высокой долей уверенности предполагать, что основные данные передаются именно через `payload`. Это кардинально упрощает отладку и понимание логики.
Отличие данных от метаданных
Важно понимать различие между `payload` и другими свойствами объекта `msg`, такими как `topic`, `_msgid`, `qos`, `parts` и т.д. Эти свойства несут метаданные — информацию о данных, а не сами данные.
- `msg.payload`: Содержит ЧТО передается (значение температуры, команда на включение, текст сообщения).
- `msg.topic`: Содержит контекст, или КУДА/ОТКУДА идут данные (например, `office/room101/temperature/state`). Как мы уже рассматривали ранее, `topic` является ключевым инструментом для маршрутизации сообщений с помощью узла `Switch`.
> ℹ️ Информация: Хотя `msg.payload` является стандартом де-факто, многие узлы позволяют изменить это поведение. Например, в узле `mqtt out` можно указать, чтобы данные для отправки брались не из `payload`, а из другого свойства, скажем, `msg.data`. Это может быть полезно в сложных сценариях, когда нужно сохранить оригинальный `payload` неизменным, но не является стандартной практикой и должно использоваться с осторожностью и хорошим комментированием.
Соблюдение этого простого правила — данные в `payload`, контекст в `topic` — является фундаментом для построения надежных и легко поддерживаемых систем автоматизации на платформе HI.
---
Основные типы данных в msg.payload
Поскольку Node-RED построен на базе Node.js, `msg.payload` может содержать любой тип данных, поддерживаемый JavaScript. Понимание этих типов и их правильное применение — ключ к созданию предсказуемых потоков.
| Тип данных | Описание и применение | Пример в `msg.payload` |
| :--- | :--- | :--- |
| String (Строка) | Текстовые данные. Используется для передачи команд (`"ON"`, `"OFF"`), статусов (`"open"`, `"closed"`), имен, а также для передачи данных в формате JSON (сериализованный объект). | `"Hello, World!"` или `"{\"temp\":21.5}"` |
| Number (Число) | Числовые значения, как целые (Integer), так и с плавающей точкой (Float). Основной тип для показаний датчиков: температура, влажность, давление, уровень CO2, показания счетчиков. | `23.7` или `1500` |
| Boolean (Булево) | Логические значения `true` (истина) или `false` (ложь). Идеально подходит для представления бинарных состояний: включено/выключено, открыто/закрыто, есть протечка/нет протечки. | `true` |
| Object (Объект) | Структурированные данные в формате ключ-значение (JSON). Самый мощный и рекомендуемый тип для передачи нескольких связанных параметров в одном сообщении. Позволяет создавать читаемые и расширяемые контракты сообщений. | `{"value": 25.1, "unit": "°C", "ts": 1678886400}` |
| Array (Массив) | Упорядоченный список значений. Полезен для передачи серии показаний, списка устройств или результатов, полученных от нескольких источников. | `[21.5, 21.6, 21.4]` |
| Buffer (Буфер) | Массив байт для представления бинарных данных. Используется в специфических случаях: работа с файлами, изображениями, или при низкоуровневом взаимодействии с протоколами вроде Modbus RTU, где данные приходят в виде сырого набора байт. | `
| null / undefined | Специальные значения, обозначающие "отсутствие данных". Поток сообщения с `msg.payload`, равным `null`, часто прерывается, так как многие узлы не знают, как его обработать. Это может быть полезно для фильтрации. | `null` |
Практические примеры для каждого типа:
- String: Кнопка на панели управления отправляет команду в виде строки.
{
"payload": "START_PUMP_01",
"topic": "commands/pumps/control"
}
- Number: Датчик температуры DS18B20 на универсальном входе контроллера передает измеренное значение.
{
"payload": 22.5,
"topic": "telemetry/living_room/temperature"
}
- Boolean: Геркон на двери сообщает о своем состоянии.
{
"payload": true,
"topic": "telemetry/main_door/is_open"
}
- Object (JSON): Комбинированный датчик влажности и температуры передает все данные в одном сообщении. Это предпочтительный подход, так как он атомарен и несет максимум контекста.
{
"payload": {
"temperature": 24.1,
"humidity": 45.8,
"source": "sensor-th-01-room2",
"ts": 1680525143000
},
"topic": "telemetry/room2/environment"
}
- Array: Сценарий запрашивает температуру в трех разных комнатах и собирает результат в массив.
{
"payload": [22.1, 24.5, 19.8],
"topic": "telemetry/house/avg_temperature_calc"
}
- Buffer: Узел `modbus-read` считывает два 16-битных регистра.
{
"payload": { "data": [1036, 17203], "buffer": },
"topic": "modbus/read/response"
}
В данном случае `payload` является объектом, но его ключевое содержимое — это свойство `buffer` типа Buffer.
---
Практика: Изменение типа и содержимого payload с помощью узла Change
Узел `Change` — один из самых универсальных и часто используемых инструментов в Node-RED. Он позволяет выполнять самые разнообразные манипуляции с объектом `msg`, и в первую очередь с `msg.payload`, без написания кода в узле `Function`.
Рассмотрим четыре основные операции с `msg.payload`.
1. Установка нового значения (Set)
Это правило полностью заменяет содержимое `msg.payload` новым значением.
Задача: Преобразовать входящее сообщение с timestamp в строку "Проверено".* Set: `msg.payload`
* to: (выберите тип "string") `Проверено`
2. Изменение внутри строки (Change)
Это правило позволяет найти и заменить часть строки.
Задача: Стандартизировать сообщения о состоянии. Заменить "Warning" на "ALERT".* Change: `msg.payload`
* Search for: (тип "string") `Warning`
* Replace with: (тип "string") `ALERT`
3. Работа с JSON-объектами
Узел `Change` отлично подходит для манипуляций со структурированными данными.
Задачи:А. Извлечь одно значение из объекта в `payload`.
Б. Изменить значение по ключу внутри объекта.
Настройка:
{
"temperature": 25,
"humidity": 60,
"status": "OK"
}
* Set: `msg.payload`
* to: (выберите тип "msg.") `msg.payload.temperature`
* Результатом будет `msg.payload`, равный числу `25`.
* Set: `msg.payload.status`
* to: (тип "string") `ERROR`
* Результатом будет исходный объект, но с измененным полем `status`: `{"temperature": 25, "humidity": 60, "status": "ERROR"}`.
4. Трансформация данных с помощью JSONata
JSONata — это мощный язык запросов и преобразований для JSON, встроенный в Node-RED. Он позволяет выполнять сложные трансформации данных одной строкой, на которые в узле `Function` ушли бы десятки строк кода.> 💡 Подсказка: Используйте встроенный редактор JSONata в узле `Change`. Когда вы выбираете тип `J: (expression)`, появляется кнопка `...`, открывающая редактор. Он позволяет видеть результат трансформации на примере реального сообщения, что значительно ускоряет отладку.
Задача: Преобразовать "сырые" данные от Modbus-устройства в понятный JSON-объект.Предположим, узел `modbus-read` выдал нам такой `payload`: `{"value": 255, "unitId": 10}`. Нам нужно преобразовать это в стандартный формат `{ "temperature": 25.5, "unit": "°C", "device": "modbus:10" }`.
* Set: `msg.payload`
* to: (выберите тип "J: expression")
* В поле выражения введите:
{
"temperature": payload.value / 10,
"unit": "°C",
"device": "modbus:" & payload.unitId
}
{
"temperature": 25.5,
"unit": "°C",
"device": "modbus:10"
}
Это наглядный пример мощи JSONata: мы выполнили арифметическую операцию, добавили статическую строку и выполнили конкатенацию (слияние) строк в одном выражении.
---
Пример: msg.payload в протоколе MQTT
Протокол MQTT является основным протоколом для межмашинного взаимодействия (M2M) в IoT и системах автоматизации. В Node-RED работа с ним строится вокруг `msg.payload` и `msg.topic`.
- Узел `mqtt in`: Подписывается на указанный топик. Когда приходит сообщение, его тело помещается в `msg.payload`.
- Узел `mqtt out`: Публикует сообщение в указанный топик. По умолчанию, в качестве тела сообщения берутся данные из `msg.payload`.
Сериализация и десериализация
Большинство MQTT-брокеров и клиентов работают с сообщениями как с набором байт, который чаще всего интерпретируется как строка. Это означает, что если вы хотите передать сложную структуру (JSON-объект), ее необходимо сериализовать — преобразовать в строку. При получении происходит обратный процесс — десериализация.
> ⚠️ Внимание: Многие внешние системы и брокеры MQTT ожидают на входе `payload` в виде строки. Если вы отправляете JSON-объект из Node-RED, его необходимо явно преобразовать в строку с помощью узла `JSON` или функции `JSON.stringify()` в узле `Function`. Узел `mqtt out` в Node-RED часто делает это автоматически для объектов, но полагаться на это не всегда безопасно, особенно при работе со сторонними клиентами. Явное преобразование делает поток более надежным и понятным.
Практический кейс: датчик и исполнительное устройство
Сценарий 1: Отправка данных с датчика Цель: Каждые 10 секунд отправлять показания температуры и влажности в виде JSON-объекта в топик `hi/office/env/state`.
msg.payload = {
"temperature": parseFloat((22 + Math.random() * 2).toFixed(1)),
"humidity": parseFloat((40 + Math.random() * 5).toFixed(1)),
"ts": Date.now()
};
return msg;
После этого узла `Function` `msg.payload` будет объектом. После узла `JSON` `msg.payload` станет строкой вида: `'{"temperature":22.5,"humidity":42.1,"ts":1680525999000}'`. Именно эта строка и будет отправлена в MQTT.
Сценарий 2: Получение команды на управление реле Цель: Слушать топик `hi/office/light/set` и управлять реле. Команды приходят в виде строк `"ON"` и `"OFF"`.* Правило 1: `==` (строка) `ON` -> выход 1.
* Правило 2: `==` (строка) `OFF` -> выход 2.
В этом потоке `mqtt in` получает строку `"ON"` или `"OFF"` в `msg.payload`. Узел `Switch` анализирует эту строку и направляет поток по нужной ветке, где `msg.payload` преобразуется в булев тип, понятный для узла управления физическим оборудованием.
---
Резюме и лучшие практики работы с msg.payload
`msg.payload` — это сердце любого сообщения в Node-RED, основной способ передачи полезных данных между узлами. Правильная работа с ним — залог создания надежных, читаемых и легко поддерживаемых потоков автоматизации.
📋 Ключевые практики:
Освоив эти принципы, вы сможете эффективно управлять потоками данных, создавая мощные и элегантные решения на платформе HI.
Что дальше?
В следующем уроке мы углубимся в работу с `msg.topic`, рассмотрим продвинутые техники маршрутизации сообщений и создания динамической логики на основе иерархии топиков.