Создание сценария 'Датчик движения-Свет'
Введение: отличие датчика движения от кнопки
В предыдущем уроке мы рассмотрели создание простого сценария "Кнопка-Свет". Его ключевая особенность — stateless-логика, или логика без состояния. Нажатие кнопки — это мгновенное, дискретное событие. Система реагирует на него (включает или выключает свет) и немедленно "забывает" о том, что произошло. Каждое новое нажатие обрабатывается с чистого листа.
Датчик движения, в отличие от кнопки, является stateful-устройством, то есть устройством, обладающим состоянием. Он не просто сообщает о событии "обнаружено движение", он переходит в состояние "движение есть" и остается в нем, пока движение фиксируется. Затем он переходит в другое состояние — "движения нет". Этот фундаментальный принцип меняет подход к автоматизации.
Если мы просто подключим датчик к реле, свет будет мигать: включаться при малейшем движении и тут же гаснуть, как только датчик перестанет его фиксировать. Такое поведение некомфортно и непрактично. Пользователю необходимо, чтобы свет оставался включенным некоторое время ПОСЛЕ последнего обнаруженного движения. Это приводит нас к ключевой концепции данного урока — логике задержки выключения (таймаута). Наша задача — создать сценарий, который:
> 💡 Подсказка: Правильный выбор датчика движения — ключевой фактор стабильности сценария. Учитывайте условия среды: наличие животных, сквозняков, прямого солнечного света.
> * PIR (пассивный инфракрасный): Реагирует на тепло (ИК-излучение) движущихся объектов. Самый распространенный тип. Может давать ложные срабатывания от сквозняков или прямого солнца.
> * MW (микроволновый): Работает как мини-радар, излучая микроволны и анализируя отраженный сигнал. Способен "видеть" сквозь тонкие преграды (например, гипсокартон). Может реагировать на движение за пределами комнаты.
> * Комбинированный (PIR+MW): Срабатывает только при одновременной фиксации движения обоими сенсорами. Обеспечивает максимальную защиту от ложных срабатываний и является предпочтительным для критически важных зон.
На контроллере HI данные от датчиков движения чаще всего поступают по протоколу MQTT. Датчик публикует в определенный топик сообщения, обозначающие его состояние, как правило, в виде `1` (движение есть) и `0` (движения нет), или `true`/`false`.
---
Секция 1: Получение и обработка данных от датчика движения
Первым шагом в построении любого сценария является получение данных от источника. В нашем случае — это MQTT-сообщения от датчика движения.
Настройка `mqtt in`
* Пример топика: `/devices/wb-msw-v3_25/controls/Motion`
Инспекция входящих сообщений
Чтобы понять, в каком формате приходят данные, подключите выход узла `mqtt in` ко входу узла `debug`. Разверните панель отладки (справа, иконка с жуком). Теперь, когда вы создаете движение перед датчиком, вы будете видеть поступающие сообщения.
Типичное сообщение от датчика при обнаружении движения:
{
"_msgid": "a1b2c3d4.e5f6g7",
"topic": "/devices/wb-msw-v3_25/controls/Motion",
"payload": "1",
"qos": 1,
"retain": false
}
Когда движение прекращается, приходит сообщение с `payload: "0"`.
Проблема "дребезга" и ее решение
Вы можете заметить, что датчик присылает одно и то же состояние многократно: `1`, `1`, `1`, `1`... пока вы движетесь, и `0`, `0`, `0`, `0`... после. Это избыточная информация, которая может бессмысленно нагружать наш поток. Нам нужно реагировать только на изменение состояния: с `0` на `1` и с `1` на `0`.
Для фильтрации дубликатов используется узел `rbe` (Report by Exception). Он пропускает сообщение дальше по потоку только в том случае, если его `msg.payload` отличается от `msg.payload` предыдущего сообщения.
[mqtt in: Датчик движения] -----> [rbe: Фильтр дублей] -----> [debug]
Теперь в панели отладки вы будете видеть только два типа сообщений: одно с `payload: "1"` в момент начала движения и одно с `payload: "0"` в момент его прекращения. Мы отсеяли шум и готовы к построению основной логики.
---
Секция 2: Логика тайм-аута: Удержание света включенным
Теперь перейдем к самой важной части нашего сценария — реализации задержки выключения. Задача звучит так: как удержать свет включенным N минут после того, как датчик перестал фиксировать движение?
Для этого в Node-RED существует специализированный узел `trigger`. Это невероятно мощный и гибкий инструмент для создания логики, зависимой от времени.
Принцип работы узла `trigger`
В своей простейшей форме узел `trigger` работает по следующему алгоритму:
> ⚠️ Внимание: В ноде `trigger` критически важно активировать опцию `Extend delay if new message arrives`. Без нее таймер не будет сбрасываться при повторном обнаружении движения, и свет выключится, даже если в помещении кто-то есть.
Этот механизм "продления" таймера — ключ к нашему сценарию. Когда датчик фиксирует первое движение, `trigger` запускает таймер. Если в течение этих 5 минут происходит новое движение, узел `trigger` получает новое сообщение, и его таймер сбрасывается, начиная отсчет 5 минут заново. И так будет продолжаться до тех пор, пока в помещении есть активность. Свет выключится только тогда, когда пройдут полные 5 минут тишины.
Настройки узла `trigger`
Рассмотрим основные параметры узла, которые нам потребуются:
| Параметр | Описание | Пример значения для нашего сценария |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| Send (Отправить) | Сообщение, которое отправляется немедленно при получении входящего сигнала. | Строка `ON` или JSON `{"value": true}` |
| then wait for (затем ждать) | Длительность тайм-аута. | `5` minutes |
| then send (затем отправить) | Сообщение, которое отправляется по истечении тайм-аута. | Строка `OFF` или JSON `{"value": false}`|
| Extend delay if new message arrives | Флажок, активирующий сброс таймера при поступлении нового сообщения. Это самый важный параметр для нашей задачи. | ✅ Включено |
| Handling (Обработка) | Определяет, как узел реагирует на сообщения, приходящие во время отсчета таймера. Для продления таймера оставляем `extend delay`. | `extend delay` (продлить задержку) |
Узел `trigger` — это, по сути, готовая реализация простого конечного автомата (Finite State Machine) для управления временными задержками. Он значительно упрощает поток, избавляя нас от необходимости вручную управлять таймерами и хранить состояния в переменных контекста.
---
Секция 3: Сборка и настройка полной схемы в Node-RED
Теперь, когда мы разобрались со всеми компонентами, соберем и настроим финальную схему нашего сценария.
Полная схема потока: +----------------+
| |
[mqtt in] --> [rbe] --> [switch] -- (выход 1) --> [trigger] --> [mqtt out]
| |
+----------------+
`[mqtt in: Датчик движения]` -> `[rbe: Фильтр дублей]` -> `[switch: Есть движение?]` -> `[trigger: Таймер 5 мин]` -> `[mqtt out: Управление светом]`
Пошаговая сборка и настройка
* Добавьте узел `switch` после `rbe`. Он будет направлять сообщения в зависимости от их содержимого.
* Откройте настройки узла `switch`.
* Property: `msg.payload`.
* Правило 1: `==` (строка) `1`. Это означает "если получено сообщение о начале движения".
* Добавьте только одно правило. Сообщения с `payload: "0"` (движения нет) нам не нужно передавать на `trigger`, так как логика таймера должна запускаться только при обнаружении активности. `switch` просто отбросит все сообщения, не соответствующие правилу.
* Name: "Есть движение?".
* Соедините единственный выход узла `switch` со входом узла `trigger`.
* Добавьте узел `trigger` после `switch`.
* Откройте его настройки и сконфигурируйте следующим образом:
* Send: выберите тип `JSON` и введите `{"value": true}`. Это стандартизированная команда включения по нашему "контракту сообщений".
* then wait for: `5` и выберите из списка `minutes`.
* then send: выберите `JSON` и введите `{"value": false}`. Это команда выключения.
* Extend delay if new message arrives: Установите галочку ✅.
* Name: "Таймер света 5 мин".
* Добавьте узел `mqtt out` после `trigger`. Он будет публиковать команды, сформированные `trigger`'ом, в топик управления реле.
* Server: Выберите `localhost:1883`.
* Topic: Укажите топик для управления нужным реле. Например, `home/living_room/light/set`. Этот топик должен соответствовать тому, на который подписан поток, физически управляющий реле (как мы это делали в уроке "Кнопка-Свет").
* Name: "Управление светом в гостиной".
Готовый к импорту код потока:[
{
"id": "e2a1b3c4.d5e6f7",
"type": "mqtt in",
"z": "f8g9h0.a1b2c3",
"name": "Датчик движения (Коридор)",
"topic": "/devices/wb-msw-v3_25/controls/Motion",
"qos": "1",
"broker": "c7d8e9.f0a1b2",
"x": 150,
"y": 200,
"wires": [
[
"g3h4i5.j6k7l8"
]
]
},
{
"id": "g3h4i5.j6k7l8",
"type": "rbe",
"z": "f8g9h0.a1b2c3",
"name": "Фильтр дублей",
"func": "rbe",
"gap": "",
"x": 350,
"y": 200,
"wires": [
[
"m9n0o1.p2q3r4"
]
]
},
{
"id": "m9n0o1.p2q3r4",
"type": "switch",
"z": "f8g9h0.a1b2c3",
"name": "Есть движение?",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "1",
"vt": "str"
}
],
"checkall": "true",
"outputs": 1,
"x": 550,
"y": 200,
"wires": [
[
"s5t6u7.v8w9x0"
]
]
},
{
"id": "s5t6u7.v8w9x0",
"type": "trigger",
"z": "f8g9h0.a1b2c3",
"name": "Таймер света 5 мин",
"op1": "{\"value\": true}",
"op1type": "json",
"op2": "{\"value\": false}",
"op2type": "json",
"duration": "5",
"extend": true,
"units": "min",
"reset": "",
"bytopic": "all",
"x": 770,
"y": 200,
"wires": [
[
"y1z2a3.b4c5d6"
]
]
},
{
"id": "y1z2a3.b4c5d6",
"type": "mqtt out",
"z": "f8g9h0.a1b2c3",
"name": "Управление светом в гостиной",
"topic": "home/living_room/light/set",
"qos": "1",
"retain": "",
"broker": "c7d8e9.f0a1b2",
"x": 1020,
"y": 200,
"wires": []
}
]
После развертывания этого потока (`Deploy`) ваша автоматизация готова к проверке.
---
Секция 4: Дымовое тестирование (Smoke Test) сценария
Как и любая другая инженерная система, созданный нами сценарий требует тщательного тестирования перед сдачей в эксплуатацию. Мы применим методику дымового тестирования (Smoke Test), которую подробно рассматривали в одном из первых уроков этого модуля, чтобы проверить все ключевые аспекты его работы.
> 💡 Подсказка: Для ускорения процесса тестирования временно установите в ноде `trigger` короткий тайм-аут, например, 10 секунд. После завершения всех проверок не забудьте вернуть рабочее значение (3-10 минут).
Подключите узлы `debug` к выходам каждого узла в цепочке, чтобы в реальном времени видеть, как сообщения проходят через поток.
Тест-кейс 1: Вход в помещение (проверка включения)
- Действие: Войдите в помещение, где установлен датчик. Убедитесь, что вы создаете достаточно явное движение.
- Ожидаемый результат:
2. `switch` пропускает это сообщение на `trigger`.
3. `trigger` немедленно отправляет сообщение `{"value": true}`.
4. Физически свет в комнате мгновенно включается.
- Диагностика: Если свет не включился, проверьте:
* Правила в узле `switch`. Возможно, ваш датчик отправляет `true` (булево), а не `"1"` (строка).
* Работоспособность самого реле и силовой цепи.
Тест-кейс 2: Нахождение в помещении (проверка сброса таймера)
- Действие: Оставайтесь в помещении и периодически совершайте небольшие движения каждые 5-7 секунд (при 10-секундном тайм-ауте).
- Ожидаемый результат:
2. Каждое сообщение `payload: "1"`, прошедшее через `rbe` и `switch`, сбрасывает таймер в узле `trigger`.
3. Сообщение на выключение (`{"value": false}`) не отправляется.
4. Свет в комнате остается включенным все время.
- Диагностика: Если свет выключился, пока вы были в комнате, это почти наверняка означает, что в узле `trigger` не установлена галочка `Extend delay if new message arrives`. Это самая частая ошибка при настройке данного сценария.
Тест-кейс 3: Выход из помещения (проверка тайм-аута выключения)
- Действие: Покиньте помещение. Убедитесь, что в зоне действия датчика нет никакой активности (домашних животных, качающихся от сквозняка предметов). Засеките время.
- Ожидаемый результат:
2. `trigger` больше не получает сообщений, сбрасывающих его таймер.
3. Ровно через 10 секунд (наше тестовое время) `trigger` отправляет на выход сообщение `{"value": false}`.
4. Свет в комнате гаснет.
- Диагностика: Если свет не выключился, проверьте в панели `debug`, было ли отправлено сообщение `{"value": false}`. Если было, но свет не погас, проблема находится в потоке управления реле. Если сообщение не было отправлено, проверьте настройки узла `trigger` (поле "then send").
Успешное прохождение всех трех тест-кейсов подтверждает, что ваш сценарий работает корректно и готов к использованию с реальным, рабочим тайм-аутом.
Что дальше
В этом уроке мы сделали важный шаг от простых stateless-реакций к более сложной stateful-автоматизации с использованием временных задержек. Вы научились обрабатывать данные от датчика движения, фильтровать шум и реализовывать комфортную логику управления светом с помощью узла `trigger`.
В следующем уроке мы усложним задачу: рассмотрим, как добавить к этому сценарию возможность ручного управления с помощью настенного выключателя, создав гибридную систему, которая будет работать как в автоматическом, так и в ручном режиме.