Отладка в Node-RED: узлы Debug, Catch, Status
Введение в инструменты отладки Node-RED
> 🔗 Связанный материал: Данный урок посвящен отладке в реальном времени. Вопросы долгосрочного хранения и анализа событий (журналирование) мы подробно рассмотрим в Модуле 8, начиная с урока COURSE-07-M08-L01 "Зачем нужен журнал событий? (Audit Trail)".
Эффективная отладка — это ключевой навык инженера по автоматизации, позволяющий быстро находить и устранять проблемы в логике сценариев. В экосистеме Node-RED на контроллерах HI этот процесс строится на трех фундаментальных инструментах: узлах Debug, Catch и Status. Понимание их различий и областей применения критически важно для создания надежных и легко обслуживаемых систем.
Важно проводить четкую грань между отладкой (debugging) и журналированием (logging).
Отладка — это процесс интерактивного исследования потока данных и состояний во время разработки или пусконаладки. Ее цель — понять, почему* система ведет себя определенным образом в данный момент. Инструменты отладки обычно отключаются в производственной среде (продакшене), чтобы не создавать лишнюю нагрузку. Журналирование, которое мы рассмотрим позже, — это систематическая* запись ключевых событий, ошибок и состояний в долгосрочное хранилище (например, в базу данных MySQL на контроллере или во внешний MQTT-брокер). Журнал необходим для анализа работы системы в ретроспективе, выявления трендов и расследования инцидентов.Тремя китами отладки в Node-RED являются:
Многие начинающие разработчики используют `console.log()` внутри узлов `Function` для отладки. Хотя это технически возможно, такой подход имеет существенные недостатки:
- Скрытый вывод: Сообщения выводятся в системную консоль контроллера HI, доступ к которой требует SSH-подключения. Это неудобно по сравнению с интегрированной панелью отладки в веб-интерфейсе Node-RED.
- Отсутствие интеграции: Вы не можете легко отфильтровать сообщения, скопировать пути к данным или увидеть, какой именно узел сгенерировал сообщение.
- Сложность управления: Чтобы отключить такой вывод в продакшене, необходимо вручную редактировать код всех узлов `Function`. Узлы `Debug` можно отключить одним кликом.
Инструменты отладки должны быть неотъемлемой частью процесса разработки на контроллерах HI. Они используются на этапе создания сценария, при тестировании на стенде, во время пусконаладочных работ на объекте и при диагностике нештатного поведения уже работающей системы.
---
Глубокое погружение в узел Debug
> 💡 Подсказка: Для отладки сложных объектов, измените вывод узла Debug на 'complete msg object'. Это позволит увидеть не только `payload`, но и все служебные свойства, например, `_msgid` или данные, добавленные предыдущими узлами, что критично для понимания логики State Machine или Priority Gate.
Узел `Debug` — это ваш цифровой мультиметр для потоков Node-RED. Он позволяет измерить "напряжение" (данные) на любом "проводе" (соединении) в вашей схеме.Конфигурация узла
Узел имеет гибкие настройки вывода:
Вывод может быть направлен в несколько мест:
- Панель отладки (debug window): Стандартное место, видимое в правой боковой панели редактора Node-RED.
- Системная консоль: Дублирует вывод в консоль операционной системы контроллера. Полезно для отладки проблем, приводящих к падению самого Node-RED.
- Файл: Может записывать отладочные сообщения в файл на файловой системе контроллера. Используйте с осторожностью, чтобы не переполнить диск.
Функция "Copy Path"
Одна из самых мощных возможностей панели отладки — это "Copy Path". Когда вы разворачиваете объект `msg` в панели, рядом с каждым свойством появляется иконка для копирования. Это позволяет скопировать полный путь к свойству (например, `payload.data[0].value`) в буфер обмена. Затем этот путь можно вставить в другие узлы (`Switch`, `Change`, `Function`) для быстрого и безошибочного доступа к нужным данным.
Практический пример: инспекция ответа от Modbus-устройства
Представим, что мы опрашиваем модуль ввода/вывода по Modbus RTU (RS-485). Мы хотим прочитать два Holding регистра, начиная с адреса 100.
Поток:[Inject] ---> [Modbus-Read] ---> [Debug]
Настройка `Modbus-Read`:
- Slave ID: `5`
- Function Code: `FC 3: Read Holding Registers`
- Address: `100`
- Quantity: `2`
После срабатывания потока `Modbus-Read` вернет сложное сообщение. Подключив к нему узел `Debug` в режиме `complete msg object`, мы увидим в панели отладки примерно следующее:
{
"payload": [
255,
1024
],
"topic": "",
"responseBuffer": {
"type": "Buffer",
"data": [
0,
255,
4,
0
]
},
"input": {
"topic": "",
"payload": 1678886400000,
"_msgid": "a1b2c3d4.e5f6g7"
},
"_msgid": "h8i9j0k1.l2m3n4"
}
Анализ с помощью `Debug`:
- Мы видим, что `msg.payload` — это массив чисел `[255, 1024]`. Это и есть значения наших двух регистров.
- Мы также видим `msg.responseBuffer`, который содержит сырой ответ от устройства в виде буфера. Это полезно для отладки проблем с порядком байт (endianness).
- Свойство `msg.input` содержит исходное сообщение, которое инициировало чтение.
Теперь, чтобы в следующем узле `Function` обратиться к значению второго регистра, мы можем навести курсор на `1024` в панели отладки, нажать иконку "Copy Path", и в буфер обмена скопируется `payload[1]`. Это исключает опечатки и ускоряет разработку.
---
Узел Catch: централизованный перехват ошибок
> ⚠️ Внимание: Узел Catch не будет перехватывать ошибки из `subflow` (субпотоков) или с других вкладок. Для глобального перехвата необходимо размещать узел `Catch` на каждой вкладке с критически важной логикой или создавать специальный субпоток-обработчик ошибок, который будет использоваться повсеместно.
Узел `Catch` работает как "сеть безопасности" для вашего потока. Если какой-либо узел на этой же вкладке генерирует ошибку и она не обрабатывается на его собственном втором выходе (если он есть), `Catch` перехватит это исключение и создаст новое сообщение, содержащее всю информацию об ошибке.Принцип работы и конфигурация
Узел `Catch` можно настроить на перехват ошибок:
- От всех узлов (All nodes): Рекомендуемый режим. Ловит все неперехваченные ошибки на текущей вкладке (flow).
- От выбранных узлов (Selected nodes): Позволяет нацелиться на конкретные, наиболее критичные или нестабильные узлы.
После перехвата узел `Catch` генерирует объект `msg`, который имеет особую структуру. Ключевая информация находится в свойстве `msg.error`.
Структура `msg.error`:- `message`: Текстовое сообщение об ошибке. Например, `"Timed out"`.
- `source`: Объект, идентифицирующий узел, который вызвал ошибку.
* `type`: Тип узла (например, `knx-out`).
* `name`: Имя узла, заданное в редакторе.
Кроме `msg.error`, в сообщение также копируется оригинальное `msg`, которое вызвало ошибку. Это позволяет понять, какие именно входные данные привели к сбою.
Пример: отлов ошибки подключения к KNX шлюзу
Представим сценарий, где мы пытаемся отправить команду в шину KNX, но IP-шлюз недоступен (например, выключен или нет сетевого соединения с контроллером HI).
Поток:// Основной поток
[Inject] --(trigger)--> [KNX-Ultimate Out]
(отправка команды на групповой адрес 1/1/1)
// Поток обработки ошибок
[Catch] --(error msg)--> [Function: Format] --(notification)--> [Telegram Sender]
Настройка узлов:
Когда `Inject` активирует узел `KNX-Ultimate Out`, тот не сможет подключиться к шлюзу и сгенерирует ошибку. `Catch` немедленно перехватит ее. На вход узла `Function: Format` придет примерно такое `msg`:
{
"payload": true,
"topic": "",
"_msgid": "b1c2d3e4.f5g6h7",
"error": {
"message": "connect EHOSTUNREACH 192.168.1.99:3671",
"source": {
"id": "k8l9m0n1.o2p3q4",
"type": "knx-ultimate-out",
"name": "Управление светом в гостиной"
},
"stack": "..."
}
}
Код для узла `Function: Format`:
// Получаем информацию об ошибке из msg.error
const sourceNode = msg.error.source.name || msg.error.source.type;
const errorMessage = msg.error.message;
// Формируем человекочитаемое уведомление
const notificationText = `Критическая ошибка в системе HI!
Узел: ${sourceNode}
Ошибка: ${errorMessage}
Время: ${new Date().toLocaleString()}`;
// Помещаем текст в payload для узла отправки в Telegram
msg.payload = {
"chatId": "YOUR_ADMIN_CHAT_ID",
"type": "message",
"content": notificationText
}
return msg;
Такой подход превращает "тихий" сбой в управляемое событие, о котором немедленно узнает ответственный персонал.
---
Узел Status: мониторинг состояния узлов
В отличие от `Debug` и `Catch`, которые работают с сообщениями, узел `Status` следит за состоянием самих узлов. Многие узлы, особенно те, что взаимодействуют с внешним миром (MQTT, Modbus, KNX, DALI), отображают свой текущий статус под собой в виде иконки и текста. Узел `Status` позволяет перехватить изменение этого статуса и использовать его в логике.
Назначение и конфигурация
Узел `Status` позволяет отслеживать:
- Состояние подключения (например, узла `mqtt-in`: 'connected', 'disconnected', 'connecting').
- Ошибки связи (например, узла `modbus-read`: 'active', 'timeout', 'CRC error').
- Активность (например, узла `dali-out`: 'communicating', 'idle').
Как и `Catch`, его можно настроить на мониторинг всех узлов или только выбранных.
Структура сообщения
При изменении статуса целевого узла `Status` генерирует `msg` со свойством `msg.status`.
Структура `msg.status`:- `text`: Текстовое описание статуса.
- `fill`: Цвет иконки ('green', 'yellow', 'red', 'blue', 'grey').
- `shape`: Форма иконки ('ring' или 'dot').
- `source`: Объект, идентифицирующий узел-источник статуса.
Пример: перезагрузка сетевого интерфейса при потере MQTT-связи
Критически важной задачей на контроллере HI является обеспечение постоянной связи с MQTT-брокером. Если связь теряется, система может перестать получать команды и отправлять телеметрию.
Поток:[Status] --(status change)--> [Switch] --(is "disconnected"?)--> [Trigger] --(wait 5s)--> [Exec]
Логика потока:
- Свойство: `msg.status.text`
- Правило: `contains` `disconnected`
- Команда: `sudo /sbin/ifdown eth0 && sudo /sbin/ifup eth0`
{
"status": {
"fill": "red",
"shape": "ring",
"text": "disconnected",
"source": {
"id": "m3n4o5p6.q7r8s9",
"type": "mqtt in",
"name": "Основной брокер"
}
},
"_msgid": "c2d3e4f5.g6h7i8"
}
Этот автоматизированный сценарий самовосстановления значительно повышает надежность системы, позволяя ей самостоятельно исправлять распространенные проблемы со связью без вмешательства человека.
---
Комплексный пример: отладка потока опроса DALI
Давайте объединим все три инструмента для создания надежного потока, который опрашивает яркость DALI-светильника на объекте и отправляет данные в MQTT. Шина DALI подключена к контроллеру HI через шлюз RS-485-DALI.
Задача: Каждые 5 секунд запрашивать актуальный уровень яркости светильника с коротким адресом 3 и публиковать его в топик `hi/office/light/dim_level`. Базовый поток:[Inject] --(каждые 5 сек)--> [Function: Query] --> [DALI-Out] --> [DALI-In] --> [MQTT Out]
Теперь усовершенствуем его с помощью инструментов отладки.
Шаг 1: `Debug` для инспекции данныхМы не уверены, в каком формате `DALI-In` вернет данные. Подключим к нему узел `Debug`.
... --> [DALI-In] --> [Debug: DALI Response]
--> [MQTT Out]
Запустив поток, мы увидим в панели отладки, что `msg.payload` от узла `DALI-In` содержит число от 0 до 254. Теперь мы знаем, как с этими данными работать. Мы можем добавить узел `Function` для масштабирования этого значения в проценты (0-100), если это требуется.
Шаг 2: `Status` для мониторинга активности шиныШина DALI (как и RS-485) может быть занята. Если мы будем отправлять запросы слишком часто, могут возникнуть коллизии. Добавим `Status`, чтобы следить за узлами `DALI-Out` и `DALI-In`.
[Status: DALI Health] --(status change)--> [Debug: Bus Status]
Теперь, если узел `DALI-Out` покажет статус "communicating-error" или "queue full", мы это увидим и сможем, например, увеличить интервал опроса в узле `Inject`.
Шаг 3: `Catch` для обработки сбоев оборудованияЧто если сам шлюз RS-485-DALI "зависнет" или отключится от шины? Узлы `DALI-Out` или `DALI-In` сгененрируют ошибку таймаута. Мы должны ее поймать.
[Catch: DALI Failures] --(error)--> [Function: Alert] --> [Log to MySQL]
Этот поток будет молчать, пока все хорошо. Но как только произойдет сбой, он перехватит ошибку, сформирует запись для журнала аудита и запишет ее в базу данных MySQL, как мы научимся делать это в Модуле 8.
Итоговый отказоустойчивый и наблюдаемый поток:// ================= Поток опроса DALI =================
[Inject] ---> [Function: Query] ---> [DALI-Out] ---> [DALI-In] ---> [Function: Scale] ---> [MQTT Out]
(5s) |
+---> [Debug: Scaled Value] (активен при отладке)
// ============ Поток мониторинга и отладки ============
// Отслеживание состояния шины
[Status] --(нацелен на DALI узлы)--> [Debug: DALI Bus Status]
// Перехват критических ошибок оборудования
[Catch] --(все узлы)--> [Function: Format Error] --+--> [Log to MySQL]
|
+--> [Telegram: Alert Admin]
Этот комплексный подход, сочетающий инспекцию данных (`Debug`), мониторинг состояния (`Status`) и обработку исключений (`Catch`), является стандартом для построения профессиональных и надежных систем автоматизации на платформе HI.
---
Итоги и лучшие практики отладки
> ℹ️ Информация: В контроллерах HI вы можете включать и отключать отладочные потоки целиком с помощью переменной окружения. Определите глобальную переменную, например, `global.get("DEBUG_MODE")`, и вставьте узел `Switch` в начале отладочных потоков. Это позволяет быстро переключать всю систему между режимами "разработка" и "продакшен" без ручного включения/выключения сотен узлов `Debug`.
Подведем итоги по использованию трех ключевых инструментов отладки:
- Когда использовать `Debug`:
* Для понимания структуры данных от новых или незнакомых устройств (Modbus, KNX, DALI).
* Для быстрой проверки логики в узлах `Switch` и `Function`.
- Когда использовать `Catch`:
* Для создания отказоустойчивых сценариев, которые не "падают" от непредвиденных ошибок (обрыв связи, некорректный ответ устройства).
* Для централизованного логирования системных сбоев и отправки уведомлений.
- Когда использовать `Status`:
* Для создания сценариев самовосстановления системы (например, перезагрузка сетевого интерфейса).
* Для визуального отображения статуса системы на Dashboard.
Золотое правило отладки:Отладочные узлы (`Debug`) должны быть отключены или удалены в производственной (продакшен) среде. Они создают значительную нагрузку и могут замедлить работу контроллера.
В то же время, узлы `Catch` и `Status` являются неотъемлемой частью основной логики и должны оставаться активными в продакшене. Они обеспечивают надежность, наблюдаемость и отказоустойчивость вашей системы автоматизации.
Что дальше
В следующем уроке мы перейдем к продвинутым техникам отладки, включая использование встроенного профилировщика для поиска "узких мест" в производительности ваших потоков и симуляцию устройств для тестирования сценариев без наличия физического оборудования.