Главная → Академия → Node-RED: установка, flows, msg/JSON, отладка → Стандарты именования нод, потоков и переменных

Стандарты именования нод, потоков и переменных

Введение в стандарты именования: Зачем это нужно?

ведение в стандарты именования: Зачем это нужно?

На начальном этапе работы с Node-RED, когда проект состоит из одного-двух потоков, вопрос именования кажется второстепенным. Логика проста, все узлы на виду, и кажется, что имена вроде `function 1`, `debug 5` или `MQTT-вход` вполне достаточны. Однако такой подход является прямой дорогой к созданию так называемого "спагетти-кода" — запутанной, нечитаемой и практически неподдерживаемой системы. По мере роста проекта с десятков узлов до сотен и тысяч, хаос в именах приводит к катастрофическим последствиям.

Стандартизация именования — это не бюрократия, а ключевая инженерная дисциплина, которая напрямую влияет на жизненный цикл проекта автоматизации. Это формальное соглашение о том, как мы называем все сущности в проекте: потоки (flows), узлы (nodes), переменные и даже поля в сообщениях.

> 💡 Подсказка: Думайте о своем проекте через год. Сможете ли вы или ваш коллега быстро разобраться в логике, если имена хаотичны? Правильное именование — это инвестиция в будущее вашего проекта и здравомыслия вашей команды.

Рассмотрим ключевые преимущества внедрения стандартов именования:

  • Масштабируемость и читаемость проекта. Когда ваш проект умного дома разрастается с одной комнаты до целого коттеджа с несколькими инженерными системами (освещение, климат, безопасность, мультимедиа), только строгая и предсказуемая система имен позволит вам ориентироваться в сотнях узлов. Имя `CLIMATE-FF-BEDROOM` мгновенно сообщает, что этот поток управляет климатом в спальне на втором этаже, в то время как имя `Моя спальня` не несет никакой системной информации.
  • Упрощение командной работы и передачи проекта. В профессиональной среде проекты редко делаются одним человеком от начала и до конца. Инженер-инсталлятор передает объект инженеру по автоматизации, а тот, в свою очередь, может передать его на поддержку сервисной службе. Общий стандарт позволяет любому члену команды быстро войти в курс дела, понять логику работы системы и вносить изменения без риска что-то сломать.
  • Снижение времени на отладку. Представьте, что в системе произошел сбой. Вы открываете лог ошибок и видите сообщение: `Error from node: a1b2c3d4.5e6f78`. Это ID узла, который вам ни о чем не говорит. Вам придется искать его по всему проекту. А теперь представьте, что ошибка пришла от узла с именем `Гостиная: Датчик протечки: Валидация данных`. Вы мгновенно понимаете, где именно и на каком этапе произошла проблема. Время на диагностику сокращается с часов до минут.
  • Долгосрочная поддержка и модернизация. Через два года заказчик просит добавить управление теплыми полами в ванной. Если ваш проект структурирован, вы легко найдете поток `CLIMATE-GF-BATHROOM`, добавите нужную логику и не затронете другие системы. В хаотичном проекте вы рискуете, внося изменения в одном месте, непреднамеренно сломать логику работы освещения в гараже, потому что где-то между ними была неочевидная связь.

Стандарты именования — это фундамент, на котором строится профессиональный, надежный и легко сопровождаемый проект автоматизации на платформе HI.

Стандарт именования потоков (Flows): от систем к зонам

Потоки, или вкладки (Tabs) в редакторе Node-RED, являются первым и самым крупным уровнем организации проекта. Правильная структура имен потоков позволяет с одного взгляда оценить архитектуру всей системы. Мы будем использовать иерархический подход, который группирует логику по инженерным системам и физическому расположению.

Формула именования потока: `СИСТЕМА-ЗОНА-ФУНКЦИЯ`

