Практика: FLOW-SAFETY-LEAK-PROTECTION
Введение: Логика и компоненты сценария "Защита от протечки"
> ℹ️ Информация: Данный урок является практической реализацией теоретической концепции, описанной в сценарии SCN-SAFETY-001. Перед началом работы убедитесь, что вы изучили основные принципы и цели, заложенные в основу данного критически важного механизма безопасности.
Целью данного практического урока является пошаговая разработка, внедрение и тестирование надежного сценария FLOW-SAFETY-LEAK-PROTECTION в среде Node-RED на базе аппаратной платформы контроллера HI. Этот сценарий представляет собой один из ключевых элементов системы безопасности любого современного объекта автоматизации, будь то квартира, загородный дом или коммерческое помещение. Его основная задача — минимизировать ущерб от затопления путем автоматического прекращения подачи воды при обнаружении утечки.
Для успешной реализации нам потребуется задействовать несколько ключевых аппаратных и программных компонентов:
- Датчики протечки: Это "глаза" нашей системы. Они могут быть проводными, подключаемыми напрямую к универсальным входам (UI) контроллера, или беспроводными (например, Zigbee, LoRaWAN), передающими свой статус через соответствующий шлюз. Их задача — мгновенно зафиксировать наличие воды в нештатном месте.
- Шаровые краны с электроприводом: Это "руки" системы. При получении команды от контроллера они физически перекрывают магистрали горячего и холодного водоснабжения. В наших примерах мы будем рассматривать управление кранами с питанием 220В или 12/24В через релейные выходы (RL) контроллера.
- Контроллер HI: "Мозг" системы. Он выполняет всю логику: опрашивает датчики, принимает решения на основе полученных данных и отправляет команды на исполнительные устройства (краны). Вся логика, описываемая в данном уроке, будет реализована в среде Node-RED.
- Система оповещений: "Голос" системы. В случае аварии контроллер должен немедленно проинформировать владельца или обслуживающий персонал о происшествии через доступные каналы связи (Push-уведомления, Telegram, SMS).
Архитектурно сценарий FLOW-SAFETY-LEAK-PROTECTION относится к высшему приоритету в иерархии систем автоматизации. Он должен быть абсолютно надежным и отказоустойчивым. Сбой в работе системы комфорта (например, сценария управления освещением) приведет к неудобству. Сбой в работе системы безопасности может привести к катастрофическим последствиям и значительному финансовому ущербу. Именно поэтому при разработке потока мы будем уделять особое внимание обработке ошибок, верификации состояний и использованию надежных паттернов проектирования, рассмотренных в предыдущих курсах.
---
Подготовка оборудования и настройка MQTT-топиков
> 🔗 Связанный материал: Подробные инструкции по настройке MQTT-брокера на контроллерах HI и базовой интеграции устройств рассматривались в курсе COURSE-03-M02-L01. Мы предполагаем, что MQTT-брокер уже настроен и функционирует.
Перед тем как приступить к созданию логики в Node-RED, необходимо подготовить и проверить всю аппаратную часть.
Схемы подключения
* Один контакт датчика подключается к клемме `GND` контроллера.
* Второй контакт — к свободной клемме `UI`, например `UI05`.
* В конфигурации контроллера вход `UI05` настраивается на работу в режиме "сухой контакт".
* Нейтраль (N) от привода крана подключается к общей шине `N`.
* Общий провод привода (если есть) или фаза питания (L) подключается к клемме `C` (Common) одного реле, например `RL01`.
* Провод "Закрыть" подключается к клемме `NO` (Normally Open) реле `RL01`.
* Провод "Открыть" подключается к клемме `NO` реле `RL02`.
* Важно реализовать "защиту от дурака" на уровне логики, чтобы не подать напряжение на открытие и закрытие одновременно. В нашем сценарии мы будем просто подавать импульс на закрытие.
Проектирование структуры MQTT-топиков
Для унификации и удобства отладки будем придерживаться стандарта `MQTT Set/Status pattern`. Все устройства должны сообщать о своем состоянии в топики `.../status` и принимать команды в топики `.../set`.
| Устройство | Назначение | MQTT Топик | Пример `msg.payload` |
| --------------------------- | ------------------------------------------- | ----------------------------------------------- | -------------------- |
| Датчик протечки в ванной | Отправка состояния (протечка/сухо) | `hi/devices/leak_sensor_bathroom/status` | `"ON"` / `"OFF"` |
| Датчик протечки на кухне | Отправка состояния (протечка/сухо) | `hi/devices/leak_sensor_kitchen/status` | `"ON"` / `"OFF"` |
| Датчик протечки (беспроводной) | Отправка состояния через Zigbee2MQTT | `zigbee2mqtt/leak_sensor_laundry/water_leak` | `true` / `false` |
| Главный кран (ХВС) | Прием команды на открытие/закрытие | `hi/devices/water_valve_cold/set` | `"CLOSE"` / `"OPEN"` |
| Главный кран (ХВС) | Отправка текущего состояния (закрыт/открыт) | `hi/devices/water_valve_cold/status` | `"CLOSED"` / `"OPEN"`|
| Главный кран (ГВС) | Прием команды на открытие/закрытие | `hi/devices/water_valve_hot/set` | `"CLOSE"` / `"OPEN"` |
| Главный кран (ГВС) | Отправка текущего состояния (закрыт/открыт) | `hi/devices/water_valve_hot/status` | `"CLOSED"` / `"OPEN"`|
Проверка через командную строку
Перед сборкой потока убедитесь, что все компоненты корректно отправляют и принимают сообщения. Намочите контакты датчика в ванной и выполните команду на контроллере:
# Подписываемся на топик датчика
mqtt-cli sub -t 'hi/devices/leak_sensor_bathroom/status' -h localhost
# В ответ должно прийти сообщение "ON"
Теперь проверим управление краном:
# Отправляем команду на закрытие крана холодной воды
mqtt-cli pub -t 'hi/devices/water_valve_cold/set' -m 'CLOSE' -h localhost
Убедитесь, что кран физически начал закрываться.
---
Практика: Сборка основного потока в Node-RED
Создадим в редакторе Node-RED новую вкладку и назовем ее `FLOW-SAFETY-LEAK-PROTECTION`. На этой вкладке мы соберем основную логику реагирования на протечку.
ASCII-схема потока:
[mqtt in: leak_sensor_bathroom] --+
|
[mqtt in: leak_sensor_kitchen] ----+---> [rbe: filter duplicates] ---> [function: ALARM logic] --+--> [mqtt out: close cold valve]
| |
[mqtt in: leak_sensor_laundry] ---+ +--> [mqtt out: close hot valve]
|
+--> [link out: to NOTIFY flow]
Шаг 1: Подписка на топики датчиков
Шаг 2: Фильтрация дублирующихся сообщений
Шаг 3: Реализация основной логики
// Контракт_сообщения на входе:
// msg.topic (string) - топик, с которого пришло сообщение
// msg.payload (string|boolean) - "ON", "OFF", true, false
let payload = msg.payload;
// Приводим все возможные значения к булевому типу.
// Беспроводные датчики часто шлют 'true', проводные - 'ON'.
let isLeaking = (payload === 'ON' || payload === true);
// Если протечки нет (сообщение OFF/false), просто логируем и останавливаем поток.
if (!isLeaking) {
node.status({fill:"green", shape:"dot", text:"OK at " + new Date().toLocaleTimeString()});
return null; // Останавливаем дальнейшую обработку
}
// ------ ЛОГИКА ТРЕВОГИ ------
// Если мы дошли до сюда, значит, isLeaking === true
// 1. Получаем имя "зоны" из топика для информативности
let topic_parts = msg.topic.split('/');
// hi/devices/leak_sensor_bathroom/status -> leak_sensor_bathroom
let sourceDevice = topic_parts[2] || 'unknown_source';
// 2. Устанавливаем статус узла для визуальной диагностики
node.status({
fill: "red",
shape: "dot",
text: "ПРОТЕЧКА! Зона: " + sourceDevice + " в " + new Date().toLocaleTimeString()
});
// 3. Формируем единый объект аварии для дальнейшей обработки
msg.alarm = {
type: "LEAK_DETECTED",
source: sourceDevice,
timestamp: Date.now(),
original_payload: payload
};
// 4. Готовим payload для команды закрытия кранов.
// Краны ожидают команду "CLOSE".
msg.payload = "CLOSE";
// Возвращаем сообщение. Оно пойдет на все последующие узлы.
return msg;
Этот код реализует Паттерн "Контракт сообщения" и "Визуальный статус", позволяя четко отслеживать состояние системы.
Шаг 4: Отправка команд на закрытие кранов
* `Topic`: `hi/devices/water_valve_cold/set`
* `Name`: "Закрыть кран ХВС"
* `Topic`: `hi/devices/water_valve_hot/set`
* `Name`: "Закрыть кран ГВС"
Теперь, при срабатывании любого датчика, поток отправит команду `"CLOSE"` в топики управления обоими кранами.
---
Практика: Интеграция системы оповещений и управление состояниями
После того как краны перекрыты, необходимо немедленно уведомить пользователя и перевести всю систему в аварийное состояние.
> 💡 Подсказка: Используйте `node-red-contrib-moment` для добавления в сообщение об аварии временной метки в человекочитаемом формате. Это упрощает последующий анализ логов и уведомлений.
Шаг 1: Формирование сообщения для отправки
// На входе этого узла у нас есть объект msg.alarm,
// который мы сформировали в предыдущем узле.
let alarmInfo = msg.alarm;
// Формируем человекочитаемое сообщение
let friendlyMessage = `🚨 ВНИМАНИЕ: СИСТЕМА ЗАЩИТЫ ОТ ПРОТЕЧЕК! 🚨
Обнаружена протечка воды!
💧 Зона: ${alarmInfo.source}
⏰ Время: ${new Date(alarmInfo.timestamp).toLocaleString('ru-RU')}
Водоснабжение на объекте автоматически перекрыто.
Требуется ваше вмешательство для проверки и устранения причины.`;
// Помещаем его в msg.payload, т.к. узлы-отправщики
// (Telegram, Push) обычно берут текст из payload.
msg.payload = friendlyMessage;
// Также устанавливаем системный флаг аварии.
// Это позволит другим сценариям (например, насосной станции)
// узнать о проблеме и не включаться.
global.set('SYSTEM_STATE_LEAK_ALARM', true);
global.set('SYSTEM_STATE_LEAK_SOURCE', alarmInfo.source);
return msg;
Шаг 2: Отправка уведомления
Шаг 3: Блокировка других сценариев
Благодаря строке `global.set('SYSTEM_STATE_LEAK_ALARM', true)` мы создали глобальный флаг, который можно проверить в любом другом потоке. Например, в сценарии повышения давления воды можно добавить узел `switch`, который будет проверять значение `global.get('SYSTEM_STATE_LEAK_ALARM')`. Если оно `true`, насос не должен включаться, чтобы не усугубить ситуацию и не сгореть, работая "всухую". Это пример управления состояниями на уровне всей системы.
---
Логика сброса аварии и защита от ложных срабатываний
Система не должна оставаться в аварийном режиме вечно. После того как причина протечки устранена, пользователю необходим простой и понятный способ вернуть водоснабжение.
> ⚠️ Внимание: Сценарий перекрытия воды является критически важным. Не устанавливайте большую задержку перед срабатыванием — это может привести к реальному ущербу. Оптимальное значение — 1-3 секунды, чтобы отсечь "дребезг" контактов датчика.
Защита от ложных срабатываний ("дребезга")
При влажной уборке или случайном попадании брызг датчик может кратковременно сработать. Чтобы избежать ненужного перекрытия воды, добавим небольшую задержку.
* `Send`: `nothing` (сначала ничего не отправлять).
* `then wait for`: `2 seconds`.
* `then send`: `the latest message`.
* `Handling incoming messages`: `while waiting, extend the delay`.
Теперь, если от датчика придет `ON`, узел `trigger` подождет 2 секунды. Если за это время придет `OFF`, таймер сбросится, и авария не будет активирована. Если же через 2 секунды сигнал `ON` все еще актуален, сообщение пойдет дальше по цепочке.
Создание интерфейса и логики сброса
ASCII-схема логики сброса:
[dashboard: button "RESET"] --> [function: Check all sensors] --(all OK)--> [function: Build OPEN command] --+--> [mqtt out: open cold valve]
| |
+--(sensors not OK)--> [function: Notify "CAN'T RESET"] --> [Notify user] +--> [mqtt out: open hot valve]
|
+--> [function: Reset Global Flag] --> [Notify user: "System is OK"]
Логика узла "Check all sensors" (`function`):
// 1. Получаем текущие состояния ВСЕХ датчиков протечки из контекста.
// Предполагается, что у вас есть отдельный поток, который
// сохраняет последнее состояние каждого датчика в flow-контекст.
// (см. паттерн "Конечный автомат" / FSM).
let bathroom_state = flow.get("leak_sensor_bathroom_state") || false;
let kitchen_state = flow.get("leak_sensor_kitchen_state") || false;
let laundry_state = flow.get("leak_sensor_laundry_state") || false;
// 2. Проверяем, что ВСЕ датчики "сухие"
if (bathroom_state === true || kitchen_state === true || laundry_state === true) {
// Если хотя бы один датчик все еще мокрый, сброс невозможен.
// Отправляем сообщение на второй выход (ошибка).
msg.payload = "Сброс невозможен! Один или несколько датчиков все еще фиксируют протечку.";
return [null, msg];
}
// 3. Если все датчики в норме, отправляем сообщение на первый выход (успех).
msg.payload = "OPEN"; // Команда для открытия кранов
return [msg, null];
Логика узла "Reset Global Flag" (`function`):
// Сбрасываем глобальные флаги
global.set('SYSTEM_STATE_LEAK_ALARM', false);
global.set('SYSTEM_STATE_LEAK_SOURCE', 'none');
msg.payload = "✅ Система защиты от протечек возвращена в штатный режим. Водоснабжение восстановлено.";
return msg;
Дальнейшие узлы этого потока должны отправить команду `"OPEN"` на краны, а затем отправить пользователю уведомление о том, что система нормализована.
---
Итоги и рекомендации по отказоустойчивости
В рамках этого урока мы cоздали полноценный, многокомпонентный и отказоустойчивый сценарий FLOW-SAFETY-LEAK-PROTECTION. Мы реализовали:
- Сбор данных с разнотипных датчиков по протоколу MQTT.
- Надежную логику принятия решения с защитой от ложных срабатываний.
- Управление исполнительными устройствами (шаровыми кранами).
- Мгновенную систему оповещений пользователя.
- Механизм управления глобальными состояниями и безопасного сброса аварии.
Для обеспечения максимальной надежности системы на реальном объекте следуйте дополнительным рекомендациям:
* Датчики протечки устанавливайте в самых низких точках пола, под потенциальными источниками утечек: под мойкой, ванной, за стиральной и посудомоечной машинами, у коллекторного узла.
* Шаровые краны устанавливайте на вводе водоснабжения в квартиру/дом после ручных вентилей и фильтров грубой очистки. Обеспечьте к ним легкий доступ для обслуживания и ручного управления.
* Не реже одного раза в квартал проводите полное тестирование сценария. Имитируйте протечку, закоротив контакты датчика влажной губкой. Убедитесь, что краны закрылись, а уведомление пришло.
* Проверяйте состояние элементов питания в беспроводных датчиках. Хороший сценарий будет включать мониторинг `battery_low` и заблаговременные оповещения.
* Периодически запускайте ручное открытие/закрытие кранов, чтобы предотвратить их "закисание".
* Как мы обсуждали в уроке 'Реализация на ARM32/ПЛК для критичных сценариев', для объектов с повышенными требованиями к безопасности логика перекрытия воды должна быть продублирована. Поток в Node-RED является верхним, удобным для пользователя уровнем. Основная, неотключаемая логика `(Датчик Сработал -> Закрыть Кран)` должна быть реализована на более низком, детерминированном уровне ПЛК, который предлагает контроллер HI. Это гарантирует срабатывание защиты даже в случае сбоя или перезагрузки операционной системы Debian и среды Node-RED.
Что дальше
В следующем уроке мы рассмотрим реализацию другого важного сценария безопасности: `SCN-SAFETY-003: Контроль датчиков дыма/газа`, который имеет схожие принципы построения (обнаружение, действие, оповещение), но обладает своей спецификой, связанной с типами датчиков и требуемыми действиями в случае тревоги.