ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → Отладка в Node-RED: узлы Debug, Catch, Status

Отладка в Node-RED: узлы Debug, Catch, Status

Урок 4 · Сценарии умного дома: режимы, состояния, приоритеты · 30 мин · theory

Введение в инструменты отладки Node-RED

> 🔗 Связанный материал: Данный урок посвящен отладке в реальном времени. Вопросы долгосрочного хранения и анализа событий (журналирование) мы подробно рассмотрим в Модуле 8, начиная с урока COURSE-07-M08-L01 "Зачем нужен журнал событий? (Audit Trail)".

Эффективная отладка — это ключевой навык инженера по автоматизации, позволяющий быстро находить и устранять проблемы в логике сценариев. В экосистеме Node-RED на контроллерах HI этот процесс строится на трех фундаментальных инструментах: узлах Debug, Catch и Status. Понимание их различий и областей применения критически важно для создания надежных и легко обслуживаемых систем.

Важно проводить четкую грань между отладкой (debugging) и журналированием (logging).

Отладка — это процесс интерактивного исследования потока данных и состояний во время разработки или пусконаладки. Ее цель — понять, почему* система ведет себя определенным образом в данный момент. Инструменты отладки обычно отключаются в производственной среде (продакшене), чтобы не создавать лишнюю нагрузку. Журналирование, которое мы рассмотрим позже, — это систематическая* запись ключевых событий, ошибок и состояний в долгосрочное хранилище (например, в базу данных MySQL на контроллере или во внешний MQTT-брокер). Журнал необходим для анализа работы системы в ретроспективе, выявления трендов и расследования инцидентов.

