ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → SCN-SAFETY-015: Аварийное освещение (включение света при срабатывании датчиков безопасности)

SCN-SAFETY-015: Аварийное освещение (включение света при срабатывании датчиков безопасности)

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

Введение в сценарий "Аварийное освещение"

Аварийное освещение в контексте умного дома — это не просто резервный свет на случай отключения электричества. Это активный компонент комплексной системы безопасности, задача которого — немедленно и однозначно реагировать на тревожные события, обеспечивая визуальную информацию и помогая сориентироваться в потенциально опасной ситуации. В отличие от строго регламентированного эвакуационного освещения, которое регулируется государственными нормативами (ГОСТ, СНиП) и предназначено для безопасного покидания здания, наш сценарий преследует иные цели:
  • Информационная функция: Яркий, повсеместно включенный свет является первым и самым очевидным сигналом тревоги для находящихся в доме людей. Он мгновенно привлекает внимание к нештатной ситуации.
  • Дезориентация нарушителя: При срабатывании охранных датчиков внезапное включение всего света на объекте оказывает сильный психологический эффект на злоумышленника и лишает его преимущества темноты.
  • Подготовка к действию: В случае пожара или утечки газа освещение помогает быстро оценить обстановку, найти средства пожаротушения, документы и безопасно двигаться к выходу, даже если основное сознание занято анализом угрозы.
  • Содействие внешним службам: Яркий свет в окнах и на придомовой территории помогает службам быстрого реагирования (пожарные, полиция) сориентироваться по прибытии на объект.
  • Сценарий активируется по нескольким типам триггеров, каждый из которых сигнализирует о событии с высоким уровнем приоритета:

    Этот сценарий является частью единой экосистемы безопасности. Его активация должна инициировать цепочку связанных действий, таких как перекрытие потенциально опасных коммуникаций (газ, приточная вентиляция), отправка push-уведомлений или SMS владельцу, включение сирены и, как мы увидим далее, получение абсолютного приоритета над всеми прочими сценариями управления светом.

    ---

    Архитектура решения: от датчика к светильнику

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

    > 🔗 Связанный материал: Для понимания базовых принципов работы с MQTT и настройки брокера на контроллере HI, обратитесь к материалам модуля COURSE-03-M02.

    Аппаратные компоненты системы

    | Компонент | Примеры устройств | Протокол/Шина подключения к контроллеру HI | Роль в сценарии |

    | -------------------- | -------------------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |

    | Датчики дыма/газа | Болид ДИП-34А, Астра-421, System Sensor 2951J | Modbus RTU (через модуль расширения), "Сухой контакт" | Триггер тревоги типа "Пожар" или "Газ". |

    | Охранные датчики | Gira KNX Motion Detector, герконы на дверях/окнах | KNX, "Сухой контакт" (на входы UI контроллера) | Триггер тревоги типа "Вторжение". |

    | Тревожные кнопки | Настенные кнопки, носимые брелоки (Zigbee/BLE) | "Сухой контакт", Zigbee (через шлюз) | Триггер тревоги типа "Паника" для ручной активации. |

    | Исполнители | Релейные выходы контроллера HI, KNX-актуаторы, DALI-драйверы | Реле, KNX, DALI (через шлюз) | Физическое включение осветительных приборов на 100% яркости. |

    Стандартизация MQTT-событий

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

    Стандарт топика: `hi/events/security//`
    • ``: Логическая зона объекта (например, `kitchen`, `living_room`, `hall_floor1`).
    • ``: Тип датчика (например, `smoke`, `gas_co`, `motion`, `door`, `panic`).
    Стандарт контракта сообщения (`msg.payload`):

    При срабатывании датчик должен отправить JSON-сообщение со значением `true`. При возвращении в норму — `false`.

    Пример сообщения от датчика дыма на кухне:

    • Топик: `hi/events/security/kitchen/smoke`
    • Payload (тревога):
    {
    

    "value": true,

    "source": "modbus-smoke-sensor-01",

    "ts": 1678886400000

    }

    • Payload (норма):
    {
    

    "value": false,

    "source": "modbus-smoke-sensor-01",

    "ts": 1678886900000

    }

    Для реализации этой логики необходимо предварительно настроить на контроллере HI соответствующие потоки-драйверы. Например, поток, который опрашивает Modbus-датчик дыма, при получении от него тревожного значения должен сформировать и опубликовать указанное выше MQTT-сообщение. Аналогично для датчиков, подключенных к "сухим контактам" или работающим по KNX. Этот уровень абстракции позволяет основному сценарию аварийного освещения не зависеть от физического способа подключения датчиков.

    ---

    Реализация в Node-RED: обработка тревожных сигналов

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

    > 💡 Подсказка: Используйте wildcard-подписку (например, `hi/events/security/+/+`) в ноде `mqtt in` для одновременного прослушивания всех датчиков безопасности. Это упрощает масштабирование системы без изменения логики потока.

    Создадим следующий поток:

    [mqtt in] --> [json] --> [rbe] --> [function: Prepare Standard Alarm] --> [link out: To Light Control]
    

    |

    +-- (invalid json) --> [catch] --> [log]

    Шаг 1: Подписка и фильтрация

  • Добавьте узел `mqtt in`. Настройте его на топик `hi/events/security/+/+` с выводом `a parsed JSON object` и QoS `2`.
  • Сразу после него поставьте узел `json` для надежного парсинга и `rbe` (report by exception). `rbe` будет блокировать дублирующиеся сообщения (например, если датчик постоянно шлет `true`), пропуская только изменение состояния (`false` -> `true` или `true` -> `false`). Это защищает систему от лишней нагрузки.
  • Шаг 2: Формирование стандартизированного сообщения о тревоге

    Ключевая задача этого этапа — извлечь из MQTT-топика тип тревоги и зону, а также определить, является ли событие активацией тревоги или ее отменой. Затем мы формируем унифицированный объект `msg`, который будет использоваться в последующей логике. Подключите к `rbe` узел `function` с именем "Prepare Standard Alarm".

    // Код для узла "function: Prepare Standard Alarm"
    
    

    // Получаем состояние из исходного сообщения: true - тревога, false - норма

    const isAlarmActive = msg.payload.value;

    // Разбираем топик, чтобы получить зону и тип датчика

    // Пример msg.topic: "hi/events/security/living_room/smoke"

    const parts = msg.topic.split('/');

    if (parts.length < 5) {

    node.error("Некорректный формат топика: " + msg.topic, msg);

    return null;

    }

    const zone = parts[3];

    const sensorType = parts[4];

    // Определяем тип тревоги

    let alarmType = 'unknown';

    if (sensorType === 'smoke' || sensorType === 'gas_co' || sensorType === 'temp_high') {

    alarmType = 'fire';

    } else if (sensorType === 'motion' || sensorType === 'door' || sensorType === 'window') {

    alarmType = 'intrusion';

    } else if (sensorType === 'panic') {

    alarmType = 'panic';

    }

    // Формируем новый, стандартизированный payload для дальнейшей обработки

    msg.payload = {

    alarm: isAlarmActive, // true (тревога) или false (сброс)

    type: alarmType,

    zone: zone,

    source_topic: msg.topic,

    original_payload: msg.payload // Сохраняем исходное сообщение для отладки

    };

    // Устанавливаем статус узла для визуальной диагностики

    if (isAlarmActive) {

    node.status({

    fill: "red",

    shape: "dot",

    text: `ALARM: ${alarmType.toUpperCase()} in ${zone}`

    });

    } else {

    node.status({

    fill: "green",

    shape: "dot",

    text: `CLEAR: ${alarmType.toUpperCase()} in ${zone}`

    });

    }

    return msg;

    Этот узел-функция является сердцем первичной обработки. Он преобразует разрозненные сигналы от датчиков в единый, понятный для системы формат, сообщая не только о типе и месте тревоги, но и о её состоянии (активна или снята). Полученное сообщение мы отправляем дальше по цепочке с помощью узла `link out` в поток управления освещением.

    ---

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

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

    > ⚠️ Внимание: Всегда используйте отдельные, зарезервированные групповые адреса (ГА) для аварийных сценариев в KNX. Не пересекайте их с ГА для повседневного управления (например, от выключателей), чтобы избежать логических конфликтов и цикличных команд.

    Рассмотрим, как подготовить сообщение для шлюза, который затем уже сам отправит команду в нужную шину (например, KNX).

    Динамический выбор групп света

    Стратегия аварийного освещения может быть разной. Самый простой вариант — включить абсолютно весь свет в здании. Более сложный и целесообразный — включить свет в зоне сработки датчика и всех смежных зонах (пути эвакуации). Реализуем второй вариант с помощью узла `function`.

    Этот узел будет принимать на вход наше стандартизированное сообщение о тревоге и, на основе `msg.payload.zone` и `msg.payload.alarm`, формировать сообщения для шлюза.

    // Код для узла "function: Map Zone to Lights"
    
    

    const zone = msg.payload.zone;

    const alarmType = msg.payload.type;

    const state = msg.payload.alarm; // true для включения, false для выключения

    // Создаем карту соответствия зон и логических идентификаторов устройств/групп,

    // которыми управляет "Шлюз приоритетов".

    // В реальном проекте эту карту лучше вынести в глобальный контекст.

    const lightZoneMap = {

    "kitchen": ["light_kitchen_main", "light_kitchen_spot"],

    "living_room": ["light_living_main", "light_living_spots"],

    "hall_floor1": ["light_hall_1"],

    "hall_floor2": ["light_hall_2"],

    "all_halls": ["light_hall_1", "light_hall_2"],

    "all_lights": ["group_all_lights"] // Логическая группа для всего света

    };

    let targetDevices = [];

    // Логика выбора групп света

    // При пожаре управляем ВСЕМ светом для максимальной видимости

    if (alarmType === 'fire' || alarmType === 'gas' || alarmType === 'panic') {

    targetDevices.push(lightZoneMap.all_lights[0]);

    }

    // При вторжении включаем свет в зоне вторжения и на путях эвакуации (коридоры)

    else if (alarmType === 'intrusion') {

    if (lightZoneMap[zone]) {

    targetDevices = targetDevices.concat(lightZoneMap[zone]);

    }

    targetDevices = targetDevices.concat(lightZoneMap.all_halls);

    }

    // Если не найдено специфических правил, на всякий случай управляем всем светом

    if (targetDevices.length === 0) {

    targetDevices.push(lightZoneMap.all_lights[0]);

    }

    // Устанавливаем высокий приоритет для аварийного сценария

    const priority = 2;

    // Формируем массив сообщений для отправки в "Шлюз приоритетов"

    const outputMessages = targetDevices.map(deviceID => {

    return {

    // Топик, который слушает шлюз управления

    topic: `hi/control/${deviceID}/set`,

    payload: {

    value: state, // true (включить) или false (выключить)

    priority: priority,

    source: `emergency-scenario-${alarmType}` // Источник для отладки

    }

    };

    });

    // Отправляем массив сообщений на выход.

    // Node-RED отправит каждое из них как отдельное сообщение.

    return [outputMessages];

    После этого `function`-узла разместите узел `mqtt out`, настроенный на ваш MQTT-брокер (поле Topic можно оставить пустым). Функция возвращает массив сообщений, и Node-RED автоматически отправит каждое из них как отдельное сообщение. Каждое сообщение будет опубликовано в свой MQTT-топик (например, `hi/control/group_all_lights/set`). Эти сообщения будут получены и обработаны централизованным "Шлюзом приоритетов", который, в свою очередь, уже отправит физическую команду в шину (KNX, DALI и т.д.).

    ---

    Приоритеты и интеграция со Шлюзом Управления

    Активация аварийного освещения — событие наивысшего приоритета. Никакие другие сценарии или действия пользователя (например, нажатие на выключатель "Выключить все") не должны ему помешать.

    > ℹ️ Информация: Механизм приоритетов, который мы здесь используем, является практическим применением архитектурного паттерна «Шлюз приоритетов», изученного в уроке SCN-ARCH-010 «Паттерны управления состоянием и приоритетами». Рекомендуется ознакомиться с ним для полного понимания.

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

    Принцип работы через Шлюз приоритетов

  • Отправка команды: Наш сценарий "Аварийное освещение" не управляет светом напрямую. Вместо этого он формирует стандартизированное сообщение и отправляет его в MQTT-топик, который прослушивает Шлюз приоритетов (например, `hi/control/+/set`).
  • Содержание команды: Сообщение содержит три ключевых элемента:
  • * Цель (`topic`): Логический идентификатор устройства или группы (например, `hi/control/group_all_lights/set`).

    * Действие (`payload.value`): `true` (включить) или `false` (выключить).

    * Приоритет (`payload.priority`): Числовое значение. Для аварийных сценариев мы используем высокий приоритет, например `2`. Для обычных сценариев (выключатели, датчики движения) используется низкий приоритет, например `0` или `1`.

  • Логика шлюза:
  • * Получив нашу команду с `priority: 2`, шлюз немедленно её выполняет (включает свет) и "захватывает" управление группой света на уровне `2`.

    * Пока захват активен, любые команды для этой же группы света, приходящие с более низким приоритетом (например, от настенного выключателя с `priority: 0`), будут шлюзом проигнорированы. Свет останется включенным.

  • Снятие блокировки: Чтобы вернуть управление в штатный режим, необходимо отменить тревогу. Сценарий должен отправить команду на выключение (`value: false`) для той же группы света и с тем же высоким приоритетом (`priority: 2`). Получив такую команду, шлюз выключит свет и освободит "захват", позволив снова работать командам с низким приоритетом.
  • Этот подход избавляет от необходимости модифицировать каждый низкоприоритетный сценарий, добавляя в него проверку флага. Вся логика приоритетов инкапсулирована в одном месте — в Шлюзе управления.

    ---

    Итоги и рекомендации по тестированию

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

    Ключевые этапы созданного потока:

  • Сбор данных: `mqtt in` с wildcard-подпиской собирает все сигналы тревоги.
  • Валидация и стандартизация: `rbe` и `function` узел отсеивают дубли, определяют тип, место и состояние тревоги (активна/снята) и формируют единый объект `msg`.
  • Установка приоритета: Формируется сообщение с высоким приоритетом (`priority: 2`) для "Шлюза управления".
  • Исполнение: `function`-узел-маршрутизатор выбирает целевые группы освещения и формирует сообщения, которые через `mqtt out` отправляются в "Шлюз приоритетов" для исполнения.
  • Чек-лист для обязательного тестирования

    Перед сдачей объекта в эксплуатацию необходимо провести полное тестирование сценария.

    • [ ] Имитация тревоги "Пожар": Активируйте (тестовой кнопкой или специальным аэрозолем) датчик дыма. Убедитесь, что включился весь свет в здании.
    • [ ] Имитация тревоги "Вторжение": Включите режим "Охрана" и активируйте датчик движения или открытия двери. Проверьте, что свет включился в целевой и смежных зонах (согласно вашей логике).
    • [ ] Проверка ручной тревоги: Нажмите тревожную кнопку. Убедитесь, что реакция аналогична тревоге "Пожар".
    • [ ] Проверка блокировки: Во время активной тревоги попробуйте выключить свет с настенного выключателя или через сценарий "Выключить все" (которые отправляют команды с низким приоритетом). Свет должен остаться включенным.
    • [ ] Проверка сброса режима: Имитируйте возврат датчика в норму. Убедитесь, что аварийное освещение выключилось (с помощью команды с высоким приоритетом), и управление светом вернулось в штатный режим (низкоприоритетные команды снова работают).
    • [ ] Проверка граничных условий: Протестируйте реакцию системы на быстрые последовательные срабатывания/отключения датчика (проверка работы узла `rbe`).

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

    Что дальше

    Созданный сценарий можно и нужно развивать:

    • Звуковое оповещение: Параллельно с включением света можно активировать сирену или транслировать голосовые сообщения через аудиосистему.
    • Push-уведомления: Интегрируйте отправку мгновенных уведомлений на смартфоны владельцев с указанием типа и зоны тревоги.
    • Интеграция с видеонаблюдением: При срабатывании охранного датчика можно дать команду системе видеонаблюдения повернуть камеру в нужную точку и начать запись.
    • Визуализация: Выведите состояние "захвата" устройства из "Шлюза приоритетов" на главную панель управления, чтобы пользователь всегда видел, что свет заблокирован аварийным сценарием.