Шаблон 'Импульс' (Pulse)
Введение в шаблон 'Импульс'
Шаблон проектирования 'Импульс' (Pulse) — это фундаментальная техника в автоматизации, предназначенная для кратковременной подачи управляющего сигнала на устройство с целью его активации. В отличие от шаблона 'Включено/Выключено' (On/Off), который мы детально разобрали в предыдущем уроке (LESSON-05-M02-L01), 'Импульс' не подразумевает сохранение состояния со стороны контроллера. Контроллер лишь инициирует действие, а дальнейшая логика работы (например, открытие ворот до концевого выключателя и последующее закрытие по второму импульсу) реализуется на стороне самого исполнительного устройства.
Основное отличие от шаблона 'On/Off' можно представить в следующей таблице:
| Характеристика | Шаблон 'On/Off' (Включено/Выключено) | Шаблон 'Pulse' (Импульс) |
| ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------- |
| Управление состоянием | Контроллер хранит и отслеживает состояние (Stateful). | Контроллер не хранит состояние (Stateless, "fire and forget"). |
| Длительность сигнала | Сигнал подается постоянно до получения команды на отключение. | Сигнал подается кратковременно (например, 200-500 мс). |
| Логика устройства | Устройство пассивно (например, обычное реле, которое замыкает цепь). | Устройство имеет встроенную логику (контроллер ворот, диммер). |
| Аналогия | Выключатель света с фиксацией. | Кнопка дверного звонка или кнопка на пульте от ворот (без фиксации). |
> 💡 Подсказка: Импульсный режим идеален для устройств, которые имеют собственную логику управления и требуют лишь сигнала для старта (например, контроллер ворот, который сам обрабатывает открытие и закрытие).
Типичные сценарии применения
Шаблон 'Импульс' незаменим во множестве практических задач на объектах автоматизации:
- Управление воротами и шлагбаумами: Подача короткого импульса на управляющий вход контроллера ворот для запуска цикла "открыть-стоп-закрыть-стоп".
- Электромагнитные и электромеханические замки: Кратковременная подача напряжения для открытия замка на несколько секунд.
- Импульсные (бистабильные) реле: Управление освещением или другими нагрузками, где каждый импульс меняет состояние реле на противоположное.
- Пошаговое управление (Step Control): Короткие импульсы для приводов штор, жалюзи или диммеров для небольшого изменения их положения (например, "повернуть ламели" или "увеличить яркость на 10%").
- Активация сценариев на других устройствах: Отправка импульса для запуска сложной логики на другом контроллере или панели управления.
По сути, в любом месте, где в классической электрике используется кнопка без фиксации, в системе автоматизации на платформе HI применяется шаблон 'Импульс'.
---
Базовая реализация в Node-RED: узел 'Trigger'
Основным и наиболее удобным инструментом для реализации шаблона 'Импульс' в среде Node-RED является узел `Trigger`. Этот узел позволяет создать последовательность из двух сообщений, разделенных заданным интервалом времени, что в точности имитирует нажатие и отпускание физической кнопки.
Настройка узла 'Trigger'
При добавлении узла `Trigger` на рабочую область его настройки выглядят предельно просто и логично:
Дополнительно, узел имеет опцию "Extend delay if new message arrives", которая позволяет сбрасывать таймер при получении нового сообщения, но в базовом сценарии импульса она обычно не используется.
Визуализация потока
Создадим простейший поток для демонстрации работы узла `Trigger`. Он будет состоять всего из трех узлов: `Inject` -> `Trigger` -> `Debug`.
* Send: `Number` `1`
* then wait for: `250` `milliseconds`
* then send: `Number` `0`
+----------+ +-------------------+ +---------+
| Inject |----->| Trigger (250ms) |----->| Debug |
+----------+ +-------------------+ +---------+
После развертывания потока (Deploy) и однократного нажатия на кнопку узла `Inject`, вы увидите в панели отладки (Debug) следующую картину:
// Сообщение 1 (t = 0ms)
{
"payload": 1,
"_msgid": "a1b2c3d4.e5f6g7"
}
// Сообщение 2 (t = 250ms)
{
"payload": 0,
"_msgid": "a1b2c3d4.e5f6g7"
}
> ℹ️ Информация: Обратите внимание, что `_msgid` у обоих сообщений одинаковый. Узел `Trigger` генерирует второе сообщение на основе того, которое его активировало, изменяя только `payload`. Это полезно для сохранения `topic` и других свойств исходного сообщения.
Этот простой пример является ядром шаблона 'Импульс'. Мы научились генерировать последовательность "включить, подождать, выключить", которая является цифровым эквивалентом нажатия кнопки.
---
Практический пример: управление реле для открытия ворот
Теперь применим полученные знания для решения реальной задачи — управления автоматическими воротами с помощью реле на контроллере HI. Предположим, что контроллер ворот имеет вход "сухого контакта" (Dry Contact), замыкание которого инициирует цикл работы ворот. Мы будем замыкать этот контакт с помощью одного из реле контроллера.
> ⚠️ Внимание: Перед подключением к реальному оборудованию убедитесь, что его управляющий вход рассчитан на тот тип сигнала, который вы подаете с реле. Неправильное подключение может повредить контроллер ворот или сам модуль реле. В данном случае мы имитируем "сухой контакт", поэтому на клеммы реле контроллера мы заводим не силовое напряжение, а управляющие провода от входа контроллера ворот.
Построение потока в Node-RED
Для управления реле, подключенным к нашему контроллеру HI, мы будем использовать протокол MQTT. Стандартная архитектура платформы HI предполагает, что каждое реле представлено в виде MQTT-топика.
Предположим, нам нужно управлять первым реле (`K1`) на модуле расширения `wb-mr6c` с MQTT-идентификатором `wb-mr6c_3`. Согласно стандарту топиков платформы, для этого используется топик `.../on`.
- Командный топик: `hi/devices/wb-mr6c_3/controls/K1/on`
- Значение `1`: Включает реле.
- Значение `0`: Выключает реле.
Наш поток будет выглядеть так:
+-----------+ +-------------------+ +-------------------------------+
| MQTT In |----->| Trigger (300ms) |----->| MQTT Out |
| gates/set | | Send 1, then 0 | | Topic: .../controls/K1/on |
+-----------+ +-------------------+ +-------------------------------+
Детальная настройка:
- `MQTT In`:
* QoS: `1`
* Output: `a string`
- `Trigger`:
* then wait for: `300` `milliseconds`
* then send: `Number` `0`
* Handle multiple messages: `ignore subsequent messages` (Важно, чтобы несколько быстрых нажатий не создавали очередь импульсов).
- `MQTT Out`:
* QoS: `1`
* Retain: `false`
Логика работы потока
{ "payload": 1 }
{ "payload": 0 }
Таким образом, мы создали надежный и простой механизм управления сложным устройством, не вдаваясь в его внутреннюю логику, а лишь подавая стандартный для него управляющий сигнал.
---
Продвинутые сценарии: импульсы переменной длительности
Бывают ситуации, когда одно и то же устройство требует импульсов разной длительности для активации разных функций. Классический пример — управление приводом штор или жалюзи:
- Короткий импульс (< 300 мс): Шаговый режим. Слегка приоткрыть/призакрыть штору или повернуть ламели.
- Длинный импульс (> 500 мс) или удержание сигнала: Полное открытие или закрытие до конечного положения.
Узел `Trigger` элегантно решает эту задачу. Его длительность задержки можно задавать не статически, а динамически, через свойство `delay` входящего сообщения.
Динамическое управление узлом 'Trigger'
Если в сообщении, приходящем на вход узла `Trigger`, присутствует свойство `msg.delay`, содержащее числовое значение в миллисекундах, узел будет использовать именно это значение для задержки, игнорируя то, что указано в его статической конфигурации.
Это позволяет построить более гибкие потоки. Например, можно использовать узел `Function` перед `Trigger` для анализа входящей команды и формирования нужной задержки.
Пример потока с узлом `Function`:Предположим, из интерфейса приходят команды в виде JSON:
- Для короткого нажатия: `{ "action": "step" }`
- Для длинного нажатия: `{ "action": "full" }`
[MQTT In] ---> [JSON Parser] ---> [Function: Set Delay] ---> [Trigger] ---> [MQTT Out]
Код для узла `Function: Set Delay`:
// Получаем объект из msg.payload
const command = msg.payload;
// Устанавливаем длительность импульса по умолчанию
let pulseDuration = 250; // ms, для шагового режима
if (command && command.action === 'full') {
// Для полного открытия установим более длинный импульс
pulseDuration = 1000; // ms
}
// Устанавливаем динамическую задержку для узла Trigger
msg.delay = pulseDuration;
// Устанавливаем payload для первого сигнала триггера
// Мы можем переопределить здесь и payload, если нужно
msg.payload = 1;
// Устанавливаем статус для визуальной отладки
node.status({
fill: "blue",
shape: "dot",
text: "Pulse: " + pulseDuration + "ms"
});
return msg;
В настройках `Trigger` теперь можно оставить задержку по умолчанию, но он будет переопределяться значением из `msg.delay`. Это мощный механизм для создания контекстно-зависимого поведения.
Альтернативный подход: узел `Delay`
Хотя `Trigger` является предпочтительным, создать импульс можно и с помощью связки из двух узлов `Change` и одного узла `Delay`:
Этот поток требует разветвления, чтобы отправить и первое, и второе сообщение.
ASCII-схема: +--> [Change: set 1] ----------------------------------+
| |
[Inject] --+--> [Delay: 250ms] --> [Change: set 0] --> [Join] --> [Debug]
^
|
+------------+
Такая конструкция менее читаема и более громоздка, чем использование одного узла `Trigger`, поэтому для генерации импульсов рекомендуется всегда в первую очередь рассматривать `Trigger`.
---
Практический пример: пошаговое управление приводом шторы (DALI/RS-485)
Рассмотрим сложный, но очень распространенный сценарий: управление шторой или жалюзи, подключенными по шине DALI или Modbus (RS-485). Такие приводы часто поддерживают несколько команд:
- `UP`/`DOWN`: Движение до конечного положения.
- `STEP_UP`/`STEP_DOWN`: Движение на один шаг (поворот ламелей или небольшое смещение).
- `STOP`: Остановка движения.
Задача: реализовать управление с помощью кнопок в интерфейсе "Вверх", "Вниз", "Стоп". При коротком нажатии на "Вверх"/"Вниз" отправлять команду `STEP_UP`/`STEP_DOWN`. При удержании — `UP`/`DOWN`, а при отпускании — `STOP`.
Наш контроллер HI инкапсулирует сложность работы с шинами DALI/RS-485. Мы будем отправлять простые JSON-команды в MQTT-топик, а системный сервис контроллера уже сам преобразует их в команды для физической шины.
Командный топик: `hi/blinds/living_room/set` Формат `msg.payload`:{ "command": "UP" }
{ "command": "STEP_UP" }
{ "command": "STOP" }
Для реализации нам понадобятся узлы, отслеживающие "нажатие" и "отпускание" кнопки в UI. В Node-RED Dashboard это можно сделать с помощью узла `ui_button`, который может отправлять разные сообщения при нажатии (`mousedown`) и отпускании (`mouseup`).
Логика потока:Для предотвращения отправки множества команд `UP` во время удержания, мы используем узел `rbe` (report-by-exception), который блокирует все сообщения, пока их `payload` не изменится.
Ниже представлен полный JSON-код потока для импорта в Node-RED, который реализует эту логику для одной кнопки "Вверх". Аналогичный поток создается и для кнопки "Вниз".
JSON для импорта в Node-RED:[
{
"id": "e2a3b4c5.d6e7f8",
"type": "comment",
"z": "...",
"name": "FLOW-BLINDS-STEP-001: Stepped Blind Control",
"info": "Реализует логику короткого/длинного нажатия для управления шторой.\nКороткое нажатие (<400мс): STEP_UP\nДлинное нажатие (>400мс): UP, затем STOP при отпускании."
},
{
"id": "a1b2c3d4.e5f6g7",
"type": "ui_button",
"z": "...",
"name": "Штора Вверх",
"group": "...",
"order": 1,
"width": 0,
"height": 0,
"passthru": false,
"label": "Вверх",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "arrow_upward",
"payload": "press",
"payloadType": "str",
"topic": "up",
"topicType": "str",
"x": 150,
"y": 200,
"wires": [
[
"f9e8d7c6.b5a4b3"
]
]
},
{
"id": "f9e8d7c6.b5a4b3",
"type": "trigger",
"z": "...",
"name": "Таймер 400мс",
"op1": "long_press",
"op2": "release",
"op1type": "str",
"op2type": "str",
"duration": "400",
"extend": true,
"override": "op2",
"units": "ms",
"reset": "release",
"bytopic": "all",
"topic": "topic",
"outputs": 2,
"x": 330,
"y": 200,
"wires": [
[
"c3d4e5f6.a7b8c9"
],
[
"g7h8i9j0.k1l2m3"
]
]
},
{
"id": "c3d4e5f6.a7b8c9",
"type": "change",
"z": "...",
"name": "Команда 'UP'",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"command\":\"UP\"}",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 510,
"y": 180,
"wires": [
[
"n4o5p6q7.r8s9t0"
]
]
},
{
"id": "g7h8i9j0.k1l2m3",
"type": "switch",
"z": "...",
"name": "Проверка таймера",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "release",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 520,
"y": 260,
"wires": [
[
"u1v2w3x4.y5z6a7"
],
[]
]
},
{
"id": "u1v2w3x4.y5z6a7",
"type": "change",
"z": "...",
"name": "Команда 'STEP_UP'",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"command\":\"STEP_UP\"}",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 720,
"y": 240,
"wires": [
[
"b8c9d0e1.f2g3h4"
]
]
},
{
"id": "b8c9d0e1.f2g3h4",
"type": "mqtt out",
"z": "...",
"name": "Отправить команду на штору",
"topic": "hi/blinds/living_room/set",
"qos": "1",
"retain": "false",
"broker": "...",
"x": 950,
"y": 220,
"wires": []
},
{
"id": "n4o5p6q7.r8s9t0",
"type": "trigger",
"z": "...",
"name": "STOP при отпускании",
"op1": "",
"op2": "{\"command\":\"STOP\"}",
"op1type": "pay",
"op2type": "json",
"duration": "-1",
"extend": false,
"override": "op2",
"units": "s",
"reset": "release",
"bytopic": "all",
"topic": "topic",
"outputs": 2,
"x": 730,
"y": 180,
"wires": [
[
"i5j6k7l8.m9n0o1",
"b8c9d0e1.f2g3h4"
],
[
"b8c9d0e1.f2g3h4"
]
]
},
{
"id": "i5j6k7l8.m9n0o1",
"type": "rbe",
"z": "...",
"name": "Блокировать дубликаты",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"septopics": false,
"property": "payload.command",
"x": 930,
"y": 140,
"wires": [[]]
}
]
Этот пример демонстрирует, как комбинация простых узлов (`Trigger`, `Change`, `Switch`) и правильная логика позволяют реализовать сложный и интуитивно понятный для пользователя интерфейс управления.
---
Итоги и лучшие практики
В этом уроке мы глубоко погрузились в шаблон 'Импульс', который является одним из краеугольных камней в арсенале инженера по автоматизации.
Краткие выводы:- Шаблон 'Импульс' применяется для управления устройствами со встроенной логикой, которые требуют лишь кратковременного сигнала для активации. Это подход "отправил и забыл" (fire-and-forget).
- Для 90% задач, связанных с генерацией импульсов, узел `Trigger` является основным, самым удобным и читаемым инструментом в Node-RED.
- Импульсный режим позволяет создавать сложные сценарии, такие как пошаговое управление или активация функций по короткому/длинному нажатию, используя динамическую настройку длительности через `msg.delay`.
Советы по отладке и документированию
Шаблон 'Импульс', несмотря на свою простоту, является мощным инструментом, который отделяет профессиональную систему автоматизации от любительской. Его правильное применение обеспечивает предсказуемость, надежность и удобство для конечного пользователя.
Что дальше
> 🔗 Связанный материал: В следующем уроке (LESSON-05-M02-L03) мы рассмотрим шаблон 'Timed' (Работа по таймеру), который расширяет концепцию управления по времени, но применяется для других задач, нежели 'Импульс'. Мы научимся создавать сценарии, где нагрузка должна быть включена на строго определенный, часто длительный промежуток времени, например, управление поливом, вентиляцией или подогревом.