ГлавнаяАкадемияВведение в протоколы автоматизации → FLOW-SAFETY-001: Flow для обработки сигнала от датчика протечки

FLOW-SAFETY-001: Flow для обработки сигнала от датчика протечки

Урок 5 · Введение в протоколы автоматизации · 30 мин · theory

Введение: Архитектура сценария 'Протечка воды'

🔗 Связанный материал: Данный урок является практическим применением концепций, рассмотренных в уроке `Сценарий 'Протечка воды': отключение насосов и розеток в мокрой зоне` (COURSE-06-M07-L03). Мы переходим от теории к созданию полностью рабочего и надежного потока (flow) в среде Node-RED.

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

Как мы уже рассматривали ранее, концепция безопасного состояния (Safe-State) подразумевает перевод системы или её части в заранее определенное, безопасное состояние при возникновении аварийной ситуации. Применительно к протечке воды, Safe-State — это не просто оповещение, а комплекс немедленных и решительных действий:

  • Перекрытие подачи воды: Мгновенное закрытие магистральных шаровых кранов с электроприводом для прекращения притока воды.
  • Обесточивание "мокрых зон": Отключение розеточных групп в санузлах, на кухне и в других помещениях, где вода на полу может привести к короткому замыканию, риску поражения электрическим током или возгоранию.
  • Для реализации этого сценария мы будем использовать следующие системные компоненты, доступные на платформе HI:

    * Шаровые краны с электроприводом, управляемые по протоколу Modbus или через релейные выходы контроллера.

    * Релейные модули контроллера HI или внешние модули (например, Wirenboard WB-MRM6C), управляющие силовыми линиями розеток.

    Высокоуровневая логическая схема нашего сценария строится по классической четырехэтапной модели реагирования на инциденты:

  • Обнаружение (Detect): Непрерывный мониторинг состояния датчиков протечки.
  • Действие (Act): При подтвержденном сигнале тревоги немедленная активация Safe-State — закрытие кранов и отключение реле.
  • Оповещение (Notify): Одновременная отправка тревожного сообщения с указанием сработавшего датчика.
  • Сброс (Reset): Возврат системы в нормальное рабочее состояние только после ручного подтверждения от пользователя, удостоверившегося в устранении причины аварии.
  • Создание такого flow требует не только знания узлов Node-RED, но и понимания инженерных принципов построения надежных систем, включая защиту от ложных срабатываний и проектирование безопасных процедур восстановления.

    ---

    Шаг 1: Получение данных с датчика протечки по MQTT

    Первым шагом в построении любого сценария автоматизации является получение данных от источника — в нашем случае, от датчика протечки. Мы рассмотрим наиболее распространенный и гибкий способ интеграции на платформе HI — использование протокола MQTT.

    Большинство современных периферийных устройств, таких как модули Wirenboard, публикуют (publish) свои состояния в топики на MQTT-брокере, который работает прямо на контроллере HI. Наша задача — подписаться (subscribe) на нужный топик в Node-RED и правильно интерпретировать полученное сообщение.

    Типичная структура MQTT-топиков и payload

    Для модуля датчиков WB-MSW v.3, с которым мы работаем в этом примере, типичная структура топиков выглядит следующим образом:

    `/devices/{device-name}/controls/{control-name}`

    Когда датчик, подключенный к первому входу модуля, фиксирует наличие воды, модуль публикует в топик `/devices/wb-msw-v3_21/controls/Water Alarm 1` сообщение со значением (payload) `'1'`. Когда датчик высыхает, публикуется payload `'0'`.

    > ℹ️ Информация: Важно отметить, что многие устройства отправляют значения в виде строк (`"1"`, `"0"`, `"true"`, `"false"`), а не в виде чисел или булевых значений. Это требует нормализации данных внутри Node-RED для дальнейшей обработки.

    Настройка узла `mqtt in`

    Для получения этих данных мы используем узел `mqtt in` из стандартной палитры Node-RED.

  • Перетащите узел `mqtt in` на рабочее поле.
  • Дважды кликните на него для открытия окна настроек.
  • Server: Выберите преднастроенный MQTT-брокер (обычно `localhost:1883`, так как он работает на самом контроллере).
  • Topic: Укажите точный топик, на который нужно подписаться. В нашем случае это `/devices/wb-msw-v3_21/controls/Water Alarm 1`.
  • QoS: Установите `2 - Exactly once`, чтобы гарантировать доставку сообщения даже в случае кратковременных сбоев сети.
  • Output: Оставьте `auto-detect (string or buffer)`.
  • Name: Дайте узлу осмысленное имя, например "Датчик протечки (Кухня)".
  • (Примечание: Изображение является иллюстрацией)

    Теперь, при каждом изменении состояния датчика, на выход этого узла будет поступать объект `msg`, где `msg.payload` будет содержать строку `'1'` или `'0'`.

    Нормализация данных

    Для удобства дальнейшей работы с логикой, строковые значения `'1'` и `'0'` следует преобразовать в более подходящий тип, например, в булевы `true` и `false`. Это делается с помощью узла `change`.

  • Разместите узел `change` после узла `mqtt in`.
  • Настройте его следующим образом:
  • * Правило 1:

    * `Set`: `msg.payload`

    * `to the value`: `true` (boolean)

    * `if`: `msg.payload` `==` `'1'` (string)

    * Правило 2:

    * `Set`: `msg.payload`

    * `to the value`: `false` (boolean)

    * `if`: `msg.payload` `==` `'0'` (string)

  • Name: "Нормализация (string to boolean)".
  • Теперь на выходе узла `change` мы имеем стандартизированный сигнал: `msg.payload` будет равен `true` при протечке и `false` в нормальном состоянии. Это значительно упрощает построение дальнейшей логики с помощью узлов `switch` и `trigger`.

    Пример сообщения до нормализации:

    {
    

    "topic": "/devices/wb-msw-v3_21/controls/Water Alarm 1",

    "payload": "1",

    "qos": 2,

    "retain": false,

    "_msgid": "c7a012b1.385fe"

    }

    Пример сообщения после нормализации:

    {
    

    "topic": "/devices/wb-msw-v3_21/controls/Water Alarm 1",

    "payload": true,

    "qos": 2,

    "retain": false,

    "_msgid": "c7a012b1.385fe"

    }

    Эта простая связка `mqtt in` -> `change` является надежным фундаментом для нашего сценария.

    ---

    Шаг 2: Реализация основной логики и защита от ложных срабатываний

    Получив чистый и нормализованный сигнал от датчика (`true`/`false`), следующим шагом является реализация основной логики. И здесь кроется одна из самых частых ошибок начинающих инженеров — немедленная реакция на сигнал.

    Риски немедленной реакции

    Представьте, что вы напрямую соединили выход нормализатора с узлами, закрывающими краны. Что произойдет, если на датчике возникнет кратковременная помеха? Или если во время влажной уборки тряпкой случайно коснулись контактов датчика всего на полсекунды? Система немедленно перекроет воду и отключит розетки по всему дому, создав серьезные неудобства без реальной на то причины. Такое явление называется ложным срабатыванием. Его источниками могут быть:

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

    Применение узла `trigger` для фильтрации

    Идеальным инструментом для этой задачи в Node-RED является узел `trigger`. Он позволяет передать сигнал дальше только в том случае, если он остается активным в течение заданного промежутка времени.

    Разместите узел `trigger` после вашего узла `change`. Соедините выход узла `change` с входом `trigger`.

    Конфигурация узла `trigger` для защиты от ложных тревог:
  • Откройте настройки узла `trigger`.
  • Send: `nothing` (изначально ничего не отправлять).
  • then wait for: `2` `seconds` (затем подождать 2 секунды).
  • then send: `the latest message`.
  • Handling of intermediate messages: Оставьте `send them` (это важно для сброса таймера).
  • В поле `and/or when a message is received with topic equal to` введите `reset`. Это позволит нам в будущем принудительно сбрасывать таймер, если потребуется.
  • Name: "Защита от дребезга (2 сек)".
  • Как это работает: 1. На вход `trigger` приходит `msg` с `payload: true`.

    2. Узел запускает внутренний таймер на 2 секунды, но ничего не отправляет на выход.

    3. Датчик продолжает быть мокрым, поэтому новых сообщений не приходит (или приходят такие же `payload: true`, которые просто обновляют "последнее сообщение").

    4. По истечении 2 секунд `trigger` отправляет на выход последнее полученное сообщение, то есть `msg` с `payload: true`. Тревога подтверждена.

    1. На вход `trigger` приходит `msg` с `payload: true` (например, от случайной капли).

    2. Узел запускает таймер на 2 секунды.

    3. Через полсекунды датчик высыхает, и с узла `change` приходит новый `msg` с `payload: false`.

    4. `trigger` видит этот новый `msg` (потому что мы выбрали "Handling of intermediate messages: send them"), и его логика по умолчанию сбрасывает таймер и ничего не делает, так как сообщение изменилось.

    5. На выход ничего не отправляется. Ложная тревога отфильтрована.

    > 💡 Подсказка: Выберите задержку в 2-3 секунды. Этого достаточно, чтобы отфильтровать случайные помехи от датчика, но не настолько долго, чтобы нанести существенный ущерб при реальной протечке. Для большинства бытовых сценариев это оптимальный баланс между надежностью и скоростью реакции.

    Эта простая, но элегантная логика с использованием узла `trigger` превращает наш flow из "игрушечного" в профессиональное и надежное решение, которому можно доверять управление критически важными системами.

    ---

    Шаг 3: Активация 'Safe-State' — управление исполнительными устройствами

    После того как узел `trigger` подтвердил, что тревога не является ложной, мы получаем на его выходе сигнал (`msg` с `payload: true`). Теперь наша задача — немедленно и решительно действовать. На этом шаге мы преобразуем этот единственный сигнал тревоги в серию команд для всех необходимых исполнительных устройств.

    Мы будем использовать узел `mqtt out` для отправки команд на закрытие шаровых кранов и отключение реле розеток, так как это универсальный метод управления оборудованием на платформе HI.

    Сначала, нам нужно направить поток в зависимости от значения `payload`. Это делается с помощью узла `switch`:

  • Разместите узел `switch` после узла `trigger`.
  • Настройте его на проверку `msg.payload`:
  • * Правило 1: `is true` -> Выход 1 (Сигнал тревоги)

    * Правило 2: `is false` -> Выход 2 (Сигнал сброса/отмены) - этот выход мы будем использовать позже для логики ручного сброса.

    Сейчас мы сосредоточимся на первом выходе, который активируется при `payload: true`.

    Управление шаровыми кранами с электроприводом

    Предположим, у нас два шаровых крана (холодная и горячая вода), которые управляются через Modbus-реле Wirenboard WB-MWAC. Это реле, в свою очередь, управляется по MQTT. Чтобы закрыть кран, подключенный к выходу K1, нам нужно отправить в топик `/devices/wb-mwac_34/controls/K1/on` значение `'1'`.

  • Возьмите узел `mqtt out`.
  • Подключите его к первому выходу узла `switch`.
  • Настройте узел `mqtt out`:
  • * Server: `localhost:1883`

    * Topic: `/devices/wb-mwac_34/controls/K1/on`

    * Payload: `1` (строка)

    * QoS: `2`

    * Retain: `false`

    * Name: "Закрыть кран ХВС"

  • Скопируйте этот узел, измените топик на `/devices/wb-mwac_34/controls/K2/on` и назовите его "Закрыть кран ГВС". Подключите его также к первому выходу узла `switch`.
  • Теперь при сигнале тревоги оба крана получат команду на закрытие.

    Отключение розеточных групп

    Аналогично, мы отключим реле, управляющие розетками в "мокрых зонах". Допустим, розетки кухни управляются реле K3 на модуле WB-MRM6C, а розетки санузла — реле K5 на том же модуле. Чтобы отключить реле, нужно отправить в его "командный" топик `.../on` значение `'0'`.

  • Возьмите еще один узел `mqtt out`.
  • Настройте его:
  • * Topic: `/devices/wb-mrm6c_15/controls/K3/on`

    * Payload: `0` (строка)

    * Name: "Откл. розетки (кухня)"

  • Скопируйте узел:
  • * Topic: `/devices/wb-mrm6c_15/controls/K5/on`

    * Payload: `0` (строка)

    * Name: "Откл. розетки (санузел)"

    Подключите оба эти узла к тому же первому выходу узла `switch`.

    Пример сообщения, которое будет отправлено для отключения одного из реле:

    // Это сообщение будет сгенерировано и отправлено узлом 'mqtt out'
    

    {

    "topic": "/devices/wb-mrm6c_15/controls/K3/on",

    "payload": "0",

    "qos": 2,

    "retain": false

    }

    > ℹ️ Важность разделения топиков: Обратите внимание, что мы отправляем команды в топики, заканчивающиеся на `.../on`. Это командные топики. Устройства Wirenboard также публикуют свое текущее состояние в топики без `/on` (например, `/devices/wb-mrm6c_15/controls/K3`). Это топики состояния (read-only). Никогда не путайте их. Мы всегда отправляем команды в `.../on` и читаем статус из `...`.

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

    ---

    Шаг 4: Система оповещений и логика ручного сброса

    Перевод системы в Safe-State — это только половина дела. Вторая, не менее важная часть, — это информирование пользователя о произошедшем и предоставление ему безопасного способа вернуть систему в нормальный режим работы.

    Отправка мгновенных оповещений

    Сразу после отправки команд на исполнительные устройства, мы должны уведомить ответственное лицо. Одним из самых эффективных способов является отправка сообщения в Telegram.

  • Установите в Node-RED палитру `node-red-contrib-telegrambot-home`.
  • Настройте узел `telegram sender` (вам понадобится создать бота в Telegram и получить его API-токен).
  • Подключите этот узел к первому выходу нашего главного узла `switch`, параллельно с узлами управления кранами и реле.
  • В настройках узла `telegram sender` в поле `Content` напишите информативное сообщение. Можно использовать данные из входящего `msg`, чтобы указать, какой именно датчик сработал.
  • Пример простого сообщения:

    `⚠️ ВНИМАНИЕ! Обнаружена протечка воды! Система переведена в безопасный режим: подача воды перекрыта, розетки в мокрых зонах обесточены.`

    Пример продвинутого сообщения с использованием `msg.topic`:

    `⚠️ Протечка! Датчик: {{topic}}. Активирован режим Safe-State.`

    Теперь пользователь мгновенно узнает об инциденте и его масштабе.

    Критическая важность механизма ручного сброса

    > ⚠️ Внимание: Система НИКОГДА не должна автоматически возвращаться в нормальное состояние после высыхания датчика. Всегда требуйте ручного подтверждения от пользователя или инженера. Это критически важный аспект безопасности.

    Почему это так важно? Представьте, что прорвало трубу. Система корректно отработала и перекрыла воду. Через некоторое время лужа на полу высохла, и датчик перестал подавать сигнал. Если система "умная" и автоматически откроет краны, она просто возобновит потоп, так как первопричина (прорыв трубы) не была устранена.

    Правильная логика такова:

  • Система переходит в состояние "ТРЕВОГА" и остается в нем, даже если датчик высох.
  • Пользователь получает уведомление, приезжает на объект, находит и устраняет причину протечки (меняет прокладку, затягивает фитинг).
  • Только после физического устранения проблемы пользователь нажимает специальную кнопку "Сброс тревоги" в интерфейсе управления (например, в приложении iRidium, на панели умного дома или даже просто в Telegram-боте).
  • Эта кнопка инициирует обратный процесс: открытие кранов и включение розеток.
  • Реализация логики сброса

  • Создайте "точку входа" для сброса. Это еще один узел `mqtt in`, подписанный на специальный "системный" топик, например, `myhome/alarms/water/reset`. Когда пользователь нажимает кнопку "Сброс" в интерфейсе, этот интерфейс должен опубликовать в данный топик любое сообщение (например, `1`).
  • Реализуйте логику "защелки" (latch). Нам нужно хранить состояние тревоги. Для этого идеально подходит узел `function`, работающий как конечный автомат (FSM), или более простой вариант с использованием контекста потока.
  • Давайте реализуем простой вариант с помощью узла `switch` и контекста.

    Мы будем хранить состояние тревоги в переменной контекста `flow.water_alarm_active`.

    Упрощенная схема потока сброса:

    `[mqtt in: myhome/alarms/water/reset]` -> `[function: "Проверить статус тревоги"]` -> `[switch: "Тревога активна?"]` -> (Выход 1) -> `[mqtt out: "Открыть краны"]` & `[mqtt out: "Включить розетки"]` -> `[change: "Сбросить флаг тревоги"]`

    Код для узла `function: "Проверить статус тревоги"`:
    // Получаем текущее состояние тревоги из контекста потока.
    

    // Если оно не задано, считаем, что тревоги нет.

    let alarmActive = flow.get("water_alarm_active") || false;

    if (alarmActive) {

    // Если тревога была активна, передаем сообщение дальше

    // для выполнения действий по сбросу.

    return msg;

    } else {

    // Если тревоги не было, ничего не делаем.

    node.warn("Попытка сброса при неактивной тревоге.");

    return null;

    }

    Настройка узла `change: "Сбросить флаг тревоги"`:

    Таким образом, мы создаем надежный, двусторонний процесс: автоматическая реакция на опасность и ручное, осознанное восстановление после устранения ее причин.

    ---

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

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

    Полная логика нашего flow выглядит так:

    `[MQTT In: Датчик]` -> `[Change: Нормализация]` -> `[Trigger: Защита от дребезга]` -> `[Switch: Тревога или нет?]` -> (Ветвь "Тревога") ->

  • `[MQTT Out: Закрыть краны]`
  • `[MQTT Out: Отключить розетки]`
  • `[Telegram: Отправить уведомление]`
  • `[Change: Установить флаг flow.water_alarm_active = true]`
  • `[MQTT In: Команда сброса]` -> `[Function: Проверить флаг]` -> (Если флаг true) ->

  • `[MQTT Out: Открыть краны]`
  • `[MQTT Out: Включить розетки]`
  • `[Change: Сбросить флаг flow.water_alarm_active = false]`
  • `[Telegram: Отправить уведомление 'Система в норме']`
  • Ключевые этапы и принципы:

    📋 Ключевые понятия, которые мы применили:

    Что дальше? Возможности для расширения

    Созданный нами flow является прочной основой, которую можно и нужно развивать. Вот несколько идей для дальнейшего усовершенствования:

    В следующем уроке мы рассмотрим еще один критически важный сценарий из набора 'Safe-State' и применим изученные подходы для его реализации.