ГлавнаяАкадемияNode-RED: установка, flows, msg/JSON, отладка → Нода `Change`: установка, изменение, перемещение и удаление свойств `msg`

Нода `Change`: установка, изменение, перемещение и удаление свойств `msg`

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

Введение в ноду Change: Основной инструмент трансформации данных

Нода `Change` — один из самых фундаментальных и часто используемых узлов в палитре Node-RED. Её основное назначение — манипулирование объектом `msg` без необходимости написания кода на JavaScript. Она предоставляет декларативный интерфейс для выполнения простых и атомарных операций: установки, изменения, перемещения и удаления свойств сообщения. В экосистеме контроллера HI, где важны читаемость, надежность и скорость разработки, нода `Change` является ключевым инструментом для подготовки данных перед отправкой на исполнительные устройства или в системы верхнего уровня, такие как MQTT или MySQL.

> 💡 Подсказка: Для простых и атомарных операций с `msg` всегда отдавайте предпочтение ноде `Change` перед нодой `Function`. Это упрощает отладку, повышает производительность и делает логику потока (flow) очевидной даже для инженера, который не знаком с проектом.

Обзор интерфейса и операций

При двойном клике на ноду `Change` открывается её панель настроек, которая состоит из списка правил. Каждое правило выполняется последовательно, сверху вниз. Для каждого правила можно определить одну из четырех основных операций:

Преимущества перед нодой `Function`

Хотя нода `Function` предоставляет неограниченную гибкость благодаря JavaScript, для стандартных задач трансформации нода `Change` имеет ряд неоспоримых преимуществ.

| Критерий | Нода `Change` | Нода `Function` |

| ----------------- | ------------------------------------------------------------- | --------------------------------------------------------------- |

| Наглядность | Логика видна сразу в интерфейсе, без необходимости входа в код. | Требуется открытие редактора кода для понимания логики. |

| Производительность | Операции выполняются оптимизированным встроенным кодом Node-RED. | Каждый раз создается "песочница" для выполнения JS-кода, что несколько медленнее. |

| Простота | Не требует знаний программирования. Интуитивно понятный интерфейс. | Требует знания синтаксиса JavaScript и асинхронной модели Node.js. |

| Надежность | Меньше вероятность допустить синтаксическую или логическую ошибку. | Легко допустить ошибку (опечатку, null pointer), которая может остановить поток. |

Нода `Change` не заменяет, а дополняет другие узлы-трансформеры. Например, нода `Split` используется для разделения массива или строки на последовательность отдельных сообщений, а `Join` — для обратной операции. Нода `Change` же работает с целостной структурой одного `msg` объекта на каждом шаге потока.

---

Операция 'Set' (Установить): Создание и перезапись свойств

перация 'Set' (Установить): Создание и перезапись свойств

Операция `Set` — самая распространенная в ноде `Change`. Она используется для присвоения конкретного значения свойству объекта `msg`. Это может быть как `msg.payload`, так и любое другое свойство, например, `msg.topic`, `msg.qos` или кастомное поле `msg.audit`.

Установка различных типов данных

Панель настройки правила `Set` позволяет выбрать тип данных для устанавливаемого значения, что крайне важно для соблюдения "контракта сообщений".

Практический пример: Подготовка команды для DALI

Предположим, нам нужно отправить команду для установки яркости светильника в шину DALI. Нода `dali-out` ожидает на входе `msg.payload` в виде JSON-объекта. Исходное сообщение приходит от кнопки на панели управления и содержит лишь простую команду.

Исходное `msg` после ноды `Inject`:
{

"payload": "set_max_brightness",

"topic": "control_panel/button_1",

"_msgid": "a1b2c3d4.e5f6a7"

}