> ⚠️ Внимание: Избегайте использования пробелов, кириллицы и специальных символов (кроме `-` и `_`) в именах потоков. Это может привести к проблемам при экспорте/импорте, работе с файловой системой контроллера HI (где контекст потока может сохраняться в файл с именем потока) и в системах контроля версий (Git). Используйте только латиницу, цифры и дефис в качестве разделителя.

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

1. СИСТЕМА (System)

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

📋 Ключевые понятия: Стандартные префиксы систем

| Префикс | Описание |

| :----------- | :------------------------------------------------------------------------------------------------------ |

| `LIGHT` | Управление освещением: группы света, диммирование, сценарии. |

| `CLIMATE` | Управление климатом: отопление, кондиционирование, вентиляция, теплые полы. |

| `SECURITY` | Системы безопасности: датчики движения, открытия, контроль доступа, охранные сценарии. |

| `POWER` | Управление электропитанием и энергомониторинг: розетки, учет электроэнергии. |

| `WATER` | Управление водоснабжением: контроль протечек, управление клапанами, полив. |

| `SHUTTERS` | Управление шторами, жалюзи, роллетами. |

| `GATEWAYS` | Шлюзы и интеграции: логика взаимодействия с внешними системами (Modbus, MQTT, DALI, KNX). |

| `LOGIC` | Общая, межсистемная логика: сценарии "Я ушел", "Ночь", глобальные таймеры. |

| `SYSTEM` | Внутренние системные потоки: мониторинг состояния контроллера, обработка ошибок, резервное копирование. |

2. ЗОНА (Zone)

Этот компонент указывает на физическое расположение или зону ответственности потока. Это может быть этаж, комната или специфическая область.

  • Для этажей: `GF` (Ground Floor), `FF` (First Floor), `SF` (Second Floor), `B` (Basement).
  • Для помещений: `LIVINGROOM`, `KITCHEN`, `BEDROOM-MASTER`, `CORRIDOR`, `GARAGE`.
  • Для общих зон: `FACADE`, `PERIMETER`, `YARD`.

3. ФУНКЦИЯ (Function)

Необязательный, но полезный компонент, уточняющий конкретное назначение потока, если в одной зоне есть несколько потоков для одной системы.

Примеры хороших имен потоков:
  • `LIGHT-FF-LIVINGROOM` — все, что связано с освещением в гостиной на втором этаже.
  • `CLIMATE-GF-KITCHEN` — управление радиатором и теплым полом на кухне на первом этаже.
  • `SECURITY-PERIMETER` — логика датчиков движения и открытия по периметру дома.
  • `GATEWAYS-MODBUS-RTU` — единый поток для опроса всех устройств на шине Modbus RTU.
  • `SYSTEM-ERROR-HANDLER` — централизованный поток для сбора и обработки ошибок со всего проекта.

Такой подход превращает набор вкладок в осмысленное, самодокументируемое оглавление вашего проекта.

---

Именование узлов (Nodes): Принцип "Что делает?"

Если потоки — это главы книги, то узлы — это предложения. Имя каждого узла должно кратко, но точно описывать его роль в потоке. Общее правило — имя должно отвечать на вопрос "Что этот узел делает?". Используйте простую и последовательную формулу.

Формула именования: `[Локация/Зона] [Устройство/Сущность] [Действие/Данные]`

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

Именование по типам узлов

Узлы `Inject` и `Debug`

Это ваши главные инструменты для тестирования и отладки. Их имена должны быть максимально информативными.

| Плохо | Хорошо | Пояснение |

| :------------ | :-------------------------------------------- | :----------------------------------------------------------------------------- |

| `timestamp` | `Эмуляция: Кнопка коридор (ON)` | Ясно, что узел имитирует нажатие настенного выключателя. |

| `Inject` | `Тест: Запустить сценарий "Вечер"` | Понятно, какой сценарий будет запущен для тестирования. |

| `debug 1` | `Отладка: Payload от датчика температуры` | Сразу видно, какие данные выводятся в боковую панель. |

| `msg.payload` | `DEBUG: Итоговая команда на Modbus-устройство` | Позволяет отследить финальное сообщение, уходящее на исполнительное устройство. |

