ГлавнаяАкадемияМонтаж и пусконаладка контроллера → Создание сценария 'Датчик движения-Свет'

Создание сценария 'Датчик движения-Свет'

Урок 2 · Монтаж и пусконаладка контроллера · 15 мин · theory

Введение: отличие датчика движения от кнопки

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

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

Если мы просто подключим датчик к реле, свет будет мигать: включаться при малейшем движении и тут же гаснуть, как только датчик перестанет его фиксировать. Такое поведение некомфортно и непрактично. Пользователю необходимо, чтобы свет оставался включенным некоторое время ПОСЛЕ последнего обнаруженного движения. Это приводит нас к ключевой концепции данного урока — логике задержки выключения (таймаута). Наша задача — создать сценарий, который:

  • Мгновенно включает свет при первом обнаружении движения.
  • Удерживает свет включенным, пока движение продолжается.
  • Запускает таймер обратного отсчета, когда движение прекращается.
  • Выключает свет только по истечении этого таймера.
  • > 💡 Подсказка: Правильный выбор датчика движения — ключевой фактор стабильности сценария. Учитывайте условия среды: наличие животных, сквозняков, прямого солнечного света.

    > * PIR (пассивный инфракрасный): Реагирует на тепло (ИК-излучение) движущихся объектов. Самый распространенный тип. Может давать ложные срабатывания от сквозняков или прямого солнца.

    > * MW (микроволновый): Работает как мини-радар, излучая микроволны и анализируя отраженный сигнал. Способен "видеть" сквозь тонкие преграды (например, гипсокартон). Может реагировать на движение за пределами комнаты.

    > * Комбинированный (PIR+MW): Срабатывает только при одновременной фиксации движения обоими сенсорами. Обеспечивает максимальную защиту от ложных срабатываний и является предпочтительным для критически важных зон.

    На контроллере HI данные от датчиков движения чаще всего поступают по протоколу MQTT. Датчик публикует в определенный топик сообщения, обозначающие его состояние, как правило, в виде `1` (движение есть) и `0` (движения нет), или `true`/`false`.

    ---

    Секция 1: Получение и обработка данных от датчика движения

    Первым шагом в построении любого сценария является получение данных от источника. В нашем случае — это MQTT-сообщения от датчика движения.

    Настройка `mqtt in`

  • Перетащите на рабочее поле узел `mqtt in` из палитры "network".
  • Дважды кликните по нему для открытия окна настроек.
  • Server: Выберите из выпадающего списка MQTT-брокер вашего контроллера HI. Как правило, он уже преднастроен как `localhost:1883`.
  • Topic: Укажите полный MQTT-топик, в который ваш датчик движения публикует свое состояние. Эту информацию можно найти в документации к датчику или в настройках вашего MQTT-сервера. Для типовых датчиков, интегрированных с платформой HI, топик имеет стандартизированный вид.
  • * Пример топика: `/devices/wb-msw-v3_25/controls/Motion`

  • QoS: Установите `0` или `1`. Для большинства сценариев автоматизации QoS 1 является хорошим балансом между надежностью и производительностью.
  • Name: Дайте узлу осмысленное имя, например, "Датчик движения (Коридор)".
  • Инспекция входящих сообщений

    Чтобы понять, в каком формате приходят данные, подключите выход узла `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` предыдущего сообщения.

  • Найдите в палитре узел `rbe` (в секции "function") и разместите его между `mqtt in` и `debug`.
  • Настройки по умолчанию (`block unless value changes`) нам идеально подходят.
  • Схема потока на данном этапе:
    [mqtt in: Датчик движения] -----> [rbe: Фильтр дублей] -----> [debug]
    

    Теперь в панели отладки вы будете видеть только два типа сообщений: одно с `payload: "1"` в момент начала движения и одно с `payload: "0"` в момент его прекращения. Мы отсеяли шум и готовы к построению основной логики.

    ---

    Секция 2: Логика тайм-аута: Удержание света включенным

    Теперь перейдем к самой важной части нашего сценария — реализации задержки выключения. Задача звучит так: как удержать свет включенным N минут после того, как датчик перестал фиксировать движение?

    Для этого в Node-RED существует специализированный узел `trigger`. Это невероятно мощный и гибкий инструмент для создания логики, зависимой от времени.

    Принцип работы узла `trigger`

    В своей простейшей форме узел `trigger` работает по следующему алгоритму:

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

    Пошаговая сборка и настройка

  • `mqtt in` и `rbe`: Используйте уже настроенные узлы из Секции 1. Они будут подавать нам отфильтрованные сообщения `1` или `0`.
  • `switch` (Маршрутизация):
  • * Добавьте узел `switch` после `rbe`. Он будет направлять сообщения в зависимости от их содержимого.

    * Откройте настройки узла `switch`.

    * Property: `msg.payload`.

    * Правило 1: `==` (строка) `1`. Это означает "если получено сообщение о начале движения".

    * Добавьте только одно правило. Сообщения с `payload: "0"` (движения нет) нам не нужно передавать на `trigger`, так как логика таймера должна запускаться только при обнаружении активности. `switch` просто отбросит все сообщения, не соответствующие правилу.

    * Name: "Есть движение?".

    * Соедините единственный выход узла `switch` со входом узла `trigger`.

  • `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` (Исполнение команды):
  • * Добавьте узел `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: Вход в помещение (проверка включения)

    1. На выходе `mqtt in` `->` `rbe` появляется сообщение с `payload: "1"`.

    2. `switch` пропускает это сообщение на `trigger`.

    3. `trigger` немедленно отправляет сообщение `{"value": true}`.

    4. Физически свет в комнате мгновенно включается.

    * Правильность MQTT-топиков в `mqtt in` и `mqtt out`.

    * Правила в узле `switch`. Возможно, ваш датчик отправляет `true` (булево), а не `"1"` (строка).

    * Работоспособность самого реле и силовой цепи.

    Тест-кейс 2: Нахождение в помещении (проверка сброса таймера)

    1. Датчик периодически переходит в состояние `1` (движение).

    2. Каждое сообщение `payload: "1"`, прошедшее через `rbe` и `switch`, сбрасывает таймер в узле `trigger`.

    3. Сообщение на выключение (`{"value": false}`) не отправляется.

    4. Свет в комнате остается включенным все время.

    Тест-кейс 3: Выход из помещения (проверка тайм-аута выключения)

    1. Датчик перестает отправлять `payload: "1"`. Последнее сообщение, которое пришло от него, было отфильтровано `rbe` и имело `payload: "0"`, но `switch` его заблокировал.

    2. `trigger` больше не получает сообщений, сбрасывающих его таймер.

    3. Ровно через 10 секунд (наше тестовое время) `trigger` отправляет на выход сообщение `{"value": false}`.

    4. Свет в комнате гаснет.

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

    Что дальше

    В этом уроке мы сделали важный шаг от простых stateless-реакций к более сложной stateful-автоматизации с использованием временных задержек. Вы научились обрабатывать данные от датчика движения, фильтровать шум и реализовывать комфортную логику управления светом с помощью узла `trigger`.

    В следующем уроке мы усложним задачу: рассмотрим, как добавить к этому сценарию возможность ручного управления с помощью настенного выключателя, создав гибридную систему, которая будет работать как в автоматическом, так и в ручном режиме.