SCN-LIGHT-001: Включение света по движению с учетом освещенности
Введение в сценарий SCN-LIGHT-001: Логика и компоненты
ведение в сценарий SCN-LIGHT-001: Логика и компоненты
Сценарий автоматического включения света по движению с учетом освещенности (`SCN-LIGHT-001`) — это базовая и самая востребованная автоматизация в современном умном доме. Его главная задача — избавить пользователя от необходимости искать выключатели в проходных зонах и помещениях кратковременного пребывания.
Зачем нужен этот сценарий?
Реализация данной логики закрывает сразу три потребности:
- Энергосбережение: Свет не горит впустую. Он включается только когда в зоне есть человек, и гарантированно выключается после его ухода.
Аппаратные компоненты: Кто за что отвечает?
Для реализации сценария на базе контроллера HI минимально необходимы три физических элемента. Каждый из них выполняет свою строгую роль в алгоритме:
Как работает:* Пассивный инфракрасный датчик фиксирует изменение теплового фона (движение человека). Подключается к универсальному входу контроллера HI (например, как "сухой контакт").
Зачем нужен: Запускает логику сценария. Сообщает контроллеру: "Здесь кто-то есть!"*.
Как работает:* Измеряет текущий уровень света в помещении в люксах (лк). Подключается по цифровой шине (Modbus RS-485 или CAN).
Зачем нужен: Предотвращает ложные включения. Сообщает: "Сейчас слишком темно, свет нужен" или "Днем и так достаточно света от окна, не включаем"*.
Как работает:* Встроенное реле контроллера (замыкает цепь 220В) или модуль управления по DALI / 0-10В.
Зачем нужен:* Физически подает питание на светильник.
Алгоритм работы: Включение и Выключение
Правильно спроектированный сценарий должен иметь четко описанную логику как для старта, так и для завершения.
1. Логика включения (Start)Базовая формула выглядит так:
> ЕСЛИ `обнаружено движение (Триггер)` И `освещенность ниже порога (Условие)`, ТО `включить свет (Действие)`.
> 💡 Подсказка по UX: Порог освещенности (Lux threshold)
> Выбор порога — критично важный параметр для комфорта. Если поставить слишком низкий порог (например, 5 люкс), то сумерках датчик всё еще будет считать, что "светло", и вы окажетесь в темноте. Оптимальные значения подбираются экспериментально: для коридоров обычно это 15–30 люкс, для рабочих зон (кухня, кабинет) значение должно быть выше — 50–100 люкс.
2. Логика выключения (Stop)Свет не должен выключаться мгновенно. Если человек остановился завязать шнурки, датчик на секунду потеряет его из виду. Чтобы свет не "моргал", используется Тайм-аут (Delay Off).
> ЕСЛИ `датчик НЕ фиксирует движение [Х минут]` И `свет был включен сценарием`, ТО `выключить свет`.
Пример: Для проходного коридора тайм-аут обычно ставят на 1-2 минуты, для санузла (если там нет датчика присутствия) — 5-10 минут.Ручное вмешательство (Override)
Важнейший элемент логики, о котором часто забывают — приоритеты. Что произойдет, если в помещении с автоматическим светом пользователь нажмет физический выключатель на стене?
Система должна уметь отличать автоматическое действие от ручного:
- Авторежим: Свет включился по движению -> должен выключиться по тайм-ауту.
- Ручное переопределение (Manual Override): Если пользователь нажал выключатель, он ожидает полного контроля. Система должна заблокировать тайм-аут выключения по датчику движения, пока человек сам не выключит свет кнопкой (или пока не сработает глобальный сценарий "Ушел из дома").
Учет этих состояний делает сценарий `SCN-LIGHT-001` по-настоящему "умным" и незаметным для жильцов.
Подготовка данных: MQTT-топики от датчиков и для управления
одготовка данных: MQTT-топики от датчиков и для управления
Чтобы Node-RED мог управлять светом, ему необходимо получать информацию из физического мира (от датчиков) и отправлять команды обратно (на реле). В архитектуре умного дома эту задачу выполняет протокол MQTT.
> 💡 Связанный материал: Если у вас еще не настроены шлюзы и передача данных в MQTT, обратитесь к базовому курсу COURSE-04: Интеграция оборудования и протоколы. Текущий урок предполагает, что оборудование уже настроено и публикует данные.
Чтобы сценарий работал без сбоев, нам нужно определить четкий «контракт сообщений» — точные адреса (топики) и форматы данных для каждого участника логики.
Ниже мы разделим данные на три логические роли: Триггер, Условие и Действие.
1. Триггер: Датчик движения
Датчик движения выступает инициатором сценария. Как только человек входит в зону видимости, датчик мгновенно публикует событие. В нашем примере используется датчик, подключенный через Zigbee-шлюз.
| Параметр | Значение | Пояснение |
| :--- | :--- | :--- |
| MQTT-топик | `zigbee2mqtt/pir_hallway` | Указывает на тип шлюза (`zigbee2mqtt`) и расположение устройства (`pir_hallway`). |
| Формат данных| `JSON` | Строка, которую узел `mqtt in` в Node-RED автоматически преобразует в объект `msg.payload`. |
Пример `msg.payload` (входящего сообщения от датчика):{
"occupancy": true,
"linkquality": 90,
"battery": 100
}
Для сценария нас интересует исключительно поле `occupancy`:
- `true` — движение обнаружено;
- `false` — зона свободна (событие очистки).
2. Условие: Датчик освещенности
Датчик освещенности выступает ограничителем. Он не запускает сценарий сам по себе, а лишь дает контекст: "сейчас слишком светло, включать лампу не нужно". В системах на базе Wiren Board такие датчики часто работают по проводной шине Modbus через встроенный сервис-шлюз.
| Параметр | Значение | Пояснение |
| :--- | :--- | :--- |
| MQTT-топик | `wb-msw-v3/illuminance` | Топик проводного мультисенсора `wb-msw-v3`. |
| Формат данных| `String` (строка) | Простое числовое значение, представляющее уровень на уровне сенсора в люксах (Lx). |
Пример `msg.payload`: `"15"` (означает текущую освещенность в 15 люкс).⚠️ Проблема асинхронности данных:
Сообщения об уровне освещенности приходят с другой периодичностью (например, раз в минуту или при сильном изменении света), чем события от датчика движения. Нам потребуется механизм (например, сохранение в контекст Node-RED), чтобы в момент срабатывания движения у нас под рукой было последнее актуальное значение освещенности для проведения проверки.
3. Действие: Управление реле (Свет)
Исполнительное устройство — это релейный модуль, который физически замыкает цепь питания светильника. Чтобы управлять светом, мы отправляем команду в управляющий топик реле.
| Параметр | Значение | Пояснение |
| :--- | :--- | :--- |
| MQTT-топик | `wb-mr6c/K1/on` | Командный топик для первого канала (`K1`) модуля `wb-mr6c`. Суффикс `/on` — стандарт для приема команд. |
| Команда ВКЛ | `"1"` | Строковая единица интерпретируется модулем как включение. |
| Команда ВЫКЛ| `"0"` | Строковый ноль отключает канал. |
Итоговая шпаргалка топиков
Перед сборкой визуального потока проверьте, что у вас определены все три компонента. Вы можете протестировать их наличие в системе MQTT (например, через программу MQTT Explorer):
Теперь, когда входные и выходные данные формализованы, мы готовы объединить их с помощью логических узлов Node-RED.
Реализация логики в Node-RED: Узлы, контекст и условия
еализация логики в Node-RED: Узлы, контекст и условия
Создание потока для сценария `SCN-LIGHT-001` требует аккуратной работы с асинхронными данными и ветвлением логики. Основной триггер в нашем случае — сообщение от датчика движения.
> ⚠️ Внимание: Сообщения от разных датчиков приходят асинхронно. Нельзя строить логику в расчете, что сообщение об освещенности придет точно перед сообщением о движении. Единственный надежный способ — сохранять последние актуальные состояния устройств в контекст потока (`flow context`) и обращаться к этим сохраненным значениям в момент принятия решения.
Шаг 1: Сохранение состояния освещенности в контекст
Первым делом создадим отдельный микро-поток, который будет просто слушать топик датчика освещенности и обновлять значение в памяти Node-RED.
* Set: `flow.current_lux`
* to the value: `msg.payload`
Этот поток работает автономно в фоне. Благодаря ему переменная `flow.current_lux` всегда содержит самое свежее известное значение уровня света в помещении.
Шаг 2: Обработка события от датчика движения
Теперь собираем основную цепочку, которая инициируется датчиком движения.
* `false` -> `true` (человек вошел)
* `true` -> `false` (человек вышел)
Настройка:* В поле `Property` узла `rbe` укажите `msg.payload.occupancy`.
Шаг 3: Основное ветвление логики ("И")
После того как датчик зафиксировал изменение состояния (человек вошел), нам нужно проверить два условия: "ЕСТЬ ДВИЖЕНИЕ" и "СЕЙЧАС ТЕМНО". В визуальной среде Node-RED проще всего реализовать логическое "И" последовательной установкой узлов `switch`.
* Добавьте узел `switch` после `rbe`.
* Property: `msg.payload.occupancy`
* Rule 1: `is true`.
(Сообщения о том, что движение прекратилось, просто не пройдут эту проверку).*
* Подключите выход первого `switch` ко второму узлу `switch`. Здесь мы читаем данные из контекста.
* Property: `flow.current_lux`
* Rule 1: `<` (less than) `20` (ваш порог в люксах, тип — `number`).
* Подключите выход второго узла `switch` к узлу `change`.
* Set: `msg.payload`
* to the value: `"1"` (строка `string` или `true` в зависимости от формата вашего реле, например, для реле Wiren Board это строка `"1"`).
* После узла `change` поставьте узел `mqtt out`, настроенный на отправку в топик управления реле (например, `wb-mr6c/K1/on`).
Альтернативный вариант: Использование узла `function`
Для тех, кто предпочитает писать код, цепочку из последовательных проверок (узлы `switch` и `change`) можно заменить одним узлом `function`. Это делает поток визуально компактнее.
Ниже приведен пример JavaScript-кода для узла `function`, заменяющего Шаг 3:
// 1. Получаем последнее сохраненное значение освещенности из контекста потока
// Добавляем || 0 на случай, если значение еще ни разу не пришло и context пуст
const currentLux = flow.get("current_lux") || 0;
const luxThreshold = 20; // Задаем порог темноты
// 2. Проверяем, что текущее событие — это именно обнаружение движения
const motionDetected = msg.payload.occupancy === true;
// 3. Выполняем основное логическое условие
if (motionDetected && currentLux < luxThreshold) {
// Если движение есть и темно, визуализируем статус под узлом
node.status({ fill: "green", shape: "dot", text: `Motion + Lux: ${currentLux} < ${luxThreshold}. Turning ON` });
// Готовим payload для реле
msg.payload = "1";
return msg; // Пропускаем сообщение дальше к mqtt out
} else {
// Условие не выполнено (светло или движение прекратилось)
node.status({ fill: "grey", shape: "ring", text: `Passed. Motion: ${motionDetected}, Lux: ${currentLux}` });
// Возвращаем null, прерывая поток
return null;
}
> 💡 Промежуточный итог: На данном этапе мы полностью реализовали логику включения света. Если в комнату вошли и там темно, свет загорится. Однако сейчас он никогда не выключится сам. В следующем разделе мы добавим таймер обратного отсчета для автоматического выключения.
Управление выключением: Использование узла Trigger для задержки
правление выключением: Использование узла Trigger для задержки
Для реализации таймера автовыключения мы используем узел `trigger`. Принципы его работы были подробно рассмотрены в уроке `SCN-COMMON-004: Антидребезг и таймеры` (или соответствующем модуле про таймеры), поэтому здесь мы сфокусируемся на его практическом применении в нашем сценарии.
Логика таймера:- Запуск: Сообщение об отсутствии движения (`occupancy: false`) запускает отсчет времени на выключение.
- Сброс: Сообщение о наличии движения (`occupancy: true`) сбрасывает таймер.
- Пример: Человек вышел из помещения, датчик передал отсутствие движения — запустился таймер на 5 минут. Если через 2 минуты человек вернется, датчик снова передаст наличие движения. Таймер обнулится, и свет не погаснет, пока человек не выйдет снова.
Чтобы реализовать эту логику, перестроим поток после фильтрации сообщений (узла `rbe`).
Шаг 1. Разделение потока событий (узел Switch)
После узла `rbe` поток необходимо разделить на две ветки: первая отвечает за включение света, вторая — за задержку выключения.
* Выход 1: `msg.payload.occupancy` is true
* Выход 2: `msg.payload.occupancy` is false
Шаг 2. Обработка ветки "Движение есть" (Сброс)
Этот путь (Выход 1) ведет к логике проверки освещенности и включения света, которую мы настроили в предыдущем разделе.
Важно: От этого же пути нужно отправить команду для сброса таймера, чтобы свет не погас, пока в комнате кто-то есть.* Set: `msg.payload`
* to the value: `"reset"` (убедитесь, что выбран тип String, а не msg).
Шаг 3. Обработка ветки "Движения нет" (Запуск)
Этот путь (Выход 2 узла `switch`) будет запускать наш таймер на выключение.
Шаг 4. Конфигурация узла-таймера `trigger`
Откройте свойства узла `trigger` и настройте параметры задержки:
- Send: `nothing`. Нам не нужно отправлять никаких команд сразу после того, как датчик перестал фиксировать движение.
- then wait for: `5` `minutes`. Это длительность нашего таймера автовыключения.
- then send: `the latest message`. Если за 5 минут статус не изменился, узел пропустит сигнал дальше.
- If `msg.payload` arrives...: `...and is a "reset" string, reset the trigger`. Это ключевая настройка. Если за время отсчета в узел придет строка `"reset"` (ту, что мы сформировали на Шаге 2), таймер остановится и обнулится.
> 💡 Совет для отладки: На этапе сборки и проверки сценария установите значение `wait for` на 10-15 секунд (`seconds`). Это сэкономит время во время тестирования. Не забудьте вернуть 5 минут (`minutes`) при финальном запуске.
Шаг 5. Завершение логики выключения
После того как таймер отработал отведенное время, необходимо сформировать и отправить физическую команду выключения в MQTT.
* Set: `msg.payload`
* to the value: `"0"` (опять же, формат String, что означает "выключено" для реле Wiren Board).
Проверка результата: План тестирования выключения
После сборки убедитесь, что логика работает корректно, пройдясь по чек-листу:
- [ ] Симуляция `occupancy: true` (при низкой освещенности) -> Реле получает `"1"`.
- [ ] Симуляция `occupancy: false` -> Запустился узел `trigger`. В течение заданного времени (например, 15 сек при отладке) реле не получает никаких команд, свет остается гореть.
- [ ] Симуляция `occupancy: false`, а затем сразу `occupancy: true` -> Узел `trigger` получил команду `"reset"`. Отсчет остановлен. По истечении 15 секунд свет НЕ выключается.
- [ ] Прошло заданное время без движения -> `trigger` пропускает сигнал, узел `change` формирует `"0"`, реле выключает свет.
> ⚠️ Ограничение базового сценария: Данная логика отлично работает для полностью автоматических зон (проходные коридоры, кладовки). Но она не учитывает ситуации ручного управления. Если вы включили свет с настенного выключателя, чтобы почитать книгу (и сидите без движений), данная логика выключит свет через 5 минут. Обработка таких конфликтов и приоритетов ручного управления (Overrides) — это отдельная сложная тема, которая будет детально разобрана в следующих уроках.
Итоги и дальнейшие улучшения сценария
тоги и дальнейшие улучшения сценария
Мы спроектировали базовый сценарий автоматизации `SCN-LIGHT-001`, который комбинирует события движения и значения освещенности. Давайте закрепим результат, проверим корректность работы и наметим векторы его развития.
Итоговая архитектура
Финальная структура потока (Pipeline) логически делится на три блока:
* `mqtt in` (Освещенность) + `change`: Асинхронно получает данные в lux и кеширует их в переменную пространства потока `flow.current_lux`.
* `mqtt in` (Движение): Работает как основной триггер.
* `rbe`: Фильтрует «шум», пропуская топик только при реальной смене состояния (начало/конец движения).
* `switch` (Разделение веток): Направляет поток по ветке включения (1) или выключения (0).
* `switch` (Проверка освещенности): Реализует логическое «И». Проверяет условие `flow.current_lux < 50`.
* `trigger`: Отвечает за удержание света. Рестартит таймер при каждом новом движении, продлевая комфорт.
* `change`: Формирует конечный `msg.payload` (`"1"` для включения, `"0"` для выключения).
* `mqtt out`: Публикует команду в топик физического реле.
Чек-лист проверки (Тест-план)
Перед тем как считать сценарий завершенным, проведите тестирование по следующим критериям:
- [ ] Тест ложного включения: Имитируйте движение при ярком свете (установите `lux > 50`). Свет не должен включиться.
- [ ] Тест ночного включения: Имитируйте движение в темноте (установите `lux < 50`). Свет должен включиться мгновенно.
- [ ] Тест сброса таймера: При включенном свете повторно вызовите событие движения. Дождитесь истечения базового таймаута: свет должен продолжать гореть (таймер сбросился).
- [ ] Тест корректного выключения: Покиньте зону (или отправьте состояние «нет движения»). Дождитесь таймаута — реле должно отключиться.
Возможные улучшения и UX (Пользовательский опыт)
Текущий сценарий отлично справляется с базовой задачей, но для полноценного комфорта в «умном доме» в него можно добавить следующие функции:
Сейчас, если пользователь включит свет физическим выключателем на стене, а затем выйдет из комнаты, таймер может не сработать (т.к. движение не начиналось). Или наоборот — датчик может неожиданно выключить свет, включенный вручную. Решение: добавить прослушивание топика состояний выключателя и блокировать работу автоматического таймера (disable trigger), если свет был включен человеком.
Для ограничения работы по часам можно добавить узел `time-range-switch` (из палитры `node-red-contrib-time-range-switch`). Сценарий будет пропускать сообщения триггера только в заданный интервал, например, с 20:00 до 08:00.
Поведение сценария должно адаптироваться под общедомовые режимы поведения.
* Режим "Ночь": В ночном режиме свет может включаться не на 100% яркости, а на 10-20% (чтобы не слепить при походе на кухню), а таймаут на выключение — сокращаться до минимума.
* Режим "Никого нет дома" (Away): Сценарий полностью блокируется. Если система фиксирует «движение», она не включает свет, а инициирует охранный скрипт. В узле `switch` ставится дополнительная проверка: `global.house_mode != "away"`.
> 🔗 Связанный материал: Подробно принципы работы с глобальными режимами и состояниями мы разбираем в модуле `COURSE-07-M02 "Системные состояния и режимы контроллера"`.
При работе с DALI или 0-10V диммерами вместо отправки грубой команды `"1"` (100%), отправляется серия сообщений для плавного нарастания яркости (например, от 0% до 80% за 3 секунды). Это обеспечивает премиальный визуальный комфорт.
Что дальше
Мы разобрали базовую логику реакции на сенсоры и удержание состояния таймером. В следующем уроке мы рассмотрим более сложный сценарий — управление климатом, где будем активно использовать концепцию конечных автоматов (FSM - Finite State Machine) для переключения между состояниями системы отопления и кондиционирования.