ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Расширение контракта сообщения для аналоговых данных (value, unit)

Расширение контракта сообщения для аналоговых данных (value, unit)

Урок 5 · Датчики и входы: нормализация сигналов · 30 мин · theory

Введение: от простых значений к структурированным данным

На предыдущих этапах обучения мы рассматривали, как получать сырые данные с аналоговых входов контроллера, будь то напрямую с АЦП или через протокол Modbus, и как преобразовывать их в осмысленные физические величины с помощью масштабирования, например, используя узел `Range`. В результате этих операций мы получали в объекте `msg` простое числовое значение, например, `msg.payload = 23.5`. На первый взгляд, это кажется достаточным. Но по мере усложнения системы автоматизации такой подход становится источником серьезных проблем и ошибок.

Представьте себе систему, управляющую климатом в офисном здании. В логах отладки вы видите поток сообщений со значением `23`. Что это?

Без дополнительного контекста, который приходится держать в уме или искать в документации, это число лишено смысла. Инженер, который не создавал этот поток, потратит драгоценное время на выяснение его происхождения и назначения. При отладке системы в реальном времени такая неопределенность недопустима.

Для решения этой фундаментальной проблемы вводится понятие контракта сообщения (Message Contract). Это формальное соглашение внутри проекта о структуре и формате данных, передаваемых между узлами в Node-RED. Вместо того чтобы передавать "голые" данные, мы упаковываем их в само-документируемый объект.

> 📋 Ключевые понятия:

> * Контракт сообщения: Набор правил, описывающих структуру объекта `msg`, в частности `msg.payload`, для обеспечения предсказуемого и стандартизированного обмена данными между компонентами системы.

> * Само-документируемые данные: Данные, которые содержат в себе не только значение, но и метаинформацию, описывающую это значение (например, единицы измерения, источник, временную метку).