Задача: Преобразовать это сообщение в команду, понятную для DALI-драйвера, установив `msg.payload` в объект с параметрами адресации и значения. Конфигурация ноды `Change`:
  • Добавляем ноду `Change` после ноды `Inject`.
  • Создаем правило:
  • * `Set`: `msg.payload`

    * `to`: `JSON`

    * В текстовом поле вводим JSON-объект управления:

    {
    

    "address": 5,

    "addressType": 0,

    "command": "DAPC",

    "value": 254

    }

    Итоговое `msg` после ноды `Change`:
    {
    

    "payload": {

    "address": 5,

    "addressType": 0,

    "command": "DAPC",

    "value": 254

    },

    "topic": "control_panel/button_1",

    "_msgid": "a1b2c3d4.e5f6a7"

    }

    Теперь это сообщение может быть напрямую подано на вход ноды управления DALI. Аналогично, мы могли бы добавить еще одно правило `Set` для установки `msg.topic` в нужный нам формат, например `lighting/office/zone1/cmd`.

    Операция 'Change' (Изменить): Поиск и замена внутри свойства

    Операция `Change` (не путать с названием самой ноды) предназначена для внутренних модификаций строковых свойств. Она выполняет поиск указанной подстроки или паттерна и заменяет все найденные вхождения на новое значение. Это мощный инструмент для очистки и нормализации "сырых" данных, поступающих от внешних устройств.

    > ⚠️ Внимание: При использовании регулярных выражений будьте внимательны с экранированием специальных символов. Неправильный паттерн может привести к неожиданным результатам, ошибкам в потоке или, в худшем случае, к высокой нагрузке на CPU контроллера из-за "катастрофического возврата" (catastrophic backtracking). Всегда тестируйте свои RegEx на онлайн-валидаторах.

    Простая замена подстроки

    Самый простой сценарий — замена одной фиксированной строки на другую. Например, если текстовый датчик присылает состояние в виде "STATE=OPEN", а нам для дальнейшей обработки требуется только "OPEN".

    Настройка правила:

    Использование регулярных выражений (RegEx)

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

    Практический пример: Очистка данных с устройства по RS-485

    Многие простые устройства, работающие по ASCII-протоколам через RS-485, могут присылать данные, обрамленные служебными символами, например, символами перевода строки `\r\n`.

    Исходное `msg` от ноды `serial in`:
    {
    

    "payload": "T:23.5;H:45.1\r\n",

    "_msgid": "b2c3d4e5.f6a7b8"

    }

    Задача: Удалить из `msg.payload` все управляющие символы (`\r`, `\n`) и оставить только полезные данные. Конфигурация ноды `Change`:
  • Добавляем ноду `Change`.
  • Создаем правило:
  • * `Change`: `msg.payload`

    * `Search for`: `regex` `[\r\n]` (квадратные скобки означают "любой из символов внутри")

    * `Replace with`: `string` (оставить поле пустым)

    * В поле `in` выбираем `msg.payload`.

    Итоговое `msg` после ноды `Change`:
    {
    

    "payload": "T:23.5;H:45.1",

    "_msgid": "b2c3d4e5.f6a7b8"

    }

    Теперь `msg.payload` имеет чистый и предсказуемый формат, который можно легко разобрать на составные части с помощью нод `Split` или `Function`. Эта простая операция значительно повышает надежность всего потока, так как он становится нечувствительным к незначительным вариациям в формате входящих данных.

    ---

    Операции 'Move' (Переместить) и 'Delete' (Удалить): Оптимизация структуры `msg`

    По мере прохождения сообщения по потоку, объект `msg` может "обрастать" множеством служебных и промежуточных свойств. Это затрудняет отладку и может приводить к избыточной передаче данных. Операции `Move` и `Delete` служат для поддержания `msg` в чистоте и порядке.

    Правило `Move` (Переместить)

    Правило `Move` используется для переименования свойства. Оно берет значение из одного свойства и помещает его в другое, при этом исходное свойство удаляется.

    Пример: Протокольный узел (например, `knx-in`) вернул значение в `msg.payload.value`. Для ясности и соответствия нашему внутреннему стандарту мы хотим, чтобы это свойство называлось `msg.payload.temperature`. Исходное `msg`:
    {
    

    "payload": {

    "value": 24.5,

    "source": "1/1/1"

    },

    "_msgid": "c3d4e5f6.a7b8c9"

    }

    Конфигурация ноды `Change`: Итоговое `msg`:
    {
    

    "payload": {

    "temperature": 24.5,

    "source": "1/1/1"

    },

    "_msgid": "c3d4e5f6.a7b8c9"

    }

    Правило `Delete`(Удалить)

    Правило `Delete` — это гигиенический инструмент. Оно полностью удаляет указанное свойство из объекта `msg`. Это необходимо делать перед отправкой данных в системы, где важен минимальный размер сообщения (например, MQTT в сетях LoRaWAN) или перед записью в базу данных, чтобы не хранить ненужную информацию.

    Пример: После всех преобразований у нас в `msg` остались временные данные в свойстве `msg.temp_buffer`. Перед отправкой в MQTT нам нужно от них избавиться. Конфигурация ноды `Change`:

    Комбинация правил для комплексной трансформации

    Сила ноды `Change` раскрывается при использовании нескольких правил в одном узле. Они выполняются последовательно, что позволяет произвести сложную трансформацию за один шаг.

    Задача:
  • Переместить значение из `msg.data.sensorValue` в `msg.payload`.
  • Установить `msg.topic` в `hi/cottage/basement/humidity/state`.
  • Удалить исходный объект `msg.data`, так как он больше не нужен.
  • Конфигурация ноды `Change` (3 правила):
  • Правило 1 (Move): `Move` `msg.data.sensorValue` `to` `msg.payload`
  • Правило 2 (Set): `Set` `msg.topic` `to` `string` `hi/cottage/basement/humidity/state`
  • Правило 3 (Delete): `Delete` `msg.data`
  • Такой подход делает поток компактным и логически сгруппированным. Вся трансформация инкапсулирована в одном узле, который можно назвать "Подготовка данных влажности".

    ---

    Практический пример: Обработка ответа от Modbus RTU устройства

    Рассмотрим реальный сценарий на объекте. Контроллер HI опрашивает по шине RS-485 Modbus-счетчик электроэнергии. Нам нужно получить значение активной мощности, которое содержится в одном из регистров.

    Нода `modbus-read` возвращает сообщение, содержащее не только полезные данные, но и служебную информацию, например, буфер ответа.

    Исходное `msg` от ноды `modbus-read`:

    Предположим, нода `modbus-read` после успешного опроса вернула следующий объект. Значение мощности (например, `5200` Ватт) находится в `msg.payload`, а также есть избыточное поле `msg.responseBuffer`.

    {
    

    "payload": 5200,

    "topic": "ModbusPolling",

    "responseBuffer": {

    "data": [5200],

    "buffer": ""

    },

    "_msgid": "d4e5f6a7.b8c9d0"

    }

    > ℹ️ Информация: Структура `msg` от ноды `modbus-read` может отличаться в зависимости от её настроек. В данном примере мы рассматриваем распространенный случай, когда `payload` уже содержит готовое число.

    Задача:
  • Преобразовать этот технический ответ в сообщение, соответствующее "контракту" нашей системы.
  • Присвоить сообщению осмысленный `topic` по стандарту `проект/место/устройство/параметр`.
  • "Очистить" сообщение от всех ненужных служебных полей (`responseBuffer`, `topic`).
  • Целевое `msg` для отправки в MQTT:
    {
    

    "payload": {

    "value": 5200,

    "unit": "W",

    "source": "energymeter-main-01",

    "ts": 1678890000000

    },

    "topic": "hi/office/main-panel/energymeter-01/active-power/state",

    "_msgid": "d4e5f6a7.b8c9d0"

    }

    Для решения этой задачи в один шаг мы используем ноду `Change` с несколькими правилами.

    Конфигурация ноды `Change`:
  • Правило 1 (Move): Перемещаем значение мощности в новый `payload`
  • * `Move`: `msg.payload`

    * `to`: `msg.payload.value`

    (Это правило магическим образом создаст объект `msg.payload` и поместит туда ключ `value`)

  • Правило 2 (Set): Добавляем единицу измерения
  • * `Set`: `msg.payload.unit`

    * `to`: `string` `W`

  • Правило 3 (Set): Добавляем источник данных
  • * `Set`: `msg.payload.source`

    * `to`: `string` `energymeter-main-01`

  • Правило 4 (Set): Добавляем временную метку
  • * `Set`: `msg.payload.ts`

    * `to`: `timestamp`

  • Правило 5 (Set): Устанавливаем правильный `topic`
  • * `Set`: `msg.topic`

    * `to`: `string` `hi/office/main-panel/energymeter-01/active-power/state`

  • Правило 6 (Delete): Удаляем служебный буфер
  • * `Delete`: `msg.responseBuffer`

    Последовательное применение этих шести правил в одной ноде `Change` полностью преобразует "сырое" сообщение от Modbus-устройства в стандартизированное сообщение, готовое к публикации в MQTT и дальнейшей обработке другими подсистемами.

    ---

    Итоги и лучшие практики

    В этом уроке мы детально рассмотрели ноду `Change` — основной декларативный инструмент для манипуляции данными в Node-RED. Вы научились использовать ее четыре ключевые операции для приведения объекта `msg` к требуемой структуре.

    > 🔗 Связанный материал: Для запуска потоков и тестирования правил в этом уроке используйте ноду `Inject` для генерации исходных сообщений, как было рассмотрено в уроке `COURSE-06-M03-L01`.

    Ключевые выводы:

    Соблюдение этих практик позволит вам создавать потоки, которые не только работают, но и легко поддерживаются и масштабируются.

    Что дальше

    Мы освоили базовые операции ноды `Change`. Однако её возможности гораздо шире. В следующем уроке мы расширим возможности этого узла, изучив мощный язык запросов JSONata, который позволяет выполнять сложнейшие преобразования, вычисления и форматирование данных прямо внутри правил ноды `Change`. Это откроет новые горизонты для обработки даже самых сложных структур данных без единой строчки JavaScript-кода.