FLOW-SAFETY-001: Flow для обработки сигнала от датчика протечки
Введение: Архитектура сценария 'Протечка воды'
🔗 Связанный материал: Данный урок является практическим применением концепций, рассмотренных в уроке `Сценарий 'Протечка воды': отключение насосов и розеток в мокрой зоне` (COURSE-06-M07-L03). Мы переходим от теории к созданию полностью рабочего и надежного потока (flow) в среде Node-RED.
Основная цель этого урока — разработать и внедрить на контроллере HI отказоустойчивый сценарий автоматического реагирования на протечку воды. Этот сценарий является критически важным элементом любой современной системы автоматизации, так как он напрямую направлен на предотвращение значительного материального ущерба и обеспечение безопасности на объекте.
Как мы уже рассматривали ранее, концепция безопасного состояния (Safe-State) подразумевает перевод системы или её части в заранее определенное, безопасное состояние при возникновении аварийной ситуации. Применительно к протечке воды, Safe-State — это не просто оповещение, а комплекс немедленных и решительных действий:
Для реализации этого сценария мы будем использовать следующие системные компоненты, доступные на платформе HI:
- Датчики обнаружения: Датчики протечки, подключенные к универсальным входам контроллера или специализированным модулям (в нашем примере — модуль входов Wirenboard WB-MSW v.3, который обменивается данными по протоколу MQTT).
- Исполнительные устройства:
* Релейные модули контроллера HI или внешние модули (например, Wirenboard WB-MRM6C), управляющие силовыми линиями розеток.
- Система оповещений: Интеграция с мессенджером Telegram для мгновенной отправки тревожных уведомлений ответственному лицу (владельцу, инженеру).
Высокоуровневая логическая схема нашего сценария строится по классической четырехэтапной модели реагирования на инциденты:
Создание такого 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}`
- `{device-name}`: Уникальное имя устройства, например `wb-msw-v3_21`.
- `{control-name}`: Имя конкретного "контрола" или датчика, например `Water Alarm 1` или `Water Alarm 2`.
Когда датчик, подключенный к первому входу модуля, фиксирует наличие воды, модуль публикует в топик `/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.
(Примечание: Изображение является иллюстрацией)
Теперь, при каждом изменении состояния датчика, на выход этого узла будет поступать объект `msg`, где `msg.payload` будет содержать строку `'1'` или `'0'`.
Нормализация данных
Для удобства дальнейшей работы с логикой, строковые значения `'1'` и `'0'` следует преобразовать в более подходящий тип, например, в булевы `true` и `false`. Это делается с помощью узла `change`.
* Правило 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)
Теперь на выходе узла `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` для защиты от ложных тревог:- Сценарий 1: Реальная протечка.
2. Узел запускает внутренний таймер на 2 секунды, но ничего не отправляет на выход.
3. Датчик продолжает быть мокрым, поэтому новых сообщений не приходит (или приходят такие же `payload: true`, которые просто обновляют "последнее сообщение").
4. По истечении 2 секунд `trigger` отправляет на выход последнее полученное сообщение, то есть `msg` с `payload: true`. Тревога подтверждена.
- Сценарий 2: Ложное срабатывание.
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`:
* Правило 1: `is true` -> Выход 1 (Сигнал тревоги)
* Правило 2: `is false` -> Выход 2 (Сигнал сброса/отмены) - этот выход мы будем использовать позже для логики ручного сброса.
Сейчас мы сосредоточимся на первом выходе, который активируется при `payload: true`.
Управление шаровыми кранами с электроприводом
Предположим, у нас два шаровых крана (холодная и горячая вода), которые управляются через Modbus-реле Wirenboard WB-MWAC. Это реле, в свою очередь, управляется по MQTT. Чтобы закрыть кран, подключенный к выходу K1, нам нужно отправить в топик `/devices/wb-mwac_34/controls/K1/on` значение `'1'`.
* Server: `localhost:1883`
* Topic: `/devices/wb-mwac_34/controls/K1/on`
* Payload: `1` (строка)
* QoS: `2`
* Retain: `false`
* Name: "Закрыть кран ХВС"
Теперь при сигнале тревоги оба крана получат команду на закрытие.
Отключение розеточных групп
Аналогично, мы отключим реле, управляющие розетками в "мокрых зонах". Допустим, розетки кухни управляются реле K3 на модуле WB-MRM6C, а розетки санузла — реле K5 на том же модуле. Чтобы отключить реле, нужно отправить в его "командный" топик `.../on` значение `'0'`.
* 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.
Пример простого сообщения:
`⚠️ ВНИМАНИЕ! Обнаружена протечка воды! Система переведена в безопасный режим: подача воды перекрыта, розетки в мокрых зонах обесточены.`
Пример продвинутого сообщения с использованием `msg.topic`:
`⚠️ Протечка! Датчик: {{topic}}. Активирован режим Safe-State.`
Теперь пользователь мгновенно узнает об инциденте и его масштабе.
Критическая важность механизма ручного сброса
> ⚠️ Внимание: Система НИКОГДА не должна автоматически возвращаться в нормальное состояние после высыхания датчика. Всегда требуйте ручного подтверждения от пользователя или инженера. Это критически важный аспект безопасности.
Почему это так важно? Представьте, что прорвало трубу. Система корректно отработала и перекрыла воду. Через некоторое время лужа на полу высохла, и датчик перестал подавать сигнал. Если система "умная" и автоматически откроет краны, она просто возобновит потоп, так как первопричина (прорыв трубы) не была устранена.
Правильная логика такова:
Реализация логики сброса
Давайте реализуем простой вариант с помощью узла `switch` и контекста.
Мы будем хранить состояние тревоги в переменной контекста `flow.water_alarm_active`.
- Когда приходит сигнал тревоги (с нашего узла `trigger`), мы устанавливаем `flow.water_alarm_active = true`.
- Когда приходит команда сброса (из топика `myhome/alarms/water/reset`), мы проверяем `flow.water_alarm_active`. Если `true`, то мы инициируем открытие кранов и устанавливаем `flow.water_alarm_active = false`.
`[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: "Сбросить флаг тревоги"`:
- `Set`: `flow.water_alarm_active`
- `to the value`: `false` (boolean)
Таким образом, мы создаем надежный, двусторонний процесс: автоматическая реакция на опасность и ручное, осознанное восстановление после устранения ее причин.
---
Итоги и лучшие практики
В этом уроке мы на практике разобрали создание одного из самых важных сценариев безопасности — реакции на протечку воды. Мы прошли все этапы, от получения данных до реализации безопасного механизма восстановления, превратив набор отдельных узлов в целостную и надежную систему.
Полная логика нашего flow выглядит так:`[MQTT In: Датчик]` -> `[Change: Нормализация]` -> `[Trigger: Защита от дребезга]` -> `[Switch: Тревога или нет?]` -> (Ветвь "Тревога") ->
`[MQTT In: Команда сброса]` -> `[Function: Проверить флаг]` -> (Если флаг true) ->
Ключевые этапы и принципы:
- Надежное обнаружение: Использование стандартных протоколов (MQTT) и нормализация данных для унификации.
- Фильтрация ложных срабатываний: Применение узла `trigger` (debouncing) для игнорирования кратковременных помех — признак профессионального подхода.
- Решительные действия: Мгновенный и одновременный перевод всех связанных систем в Safe-State.
- Четкое оповещение: Немедленное информирование пользователя о характере и факте инцидента.
- Безопасный сброс: Реализация логики, требующей обязательного ручного вмешательства для возврата системы в рабочий режим.
📋 Ключевые понятия, которые мы применили:
- Интеграция датчиков по MQTT
- Фильтрация ложных срабатываний (Debouncing)
- Реализация логики 'Safe-State'
- Паттерны аварийных оповещений
- Механизм ручного сброса тревоги
Что дальше? Возможности для расширения
Созданный нами flow является прочной основой, которую можно и нужно развивать. Вот несколько идей для дальнейшего усовершенствования:
- Эскалация тревог: Если тревога не сброшена в течение 10 минут, система может предпринять более активные действия: включить звуковую сирену или совершить голосовой вызов на телефон владельца через GSM-шлюз.
- Логирование событий: Все события (обнаружение протечки, активация Safe-State, ручной сброс) должны записываться в базу данных (например, MySQL на контроллере) для последующего анализа и ведения "журнала инцидентов".
- Дифференцированные уведомления: Можно настроить отправку разных сообщений разным группам пользователей. Например, владельцу — простое уведомление, а сервисному инженеру — техническое сообщение с указанием сработавшего модуля, датчика и предпринятых действий.
- Проверка перед сбросом: В логику сброса можно добавить дополнительное условие: не открывать краны, если датчик, вызвавший тревогу, все еще сообщает о наличии воды.
В следующем уроке мы рассмотрим еще один критически важный сценарий из набора 'Safe-State' и применим изученные подходы для его реализации.