Узел `Function`

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

  • `Проверить время суток (день/ночь)`
  • `Форматировать данные для MQTT брокера`
  • `Рассчитать среднее значение за 5 мин`
  • `Валидация: Температура котла в норме?`
  • `Создать JSON для API погоды`

Узлы коммуникаций (`MQTT`, `Modbus`, `HTTP Request`)

Для этих узлов критически важно указать, с какой внешней сущностью они взаимодействуют.

  • MQTT: `MQTT In: tele/sensors/th-livingroom/SENSOR` — указывает на топик, который узел слушает.
  • Modbus: `Modbus Getter: Счетчик ЭЭ HR-30001 (Энергия)` — указывает на устройство, регистр и тип данных. HR означает Holding Register.
  • HTTP Request: `GET: API Погоды (OpenWeatherMap)`
  • TCP Out: `Отправить команду на проектор (PJLink)`

Пример из практики

Рассмотрим поток управления светом.

[Inject] "Эмуляция: Настенная кнопка Вкл"

|

V

[Function] "Инвертировать состояние света"

|

V

[Change] "Сформировать команду ON/OFF"

|

V

[MQTT Out] "cmnd/light-livingroom-main/POWER"

|

V

[Debug] "Отладка: Итоговая команда в MQTT"

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

---

Переменные в контексте (Flow, Global): camelCase и префиксы

еременные в контексте (Flow, Global): camelCase и префиксы

Контекстные переменные (`flow` и `global`) — это "память" вашей системы автоматизации. Они хранят состояния (свет включен/выключен), уставки (желаемая температура), идентификаторы таймеров и многое другое. Хаос в именах переменных так же опасен, как и в именах узлов.

> 🔗 Связанный материал: Подробно работа с переменными контекста для хранения состояний рассматривается в уроке COURSE-06-M04-L02: Контекст в Node-RED.

Ключевые принципы именования переменных:

1. Выбор и соблюдение единого стиля

Существуют два популярных стиля именования переменных:

  • camelCase: слова пишутся слитно, при этом каждое слово, кроме первого, начинается с заглавной буквы (например, `livingRoomLightState`). Это доминирующий стиль в JavaScript, языке Node-RED, поэтому он является рекомендуемым для использования на платформе HI.
  • snake_case: слова разделяются символом подчеркивания (например, `living_room_light_state`).

Самое главное — выбрать один стиль и строго придерживаться его во всем проекте. Смешение стилей (`isLight_On`) затрудняет чтение и поиск переменных.

2. Использование префиксов

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

| Префикс | Назначение | Пример |

| :------------ | :------------------------------------------- | :---------------------------------------- |

| `is` / `has` | Булево значение (флаг состояния) | `isNightModeActive`, `hasAlarmTriggered` |

| `state` | Состояние конечного автомата (FSM) | `stateHeatingSystem`, `stateWateringZone` |

| `cfg` | Конфигурационное значение, уставка | `cfgRoomTemperatureSetpoint`, `cfgTimerDuration` |

| `modbus` | Данные, полученные по протоколу Modbus | `modbusBoilerPressure`, `modbusEnergyCounter` |

| `mqtt` | Данные, полученные из MQTT | `mqttOutdoorTemperature` |

| `timer` | Идентификатор таймера (от `setTimeout`) | `timerDelayedLightOff` |

| `last` | Последнее известное значение или время | `lastMotionTimestamp`, `lastSensorValue` |

3. Валидация структуры msg перед записью

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

Пример валидации через узел Switch:

Для проверки наличия обязательного свойства (например, `msg.payload.temperature`) используйте узел Switch с правилом «is not null» или «property exists».

Пример логики валидации в Function (JSON-like check):
// Проверяем наличие свойств перед работой с ними

if (msg.payload && typeof msg.payload.value === 'number') {

const sensorValue = msg.payload.value;

flow.set('mqtt_livingRoomSensorValue', sensorValue);

return msg;

} else {

node.error("Invalid msg structure: expected payload.value as number");

return null; // Прерываем поток, если данные некорректны

}

