ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → SCN-LIGHT-023: Ночная подсветка (коридоры, санузлы) на 15% яркости

SCN-LIGHT-023: Ночная подсветка (коридоры, санузлы) на 15% яркости

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

Концепция и ценность ночной подсветки

Сценарий ночной подсветки, `SCN-LIGHT-023`, является классическим примером того, как автоматизация переходит от простого удобства к созданию по-настоящему комфортной и безопасной среды обитания. Стандартное включение света по движению на полную яркость, которое идеально подходит для дневного времени, становится раздражающим и даже опасным фактором ночью. Представьте, что вы или ваш ребенок просыпаетесь посреди ночи и идете в санузел. Внезапный удар яркого света по глазам не только вызывает дискомфорт и полностью сбивает сон, но и может на мгновение ослепить, что особенно опасно на лестницах и в коридорах.

Ценность сценария "Ночная подсветка" строится на трех ключевых аспектах:
  • Безопасность: Мягкий, приглушенный свет на уровне 10-15% яркости достаточен, чтобы уверенно ориентироваться в пространстве, видеть препятствия и ступени, но не ослепляет. Это критически важно для семей с маленькими детьми или пожилыми людьми, для которых риск падения в темноте или при временной дезориентации от яркого света особенно высок.
  • Комфорт: Сценарий сохраняет "атмосферу сна". Приглушенный свет не нарушает выработку мелатонина (гормона сна), позволяя человеку быстро вернуться в постель и снова заснуть. Это создает ощущение заботы и продуманности жилого пространства. Пропадает необходимость искать настенный выключатель в темноте или использовать фонарик на смартфоне.
  • Энергосбережение: Хотя основная цель — комфорт, экономия энергии является приятным бонусом. Работа светодиодных светильников на 15% мощности вместо 100% в течение всех ночных часов в проходных зонах приводит к значительному снижению энергопотребления. В масштабах большого коттеджа или гостиницы этот эффект становится экономически ощутимым.
  • Ключевое отличие этого сценария от ранее рассмотренного `SCN-LIGHT-001` (Включение света по движению с учетом освещенности) заключается во введении контекста состояния системы. Мы больше не принимаем решение только на основе триггера (движение) и простого условия (освещенность). Мы добавляем третий, более сложный фактор — глобальный режим "Ночь". Именно этот режим кардинально меняет логику работы автоматизации.

    Типовые зоны применения:

    Реализация этого сценария на платформе HI требует не только работы с датчиками и исполнительными устройствами, но и грамотного управления состоянием (State Management) на уровне всего проекта автоматизации.

    ---

    Управление состоянием: Техническая реализация "Ночного режима"

    Как мы подробно рассмотрели в уроке COURSE-07-M02-L01, глобальный контекст является единым источником правды для всей системы автоматизации. Для того чтобы сценарий `SCN-LIGHT-023` работал корректно, контроллер должен в любой момент времени однозначно "знать", активен ли сейчас ночной режим. Это реализуется с помощью глобальной переменной состояния, доступной для всех потоков (flows) в Node-RED.

    🔗 Связанный материал: Для сохранения состояния между перезагрузками необходимо использовать персистентный контекст. Его настройка в файле `settings.js` подробно рассмотрена в уроке [ID нового урока про FSM, например, COURSE-07-M01-L01].

    Способы активации и деактивации "Ночного режима"

    Существует несколько подходов к управлению состоянием `global.night_mode`. В профессиональных инсталляциях их часто комбинируют.

  • По расписанию: Самый простой способ. Например, с 23:00 до 07:00. Реализуется с помощью узлов `Inject`, настроенных на срабатывание в определенное время. Один узел устанавливает `global.set("night_mode", true, "persistent")`, второй — `global.set("night_mode", false, "persistent")`.
  • По астрономическому таймеру: Более продвинутый вариант. Режим включается после заката (`sunset`) и выключается на рассвете (`sunrise`). Это позволяет автоматически адаптировать график к изменению времени года. Для этого используются специализированные узлы, такие как `node-red-contrib-sun-position` или аналогичные, которые рассчитывают время заката/рассвета для заданных географических координат.
  • По ручной команде: Самый гибкий и ориентированный на пользователя способ. Режим "Ночь" активируется как часть более крупного сценария, например, "Спокойной ночи", "Я ложусь спать" или при постановке дома на охрану. Команда может прийти от настенной панели, мобильного приложения или голосового ассистента.
  • Использование MQTT для широковещательной рассылки состояния

    Хотя мы храним состояние в глобальной переменной, лучшей практикой является дублирование изменения этого состояния в MQTT-брокере, который работает на контроллере HI. Это соответствует паттерну "событийно-ориентированной архитектуры" и дает огромные преимущества в масштабировании системы.

    Поток управления состоянием может выглядеть так:

    // Flow: Управление ночным режимом
    

    [Inject: 23:00] --+

    |--> [Function: Set Night ON] --> [MQTT Out: hi/state/night_mode]

    [MQTT In] --------+

    [Inject: 07:00] --+

    |--> [Function: Set Night OFF] -> [MQTT Out: hi/state/night_mode]

    [MQTT In] --------+

    В узле `Function: Set Night ON` пишется следующий код:

    // Устанавливаем персистентную глобальную переменную
    

    global.set("night_mode", true, "persistent");

    // Формируем сообщение для MQTT по стандартному контракту

    msg.payload = {

    "value": true,

    "source": "scheduler",

    "ts": Date.now()

    };

    // Устанавливаем флаг retain, чтобы новые подписчики сразу получали актуальное состояние

    msg.retain = true;

    node.status({fill:"blue", shape:"dot", text:"Ночной режим: ВКЛ"});

    return msg;

    Теперь любой другой сценарий (не только ночной подсветки, но и, например, управления шторами или фоновой музыкой) может просто подписаться на MQTT-топик `hi/state/night_mode` и реагировать на изменение состояния системы, не обращаясь напрямую к глобальной переменной. Это делает систему более модульной и отказоустойчивой.

    ---

    Практика в Node-RED: Сборка потока автоматизации

    Теперь соберём основной поток сценария `SCN-LIGHT-023`, который будет использовать созданный нами "Ночной режим". Поток будет слушать сообщения от датчиков движения и, в зависимости от состояния `global.night_mode`, отправлять разные команды на светильники.

    Структура потока

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

    ASCII-схема потока (FLOW-AUTO-LIGHT-012):
                                           +----------------------------------+
    

    | 1. if global.night_mode == true |

    [MQTT In: hi/sensors/motion/+] --+---> [Switch: "Проверка ночного режима"] --+---> [Change: "Установить 15%"] ---> [MQTT Out: hi/lights/corridor/set]

    | +----------------------------------+ |

    | |

    | +----------------------------------+ |

    +---> [ (otherwise) ] --+---> [Change: "Установить 100%"] --> [MQTT Out: hi/lights/corridor/set]

    +----------------------------------+

    > 🔗 Связанный материал: Общая структура этого потока похожа на логику, рассмотренную в уроке `SCN-LIGHT-005` (Управление диммированием в зависимости от времени суток), но вместо проверки точного времени мы используем более гибкий механизм глобального состояния.

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

  • Узел `MQTT In` (Триггер от датчика):
  • * Topic: `hi/sensors/motion/+` — подписываемся на все датчики движения в системе. `+` является одноуровневым wildcard.

    * QoS: `1` — для гарантированной доставки сообщения.

    * Output: `a parsed JSON object` — ожидаем, что датчик присылает данные в формате JSON, например `{"value": true}`.

  • Узел `Switch` (Ветвление логики):
  • * Name: "Проверка ночного режима".

    * Property: `global.night_mode` — выбираем проверку значения из глобального контекста.

    * Правила:

    * Правило 1: `is true` (`== true`). Это будет первый выход узла, ведущий к логике ночной подсветки.

    * Правило 2: `otherwise`. Это будет второй выход, который сработает во всех остальных случаях (когда `night_mode` равно `false` или не определено).

  • Узел `Change` (Формирование команды для ночного режима):
  • * Name: "Установить 15%".

    * Rules: Настраиваем правило для формирования нового `msg.payload`.

    * Set: `msg.payload`

    * to: `expression` (тип JSONata).

    * Выражение JSONata:

            {

    "command": "setBrightness",

    "value": 15,

    "transition": 2

    }

    > ℹ️ Информация: Здесь мы формируем стандартизированный `payload`. `command` указывает действие, `value` — процент яркости, а `transition` (опционально) — время плавного включения в секундах, что добавляет комфорта.

  • Узел `Change` (Формирование команды для дневного режима):
  • * Name: "Установить 100%".

    * Rules: Аналогично предыдущему узлу, но с другими значениями.

    * Set: `msg.payload`

    * to: `expression` (тип JSONata).

    * Выражение JSONata:

            {

    "command": "setBrightness",

    "value": 100,

    "transition": 0.5

    }

  • Узел `MQTT Out` (Отправка команды актуатору):
  • * Topic: Важно сделать топик динамическим, чтобы команда отправлялась именно тому светильнику, в зоне которого сработал датчик. Если топик датчика `hi/sensors/motion/corridor_1`, то топик светильника должен быть `hi/lights/corridor_1/set`. Это можно сделать, если датчики и светильники имеют согласованные ID.

    * Если топик датчика `hi/sensors/motion/corridor_1`, то мы можем извлечь `corridor_1` и подставить в исходящий топик.

    * Topic (пример): `hi/lights/{{topic.split('/')[3]}}/set` (этот синтаксис зависит от узла, возможно, потребуется `Function` для формирования топика).

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

    ---

    Работа с оборудованием: Формирование команд для DALI, KNX и Modbus

    Собранный нами поток в Node-RED формирует универсальное сообщение-намерение (`{"command": "setBrightness", "value": 15}`). Однако, чтобы реальное оборудование — светильник DALI или релейный модуль Modbus — выполнило эту команду, это сообщение нужно преобразовать в низкоуровневый формат, понятный конкретному протоколу.

    > 💡 Подсказка: Для инкапсуляции логики управления разными протоколами (DALI, KNX, Modbus) рекомендуется создавать субпотоки (subflows). Создайте субпоток "DALI Dimmer Control", который на вход принимает наше универсальное сообщение, а на выходе формирует специфичный для DALI `payload`. Это делает основной поток сценария более читаемым и позволяет легко переиспользовать код управления оборудованием.

    Рассмотрим, как может выглядеть логика преобразования внутри таких субпотоков для разных систем.

    | Протокол | Описание | Пример `msg.payload` для отправки в узел протокола |

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

    | DALI | Для управления диммированием используется команда `DAPC` (Direct Arc Power Control), которая принимает значение от 0 до 254. 15% от 254 ≈ 38. | `{"address": "G1", "command": "DAPC", "value": 38}` (G1 - группа светильников) |

    | KNX | Команда отправляется в групповой адрес (GA), связанный с функцией диммирования. Используется стандартизированный тип данных `DPT 5.001` (Scaling 0-100%). | `{"dpt": "5.001", "payload": 15}` (отправляется в GA, например, 1/1/10) |

    | Modbus | Значение яркости записывается в предопределенный Holding Register. Диапазон значений зависит от производителя (0-100, 0-255, 0-1000). | `{"value": 150, "fc": 6, "unitid": 5, "address": 1024}` (для диапазона 0-1000) |

    | MQTT-диммер | Многие "умные" диммеры (Zigbee, Wi-Fi) поддерживают управление через MQTT с JSON-пейлоадом, похожим на стандарт Home Assistant. | `{"brightness": 38, "state": "ON"}` (для диапазона яркости 0-255) |

    Пример потока-транслятора для DALI

    Этот поток подписывается на универсальный топик и преобразует команду в формат DALI.

    [MQTT In: hi/lights/corridor/set] --> [Function: "Convert to DALI"] --> [node-red-contrib-dali-out]
    
    Код узла `Function: "Convert to DALI"`:
    // msg.payload на входе: { "command": "setBrightness", "value": 15 }
    

    let brightnessPercent = msg.payload.value;

    // Проверка на корректность входных данных

    if (typeof brightnessPercent !== 'number' || brightnessPercent < 0 || brightnessPercent > 100) {

    node.error("Неверное значение яркости: " + brightnessPercent, msg);

    return null;

    }

    // Преобразуем проценты в шкалу DALI (0-254)

    // Если яркость 0, отправляем команду OFF, иначе DAPC

    if (brightnessPercent === 0) {

    msg.payload = {

    command: "OFF"

    };

    } else {

    let daliValue = Math.round((brightnessPercent / 100) * 254);

    msg.payload = {

    command: "DAPC",

    value: daliValue

    };

    }

    // Адрес группы светильников может быть жестко задан или взят из контекста

    msg.address = "G1"; // Например, группа "Коридоры"

    return msg;

    Такой подход с разделением логики сценария и логики управления оборудованием является краеугольным камнем профессиональной разработки систем автоматизации. Он позволяет легко заменять оборудование (например, светильники Modbus на DALI), не затрагивая основной сценарий ночной подсветки.

    ---

    Итоги, проверка и возможные улучшения

    В этом уроке мы разработали один из самых востребованных сценариев умного дома — `SCN-LIGHT-023: Ночная подсветка`. Мы вышли за рамки простой автоматизации "триггер-действие" и внедрили контекстную логику, основанную на глобальном состоянии системы.

    Ключевая логика сценария:
  • Триггер: Сообщение от датчика движения.
  • Условие: Проверка глобальной персистентной переменной `global.night_mode`.
  • Действие:
  • * Если "Ночь" (`true`): отправить команду на включение света на низкой яркости (15%).

    * Если "День" (`false`): отправить команду на включение света на полной яркости (100%).

    Мы также рассмотрели, как транслировать это универсальное намерение в команды для конкретных протоколов, таких как DALI, KNX и Modbus, подчеркнув важность использования субпотоков для инкапсуляции этой логики.

    Чек-лист для тестирования

    Перед сдачей объекта заказчику необходимо тщательно протестировать сценарий во всех режимах.

    1. Убедитесь, что `global.night_mode` установлен в `false`.

    2. Сымитируйте движение в зоне датчика.

    3. Результат: свет должен плавно включиться на 100% яркости.

    1. Активируйте ночной режим (например, через узел `Inject` или выполнив сценарий "Спокойной ночи"). Убедитесь, что `global.night_mode` стал `true`.

    2. Сымитируйте движение в той же зоне.

    3. Результат: свет должен плавно включиться на 15% яркости.

    1. Находясь в ночном режиме, деактивируйте его.

    2. Снова сымитируйте движение.

    3. Результат: свет должен включиться на 100%, подтверждая, что система корректно вернулась в дневной режим.

    1. Активируйте ночной режим.

    2. Перезагрузите контроллер HI.

    3. После полной загрузки системы проверьте значение `global.night_mode`. Оно должно остаться `true`.

    4. Сымитируйте движение. Свет должен включиться на 15%, подтверждая, что персистентность состояния работает.

    Идеи для расширения и улучшения

    Этот сценарий является отличной базой для дальнейших усовершенствований:

    Что дальше?

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