Преимущества использования структурированных, само-документируемых данных очевидны:

  • Однозначность: Любой, кто видит сообщение, немедленно понимает, что оно означает. `{"value": 23.5, "unit": "°C"}` не оставляет пространства для догадок.
  • Повышение читаемости потоков: Логика потоков становится прозрачной, так как вам не нужно кликать на каждый узел, чтобы понять, какой тип данных он обрабатывает.
  • Упрощение отладки: При просмотре логов в узле `Debug` вы сразу получаете полную картину, что кардинально ускоряет поиск неисправностей.
  • Снижение вероятности ошибок: Узел, ожидающий температуру, может легко отличить ее от влажности, проверив дополнительное поле, что предотвращает неверные логические срабатывания.
  • В этом уроке мы сделаем решительный шаг от передачи простых числовых значений к работе со структурированными объектами, внедрив базовый, но чрезвычайно мощный контракт сообщения для всех аналоговых данных.

    ---

    Стандартный контракт для аналоговых данных: объект { value, unit }

    Для всех аналоговых и физических величин, циркулирующих в системе автоматизации на платформе HI, Академия устанавливает единый стандартный контракт сообщения. Полезная нагрузка (`msg.payload`) должна представлять собой JSON-объект, содержащий как минимум два ключевых поля: `value` и `unit`.

    `msg.payload = { "value": , "unit": "" }`

    Разберем компоненты этой структуры:

    `msg.payload` больше не является просто числом. Теперь это объект, который несет в себе полный контекст измеряемой величины.

    Примеры для типовых датчиков

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

    | Тип датчика / Измеряемая величина | Пример `msg.payload` | Поле `value` | Поле `unit` |

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

    | Датчик температуры (NTC, DS18B20) | `{ "value": 24.8, "unit": "°C" }` | Температура, градусы Цельсия | `°C` |

    | Датчик относительной влажности | `{ "value": 52, "unit": "%" }` | Относительная влажность, проценты | `%` |

    | Датчик освещенности | `{ "value": 850, "unit": "lux" }` | Освещенность, люксы | `lux` |

    | Датчик давления воды/воздуха | `{ "value": 3.1, "unit": "bar" }` | Давление, бары | `bar` |

    | Датчик качества воздуха (CO2) | `{ "value": 620, "unit": "ppm" }` | Концентрация CO2, частей на миллион | `ppm` |

    | Аналоговый вход 0-10В (в режиме UI)| `{ "value": 7.5, "unit": "V" }` | Напряжение на входе, вольты | `V` |

    | Счетчики (импульсные, Modbus) | `{ "value": 1543.2, "unit": "kWh" }` | Потребленная энергия, киловатт-часы | `kWh` |

    Универсальность и расширяемость

    Этот, на первый взгляд, простой формат обладает огромной гибкостью.

  • Универсальность: Он подходит для описания практически любой физической величины, с которой вы столкнетесь в проектах автоматизации зданий и промышленных объектов.
  • Расширяемость: В будущем, для более сложных сценариев (уровень Integration и Architect), этот контракт легко расширяется дополнительными полями без нарушения обратной совместимости. Например, как мы уже упоминали в скилле по паттернам Node-RED, можно добавить `source` и `ts`:
  • {
    

    "value": 24.8,

    "unit": "°C",

    "source": "temp-sensor-office-101",

    "ts": 1678886400000

    }

    Однако для уровня Installer и для большинства повседневных задач автоматизации базовой структуры `{ value, unit }` абсолютно достаточно. Внедрение этого стандарта — это первый и самый важный шаг к построению надежных и профессиональных систем.

    ---

    Практика: формирование объекта с помощью ноды Change

    Теория важна, но теперь давайте применим ее на практике. Наша задача — преобразовать `msg.payload`, содержащий простое числовое значение, в стандартизированный объект `{ value, unit }`. Самый эффективный и рекомендуемый способ сделать это в Node-RED — использовать стандартный узел `Change`.

    Рассмотрим полный путь прохождения сигнала. Представим, что мы считываем данные с Modbus-датчика температуры, который отдает значение, умноженное на 10.

  • `Modbus-Getter`: Считывает регистр, `msg.payload` становится `{ data: [255], ... }`.
  • `Function`: Извлекает значение и делит на 10. `msg.payload` становится `25.5`. (Этот шаг можно совместить со следующим, но для ясности разделим).
  • `Change`: (Наш фокус) Преобразует `25.5` в `{ "value": 25.5, "unit": "°C" }`.
  • `Debug`: Показывает итоговый структурированный объект.
  • Настройка узла `Change`

    Узел `Change` — это мощный инструмент, который позволяет модифицировать объект `msg` без написания кода в узле `Function`. Для нашей задачи мы будем использовать его способность устанавливать новое значение `msg.payload` с помощью JSONata — языка запросов и преобразований для JSON.

    Пошаговая инструкция:
  • Перетащите узел `Change` на поле и соедините его с выходом узла, который выдает числовое значение (например, `Range` или `Function` после обработки сырых данных).
  • Откройте диалог настройки узла `Change`.
  • В поле "Rules" (Правила) выберите:
  • * Set (`Установить`)

    * `msg.` payload

    * to the value (`в значение`)

    * `J:` (expression / JSONata)

  • В поле для выражения JSONata введите следующую строку:
  • { "value": payload, "unit": "°C" }
    
  • Нажмите "Done" и разверните проект.
  • Что здесь происходит?

    Теперь давайте посмотрим на наглядный пример до и после.

    Вход узла `Change`:

    `msg.payload` имеет тип `Number`

    25.5
    
    Выход узла `Change`:

    `msg.payload` стал типом `Object`

    {
    

    "value": 25.5,

    "unit": "°C"

    }

    > 💡 Подсказка: JSONata — это мощный инструмент, встроенный в Node-RED. Он позволяет выполнять не только простые преобразования, как в нашем примере, но и сложные вычисления, условные выражения, форматирование строк и многое другое прямо в узле `Change`. Инвестирование времени в изучение основ JSONata окупится многократно, так как позволит вам создавать более лаконичные и эффективные потоки, избегая лишних узлов `Function`.

    Этот метод является предпочтительным, поскольку он визуально понятен (на иконке узла `Change` видно, что происходит преобразование) и не требует написания JavaScript-кода, что снижает порог вхождения и вероятность синтаксических ошибок.

    ---

    Обработка структурированных данных: примеры использования

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

    Логика ветвления с помощью узла `Switch`

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

    Настроим узел `Switch` для маршрутизации:

  • Установите поле `Property` в `msg.payload.unit`.
  • Добавьте правила:
  • * `==` (string) `°C` -> выход 1 (логика для температуры, например, управление климатом)

    * `==` (string) `%` -> выход 2 (логика для влажности, например, управление вентиляцией или увлажнителем)

    * `==` (string) `ppm` -> выход 3 (логика для CO2, например, включение проветривания)

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

    Отображение в Dashboard

    Многие виджеты `node-red-dashboard` (например, `Gauge`, `Chart`, `Text`) прекрасно работают со структурированными данными.

    * Value format: `{{msg.payload.value | number:1}}` (отобразить значение с 1 знаком после запятой).

    * Units: `{{msg.payload.unit}}` (подставить единицу измерения из сообщения).

    В результате у вас получится информативный виджет, который автоматически подписывает отображаемое значение правильной единицей измерения. Если вы отправите на тот же виджет сообщение о влажности, он корректно отобразит `52 %`.

    Валидация данных

    > ⚠️ Внимание: Всегда валидируйте входящие данные на соответствие контракту. Поток, приходящий из другого модуля или от другого инженера, может не соответствовать ожиданиям. Отсутствие поля `unit` или некорректный тип `value` (например, строка вместо числа) может привести к ошибкам в нижестоящих узлах, которые будет сложно отследить.

    Простейший способ валидации — использовать узел `Switch`:

  • Установите `Property` в `msg.payload`.
  • Добавьте правило с проверкой типа: `is a` `Object`.
  • Добавьте правило "has property" для `value` и `unit`: `has property` `value` и еще одно `has property` `unit`.
  • Сообщения, не прошедшие проверку, можно направить на отдельный выход, который ведет к узлу `Catch` или специальному логгеру, сигнализируя о нарушении контракта.

    Подготовка данных для записи в базу данных

    Структура `{ value, unit }` идеально подходит для записи в современные базы данных временных рядов (Time-Series Databases), такие как InfluxDB или Prometheus, которые часто используются для мониторинга на платформе HI.

    При формировании запроса на запись:

    Использование `unit` в качестве тега позволяет выполнять очень эффективные запросы к базе данных, например: "покажи мне среднее значение всех метрик, где `unit` равно `°C`", что незаменимо при создании сложных дашбордов и аналитических отчетов.

    ---

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

    В этом уроке мы совершили качественный переход от работы с примитивными числовыми данными к использованию осмысленных, структурированных объектов. Мы проследили весь путь сигнала: от его получения с датчика, через масштабирование, и до финального преобразования в стандартизированный формат с помощью узла `Change`.

    Давайте закрепим ключевые моменты:

    С сегодняшнего дня использование структурированного `payload` является обязательным стандартом для всех проектов, разрабатываемых в рамках экосистемы HI. Этот подход обеспечивает:

    Что дальше?

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