4. Отказ от общих имен

Никогда не используйте короткие, неоднозначные имена, такие как `temp`, `status`, `data`, `val`. Через неделю вы не вспомните, что они означают.

  • Вместо `temp` -> `boilerWaterInletTemperature`
  • Вместо `status` -> `securitySystemArmStatus`
  • Вместо `data` -> `weatherApiForecastObject`

Практический пример в узле `Function`

Сравните два подхода к сохранению давления в котле, полученного по Modbus.

Плохой подход:
// Где-то в коде мы получили 'val' = 2.1

flow.set('press', val);

Хороший, стандартизированный подход:
// msg.payload содержит значение от Modbus-узла

const pressureValue = msg.payload / 10; // Например, данные приходят в bar * 10

// Используем префикс, camelCase и описательное имя

flow.set('modbus_boilerPressure', pressureValue);

node.status({fill:"green", shape:"dot", text:"Давление: " + pressureValue + " бар"});

Во втором случае имя переменной `modbus_boilerPressure` само себя документирует: мы знаем, что это давление (`Pressure`), оно относится к котлу (`boiler`), и данные пришли по Modbus-шине (`modbus_`).

Стандартизация структуры msg: от простого к сложному

тандартизация структуры msg: от простого к сложному

Объект `msg` — это кровь системы Node-RED. Он переносит данные и команды между узлами. Очень часто новички используют только `msg.payload`, помещая туда простые значения, например `true`, `false`, `25.5` или `"ON"`. Это работает для простых задач, но создает серьезные проблемы в сложных системах.

Профессиональный подход — использование структурированных JSON-объектов внутри `msg`. Это соответствует паттерну "Контракт сообщения", который является одним из столпов надежного проектирования в Node-RED.

От примитивов к объектам

Давайте рассмотрим эволюцию сообщения для управления светом.

Уровень 1: Примитив в `msg.payload`
// Команда на включение света

msg.payload = true;

  • Проблема: Как передать яркость? Или цветовую температуру? Придется использовать другие свойства `msg`, например, `msg.brightness = 100`, что приводит к "размазыванию" данных по всему объекту `msg` и усложняет отладку.
Уровень 2: Объект в `msg.payload`

Перейдем к использованию JSON-объекта.

{

"status": true,

"brightness": 100,

"color_temp": 3500

}

  • Преимущество: Вся информация об управлении светильником инкапсулирована в одном месте — `msg.payload`. Логика становится проще, а сообщение — информативнее.

Обязательные поля для стандартного сообщения

Чтобы сделать систему по-настоящему надежной и легко отлаживаемой, рекомендуется обогащать объект `msg` дополнительными стандартными полями.

| Поле | Расположение | Назначение | Пример |

| :------------ | :---------------- | :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------ |

| topic | `msg.topic` | Маршрутизация. Используется узлом `Switch` для направления сообщения в нужную ветку логики. Должен быть семантически понятным. | `commands/light/set` или `telemetry/sensors/temp` |

| source | `msg.payload.source` | Отладка. Уникальный идентификатор источника сообщения (ID датчика, кнопки, сценария). Помогает понять, что инициировало поток. | `wall-switch-livingroom-1` или `ds18b20-boiler-inlet` |

| timestamp | `msg.payload.ts` | Актуальность. Временная метка в формате Unix epoch (ms), когда событие произошло. Позволяет отсеивать устаревшие данные. | `1678886400000` |

| value | `msg.payload.value` | Основное значение. Данные с датчика или команда. | `23.5` или `true` |

Пример "плохого" сообщения от датчика температуры:
msg.topic = "temp";

msg.payload = 23.5;

Пример "хорошего", стандартизированного сообщения (согласно "Контракту сообщения"):
msg.topic = "telemetry/temperature/livingroom";

