ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → SCN-LIGHT-001: Включение света по движению с учетом освещенности

SCN-LIGHT-001: Включение света по движению с учетом освещенности

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

Введение в сценарий SCN-LIGHT-001: Логика и компоненты

ведение в сценарий SCN-LIGHT-001: Логика и компоненты

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

Зачем нужен этот сценарий?

Реализация данной логики закрывает сразу три потребности:

Комфорт (UX): Незаменимо в местах, где у человека часто заняты руки или выключатель находится далеко. Пример: вы заходите в дом с тяжелыми пакетами — свет в прихожей включается сам.* Целевые зоны: коридоры, лестницы, санузлы, гардеробные, кладовые. Пассивная безопасность: Автоматическая подсветка пути в темное время суток предотвращает случайные травмы. Пример: ночной поход на кухню по неосвещенному коридору.*

Аппаратные компоненты: Кто за что отвечает?

Для реализации сценария на базе контроллера HI минимально необходимы три физических элемента. Каждый из них выполняет свою строгую роль в алгоритме:

  • Датчик движения (PIR Sensor) — ТРИГГЕР.
  • Как работает:* Пассивный инфракрасный датчик фиксирует изменение теплового фона (движение человека). Подключается к универсальному входу контроллера HI (например, как "сухой контакт").

    Зачем нужен: Запускает логику сценария. Сообщает контроллеру: "Здесь кто-то есть!"*.

  • Датчик освещенности (Lux Meter) — УСЛОВИЕ.
  • Как работает:* Измеряет текущий уровень света в помещении в люксах (лк). Подключается по цифровой шине (Modbus RS-485 или CAN).

    Зачем нужен: Предотвращает ложные включения. Сообщает: "Сейчас слишком темно, свет нужен" или "Днем и так достаточно света от окна, не включаем"*.

  • Исполнительное устройство (Actuator) — ДЕЙСТВИЕ.
  • Как работает:* Встроенное реле контроллера (замыкает цепь 220В) или модуль управления по DALI / 0-10В.

    Зачем нужен:* Физически подает питание на светильник.

    Алгоритм работы: Включение и Выключение

    Правильно спроектированный сценарий должен иметь четко описанную логику как для старта, так и для завершения.

    1. Логика включения (Start)

    Базовая формула выглядит так:

    > ЕСЛИ `обнаружено движение (Триггер)` И `освещенность ниже порога (Условие)`, ТО `включить свет (Действие)`.

    > 💡 Подсказка по UX: Порог освещенности (Lux threshold)

    > Выбор порога — критично важный параметр для комфорта. Если поставить слишком низкий порог (например, 5 люкс), то сумерках датчик всё еще будет считать, что "светло", и вы окажетесь в темноте. Оптимальные значения подбираются экспериментально: для коридоров обычно это 15–30 люкс, для рабочих зон (кухня, кабинет) значение должно быть выше — 50–100 люкс.

    2. Логика выключения (Stop)

    Свет не должен выключаться мгновенно. Если человек остановился завязать шнурки, датчик на секунду потеряет его из виду. Чтобы свет не "моргал", используется Тайм-аут (Delay Off).

    > ЕСЛИ `датчик НЕ фиксирует движение [Х минут]` И `свет был включен сценарием`, ТО `выключить свет`.

    Пример: Для проходного коридора тайм-аут обычно ставят на 1-2 минуты, для санузла (если там нет датчика присутствия) — 5-10 минут.

    Ручное вмешательство (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`:

    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):

  • Откуда ждем старт (Trigger): `zigbee2mqtt/pir_hallway` → проверяем `msg.payload.occupancy`
  • Что проверяем (Condition): `wb-msw-v3/illuminance` → читаем число (в люксах)
  • Кем управляем (Action): `wb-mr6c/K1/on` → пишем `"1"` или `"0"`
  • Теперь, когда входные и выходные данные формализованы, мы готовы объединить их с помощью логических узлов Node-RED.

    Реализация логики в Node-RED: Узлы, контекст и условия

    еализация логики в Node-RED: Узлы, контекст и условия

    Создание потока для сценария `SCN-LIGHT-001` требует аккуратной работы с асинхронными данными и ветвлением логики. Основной триггер в нашем случае — сообщение от датчика движения.

    > ⚠️ Внимание: Сообщения от разных датчиков приходят асинхронно. Нельзя строить логику в расчете, что сообщение об освещенности придет точно перед сообщением о движении. Единственный надежный способ — сохранять последние актуальные состояния устройств в контекст потока (`flow context`) и обращаться к этим сохраненным значениям в момент принятия решения.

    Шаг 1: Сохранение состояния освещенности в контекст

    Первым делом создадим отдельный микро-поток, который будет просто слушать топик датчика освещенности и обновлять значение в памяти Node-RED.

  • Добавьте узел `mqtt in` и настройте его на топик вашего датчика освещенности (например, `wb-msw-v3/illuminance`). Убедитесь, что на выходе данные парсятся как число.
  • Соедините его с узлом `change`. Внутри узла `change` создайте правило:
  • * Set: `flow.current_lux`

    * to the value: `msg.payload`

  • Для отладки добавьте узел `debug` после `change`, чтобы визуально контролировать обновление значения в боковой панели Node-RED.
  • Этот поток работает автономно в фоне. Благодаря ему переменная `flow.current_lux` всегда содержит самое свежее известное значение уровня света в помещении.

    Шаг 2: Обработка события от датчика движения

    Теперь собираем основную цепочку, которая инициируется датчиком движения.

  • Прием сообщения: Добавьте узел `mqtt in` и подпишитесь на топик движения (например, `zigbee2mqtt/pir_hallway`). В поле `Output` обязательно выберите "a parsed JSON object", чтобы получить объект `msg.payload`, а не сырую строку.
  • Фильтрация дублей (`rbe`): Добавьте узел `rbe` (Report by Exception). Этот узел критически важен: он защитит систему от лавины одинаковых сообщений (`{"occupancy": true}`), пока человек находится в комнате. Сообщение пройдет дальше только при смене состояния:
  • * `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: Антидребезг и таймеры` (или соответствующем модуле про таймеры), поэтому здесь мы сфокусируемся на его практическом применении в нашем сценарии.

    Логика таймера:

    Чтобы реализовать эту логику, перестроим поток после фильтрации сообщений (узла `rbe`).

    Шаг 1. Разделение потока событий (узел Switch)

    После узла `rbe` поток необходимо разделить на две ветки: первая отвечает за включение света, вторая — за задержку выключения.

  • Добавьте узел `switch` после `rbe`.
  • Настройте два правила проверки свойства (Rules):
  • * Выход 1: `msg.payload.occupancy` is true

    * Выход 2: `msg.payload.occupancy` is false

    Шаг 2. Обработка ветки "Движение есть" (Сброс)

    Этот путь (Выход 1) ведет к логике проверки освещенности и включения света, которую мы настроили в предыдущем разделе.

    Важно: От этого же пути нужно отправить команду для сброса таймера, чтобы свет не погас, пока в комнате кто-то есть.
  • Добавьте узел `change` и подключите его к Выходу 1 узла `switch`.
  • Настройте правило переопределения:
  • * Set: `msg.payload`

    * to the value: `"reset"` (убедитесь, что выбран тип String, а не msg).

  • Соедините выход этого узла `change` со входом будущего узла `trigger`.
  • Шаг 3. Обработка ветки "Движения нет" (Запуск)

    Этот путь (Выход 2 узла `switch`) будет запускать наш таймер на выключение.

  • Добавьте узел `trigger` на рабочее поле.
  • Соедините Выход 2 узла `switch` напрямую со входом узла `trigger`. (В этот же вход попадает и команда сброса из предыдущего шага).
  • Шаг 4. Конфигурация узла-таймера `trigger`

    Откройте свойства узла `trigger` и настройте параметры задержки:

    > 💡 Совет для отладки: На этапе сборки и проверки сценария установите значение `wait for` на 10-15 секунд (`seconds`). Это сэкономит время во время тестирования. Не забудьте вернуть 5 минут (`minutes`) при финальном запуске.

    Шаг 5. Завершение логики выключения

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

  • Установите узел `change` после узла `trigger`.
  • Настройте формирование команды:
  • * Set: `msg.payload`

    * to the value: `"0"` (опять же, формат String, что означает "выключено" для реле Wiren Board).

  • Соедините выход этого узла с тем же узлом `mqtt out` (`wb-mr6c/K1/on`), который вы использовали ранее для команды включения.
  • Проверка результата: План тестирования выключения

    После сборки убедитесь, что логика работает корректно, пройдясь по чек-листу:

    > ⚠️ Ограничение базового сценария: Данная логика отлично работает для полностью автоматических зон (проходные коридоры, кладовки). Но она не учитывает ситуации ручного управления. Если вы включили свет с настенного выключателя, чтобы почитать книгу (и сидите без движений), данная логика выключит свет через 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`: Публикует команду в топик физического реле.

    Чек-лист проверки (Тест-план)

    Перед тем как считать сценарий завершенным, проведите тестирование по следующим критериям:

    Возможные улучшения и UX (Пользовательский опыт)

    Текущий сценарий отлично справляется с базовой задачей, но для полноценного комфорта в «умном доме» в него можно добавить следующие функции:

  • Ручное переопределение (Manual Override):
  • Сейчас, если пользователь включит свет физическим выключателем на стене, а затем выйдет из комнаты, таймер может не сработать (т.к. движение не начиналось). Или наоборот — датчик может неожиданно выключить свет, включенный вручную. Решение: добавить прослушивание топика состояний выключателя и блокировать работу автоматического таймера (disable trigger), если свет был включен человеком.

  • Учет времени суток:
  • Для ограничения работы по часам можно добавить узел `time-range-switch` (из палитры `node-red-contrib-time-range-switch`). Сценарий будет пропускать сообщения триггера только в заданный интервал, например, с 20:00 до 08:00.

  • Интеграция с глобальными режимами (FSM):
  • Поведение сценария должно адаптироваться под общедомовые режимы поведения.

    * Режим "Ночь": В ночном режиме свет может включаться не на 100% яркости, а на 10-20% (чтобы не слепить при походе на кухню), а таймаут на выключение — сокращаться до минимума.

    * Режим "Никого нет дома" (Away): Сценарий полностью блокируется. Если система фиксирует «движение», она не включает свет, а инициирует охранный скрипт. В узле `switch` ставится дополнительная проверка: `global.house_mode != "away"`.

    > 🔗 Связанный материал: Подробно принципы работы с глобальными режимами и состояниями мы разбираем в модуле `COURSE-07-M02 "Системные состояния и режимы контроллера"`.

  • "Мягкое" управление (Soft On/Off):
  • При работе с DALI или 0-10V диммерами вместо отправки грубой команды `"1"` (100%), отправляется серия сообщений для плавного нарастания яркости (например, от 0% до 80% за 3 секунды). Это обеспечивает премиальный визуальный комфорт.

    Что дальше

    Мы разобрали базовую логику реакции на сенсоры и удержание состояния таймером. В следующем уроке мы рассмотрим более сложный сценарий — управление климатом, где будем активно использовать концепцию конечных автоматов (FSM - Finite State Machine) для переключения между состояниями системы отопления и кондиционирования.