Тремя китами отладки в Node-RED являются:

  • Узел `Debug`: Основной инструмент для инспекции содержимого сообщений (`msg`), проходящих через поток. Он позволяет "заглянуть внутрь" потока данных в любой его точке.
  • Узел `Catch`: Специализированный узел для перехвата и обработки ошибок, сгенерированных другими узлами в рамках одного потока (вкладки). Это основа для создания отказоустойчивой логики.
  • Узел `Status`: Инструмент для мониторинга "здоровья" и текущего состояния самих узлов, а не сообщений. Он сообщает, когда узел MQTT подключился к брокеру, когда Modbus-устройство перестало отвечать и т.д.
  • Многие начинающие разработчики используют `console.log()` внутри узлов `Function` для отладки. Хотя это технически возможно, такой подход имеет существенные недостатки:

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

    ---

    Глубокое погружение в узел Debug

    > 💡 Подсказка: Для отладки сложных объектов, измените вывод узла Debug на 'complete msg object'. Это позволит увидеть не только `payload`, но и все служебные свойства, например, `_msgid` или данные, добавленные предыдущими узлами, что критично для понимания логики State Machine или Priority Gate.

    Узел `Debug` — это ваш цифровой мультиметр для потоков Node-RED. Он позволяет измерить "напряжение" (данные) на любом "проводе" (соединении) в вашей схеме.

    Конфигурация узла

    Узел имеет гибкие настройки вывода:

  • `msg.payload`: Настройка по умолчанию. Выводит только содержимое свойства `msg.payload`.
  • `complete msg object`: Самая полезная опция для глубокой отладки. Выводит весь объект `msg` целиком, со всеми его свойствами (`topic`, `_msgid`, `error`, `request` и любыми другими, добавленными по ходу потока).
  • Выражение JSONata: Позволяет вывести результат вычисления сложного выражения. Например, можно вывести только температуру из сложного объекта или проверить условие. Пример: `payload.devices[0].sensors[2].value`.
  • Вывод может быть направлен в несколько мест:

    Функция "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`:

    После срабатывания потока `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`:

    Теперь, чтобы в следующем узле `Function` обратиться к значению второго регистра, мы можем навести курсор на `1024` в панели отладки, нажать иконку "Copy Path", и в буфер обмена скопируется `payload[1]`. Это исключает опечатки и ускоряет разработку.

    ---

    Узел Catch: централизованный перехват ошибок

    > ⚠️ Внимание: Узел Catch не будет перехватывать ошибки из `subflow` (субпотоков) или с других вкладок. Для глобального перехвата необходимо размещать узел `Catch` на каждой вкладке с критически важной логикой или создавать специальный субпоток-обработчик ошибок, который будет использоваться повсеместно.

    Узел `Catch` работает как "сеть безопасности" для вашего потока. Если какой-либо узел на этой же вкладке генерирует ошибку и она не обрабатывается на его собственном втором выходе (если он есть), `Catch` перехватит это исключение и создаст новое сообщение, содержащее всю информацию об ошибке.

    Принцип работы и конфигурация

    Узел `Catch` можно настроить на перехват ошибок:

    После перехвата узел `Catch` генерирует объект `msg`, который имеет особую структуру. Ключевая информация находится в свойстве `msg.error`.

    Структура `msg.error`: * `id`: Уникальный ID узла.

    * `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]

    Настройка узлов:
  • `KNX-Ultimate Out`: Настроен на отправку значения `true` на групповой адрес `1/1/1`. IP-адрес шлюза указан неверно или шлюз выключен.
  • `Catch`: Настроен на перехват ошибок от всех узлов.
  • `Function: Format`: Формирует сообщение для отправки администратору.
  • Когда `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` позволяет отслеживать:

    Как и `Catch`, его можно настроить на мониторинг всех узлов или только выбранных.

    Структура сообщения

    При изменении статуса целевого узла `Status` генерирует `msg` со свойством `msg.status`.

    Структура `msg.status`:

    Пример: перезагрузка сетевого интерфейса при потере MQTT-связи

    Критически важной задачей на контроллере HI является обеспечение постоянной связи с MQTT-брокером. Если связь теряется, система может перестать получать команды и отправлять телеметрию.

    Поток:
    [Status] --(status change)--> [Switch] --(is "disconnected"?)--> [Trigger] --(wait 5s)--> [Exec]
    
    Логика потока:
  • `Status`: Настроен на мониторинг узла `mqtt in`, который подключен к нашему основному брокеру.
  • `Switch`: Проверяет, содержит ли `msg.status.text` подстроку `"disconnected"`.
  • `Trigger`: Используется для предотвращения "дребезга". Он отправляет одно сообщение, а затем блокируется на 5 секунд. Это не дает системе пытаться перезагрузить интерфейс много раз подряд.
  • `Exec`: Выполняет системную команду на контроллере HI для перезагрузки сетевого интерфейса.
  • Настройка `Switch`: Настройка `Exec`: Входящее сообщение в узел `Switch` при потере связи:
    {
    

    "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`.

    Подведем итоги по использованию трех ключевых инструментов отладки:

    * Во время разработки для проверки содержимого `msg` на каждом шаге.

    * Для понимания структуры данных от новых или незнакомых устройств (Modbus, KNX, DALI).

    * Для быстрой проверки логики в узлах `Switch` и `Function`.

    * Всегда на любой вкладке с важной логикой.

    * Для создания отказоустойчивых сценариев, которые не "падают" от непредвиденных ошибок (обрыв связи, некорректный ответ устройства).

    * Для централизованного логирования системных сбоев и отправки уведомлений.

    * Для мониторинга "здоровья" ключевых интеграций: MQTT, Modbus, KNX, DALI.

    * Для создания сценариев самовосстановления системы (например, перезагрузка сетевого интерфейса).

    * Для визуального отображения статуса системы на Dashboard.

    Золотое правило отладки:

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

    В то же время, узлы `Catch` и `Status` являются неотъемлемой частью основной логики и должны оставаться активными в продакшене. Они обеспечивают надежность, наблюдаемость и отказоустойчивость вашей системы автоматизации.

    Что дальше

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