msg.payload = {

"value": 23.5,

"unit": "°C",

"source": "1w-28-01234567abcd", // ID датчика 1-Wire

"ts": 1678886500000

};

Валидация контракта сообщения

Чтобы поток не "упал" при получении некорректных данных, необходимо проверять структуру `msg.payload`. В Node-RED это реализуется через узел Switch.

Пример реализации Flow-валидатора:

Мы ожидаем объект, в котором обязательно есть поле `value` (число больше 0) и `source`.

  • Узел Switch (Check Contract):
  • * Правило 1: `msg.payload.value` — is type `number`.

    * Правило 2: `msg.payload.source` — is not empty.

    * Настройка: "stopping after first match" (прекратить после первого совпадения) ИЛИ "send to all matches" в зависимости от строгости.

  • Узел Change (Error Handling): Если данные не прошли проверку (выход `otherwise`), формируем сообщение об ошибке для логов.
  • // Пример проверки через Function узел (если логика сложнее Switch)
    

    if (typeof msg.payload.value !== 'number' || !msg.payload.source) {

    node.error("Invalid msg contract: missing value or source", msg);

    return null; // Прерываем поток

    }

    return msg;

    > 💡 Совет: Стандартизация `msg` позволяет создавать универсальные Flow. Например, один и тот же обработчик графиков (UI Chart) сможет работать с любыми датчиками, если они все присылают данные в поле `msg.payload.value`.

    Сводка правил и чек-лист для самопроверки

    Следование стандартам требует дисциплины. Используйте этот чек-лист для регулярной проверки своих проектов Node-RED, чтобы убедиться, что они соответствуют профессиональным практикам, принятым в нашей академии.

    Чек-лист именования потоков (Flows)

    • [ ] Имена потоков написаны латиницей, без пробелов и спецсимволов (кроме `-`).
    • [ ] Используется иерархическая структура `СИСТЕМА-ЗОНА-ФУНКЦИЯ`.
    • [ ] Используются стандартные префиксы систем (`LIGHT`, `CLIMATE`, `SECURITY` и т.д.).
    • [ ] Системные и общие потоки (`GATEWAYS`, `SYSTEM`) вынесены отдельно.

    Чек-лист именования узлов (Nodes)

    • [ ] Имя каждого узла отвечает на вопрос "Что он делает?".
    • [ ] Для узлов `Inject` и `Debug` указано, что именно они эмулируют или отлаживают.
    • [ ] Имена узлов `Function` кратко описывают выполняемую ими логику.
    • [ ] Имена узлов коммуникаций (`MQTT`, `Modbus` и др.) содержат адрес/топик/эндпоинт.

    Чек-лист именования переменных контекста (Flow/Global)

    • [ ] Во всем проекте используется единый стиль именования (`camelCase` или `snake_case`).
    • [ ] Используются префиксы для указания типа или источника данных (`is...`, `cfg...`, `modbus...`).
    • [ ] Отсутствуют общие, ничего не значащие имена (`temp`, `data`, `status`).
    • [ ] Имена переменных являются описательными и понятны без дополнительного контекста.

    Чек-лист стандартизации структуры `msg`

    • [ ] `msg.payload` содержит структурированный JSON-объект вместо примитивных типов (чисел, строк).
    • [ ] В `msg.topic` передается информация для маршрутизации сообщения.
    • [ ] В `msg.payload` присутствует поле `source` для идентификации источника события.
    • [ ] В `msg.payload` передается временная метка `ts` (timestamp).

    Что дальше

    В этом уроке мы заложили основу для создания чистых, читаемых и поддерживаемых проектов. Мы научились стандартизировать имена для всех ключевых сущностей в Node-RED. В следующем уроке мы перейдем к еще более мощному инструменту организации кода: COURSE-06-M06-L02: Субпотоки (Subflows) и их применение для переиспользования логики. Мы узнаем, как создавать свои собственные узлы для повторяющихся задач, что позволит кардинально уменьшить дублирование кода и повысить надежность системы.