ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Использование ноды Trigger для фильтрации ложных срабатываний

Использование ноды Trigger для фильтрации ложных срабатываний

Урок 2 · Датчики и входы: нормализация сигналов · 30 мин · theory

Введение: Почему Trigger - лучший выбор для антидребезга

> 🔗 Связанный материал: Для полного понимания физики процесса и базовых методов борьбы с дребезгом настоятельно рекомендуется ознакомиться с материалами предыдущих уроков: «Проблема дребезга контактов: физика и последствия для логики» (COURSE-04-M03-L01) и «Программный антидребезг с помощью ноды Delay» (COURSE-04-M03-L02).

Как мы уже знаем, дребезг контактов — это неизбежное физическое явление, возникающее при замыкании/размыкании механических контактов (кнопки, реле, герконы). Вместо одного чистого сигнала контроллер получает целую серию хаотичных импульсов в течение нескольких миллисекунд. Для логики автоматизации это выглядит как многократное быстрое нажатие кнопки. Последствия могут быть самыми неприятными: от мерцания света при попытке его включить до ложной постановки системы на охрану и её немедленного срабатывания.

В предыдущем уроке мы рассмотрели простейший способ борьбы с этим явлением — использование ноды `Delay` в режиме ограничения частоты (`rate limit`). Этот метод отбрасывает все сообщения, следующие за первым, в течение заданного интервала. Несмотря на свою простоту, этот подход имеет фундаментальные недостатки, которые делают его непригодным для большинства профессиональных сценариев:

  • Блокировка потока: Нода `Delay` "оглушает" поток на заданное время. Если за первым импульсом дребезга (например, `true` от нажатия) сразу последует валидный сигнал (например, `false` от отпускания кнопки), он будет проигнорирован. Это делает невозможным реализацию логики, зависящей от момента отпускания кнопки, например, для определения длинных нажатий.
  • Сложность обработки сложных событий: Реализовать на базе `Delay` такие сценарии, как двойное или тройное нажатие, практически невозможно без громоздких и ненадежных конструкций с несколькими таймерами.
  • Отсутствие состояния: `Delay` — это простой "фильтр-вышибала". Он не хранит никакого состояния о том, что происходит. Он просто пропускает первое сообщение и блокирует остальные на N миллисекунд.
  • Именно для решения этих проблем в Node-RED существует специализированный узел — нода `Trigger`. Это "умный", неблокирующий таймер, который работает как конечный автомат (FSM). Он не просто блокирует поток, а переходит в различные состояния в зависимости от входящих сообщений и течения времени. `Trigger` позволяет не только эффективно отфильтровать дребезг, но и построить элегантную и надежную логику для обработки сложных последовательностей событий, таких как короткие и длинные нажатия, двойные клики или даже обнаружение "залипших" кнопок. Использование `Trigger` является признаком профессионального подхода к разработке потоков автоматизации на платформе HI.

    ---

    Анатомия ноды Trigger: режимы работы и конфигурация

    Нода `Trigger` на первый взгляд может показаться сложнее, чем `Delay`, но её гибкость и мощь полностью окупают время, потраченное на изучение. Давайте детально разберем её панель настроек и логику работы.

    > 💡 Подсказка: Используйте `msg.topic` для управления несколькими независимыми источниками (например, разными кнопками) с помощью одной ноды `Trigger`. Узел будет поддерживать отдельный таймер для каждого уникального топика, что значительно упрощает потоки и снижает дублирование логики.

    Основная логика ноды описывается тремя ключевыми полями:

  • `Send` (Отправить): Это действие, которое нода выполняет сразу после получения первого входящего сообщения, которое запускает таймер. Возможные варианты:
  • * The original message: Отправить точное `msg` (со всеми его свойствами), которое запустило узел.

    * The latest message: Если за время реакции оператора пришло несколько сообщений, будет отправлено самое последнее.

    * Nothing: Не отправлять ничего немедленно. Этот режим используется для сценариев, где действие должно произойти только по истечении тайм-аута (например, детекция длинного нажатия).

    * Пользовательское значение: Можно задать любое статичное значение (строку, число, JSON), которое будет отправлено в `msg.payload`.

  • `then wait for` (затем ждать): Это длительность тайм-аута. Узел входит в режим ожидания на указанное количество миллисекунд, секунд, минут или часов. Пока таймер активен, нода находится в "вооруженном" состоянии.
  • `and then send` (и затем отправить): Это действие, которое выполняется по истечении тайм-аута. Если за время ожидания таймер не был сброшен, нода отправит второе сообщение. Здесь также можно выбрать, что отправлять: оригинальное `msg`, последнее, ничего или пользовательское значение. Это ключевая функция для реализации логики "длинного нажатия" или "тайм-аута бездействия".
  • Важные опции

    Выходы ноды

    Нода `Trigger` имеет два выхода, что расширяет её возможности:

    Понимание этой двухчастной структуры (немедленное действие + действие по тайм-ауту) и механизма сброса — ключ к эффективному использованию `Trigger` в реальных проектах автоматизации.

    ---

    Практикум: Создание базового фильтра дребезга для кнопки

    Теперь применим полученные знания на практике. Наша задача — создать надежный фильтр дребезга для физической кнопки, подключенной к универсальному входу контроллера HI. Сигнал от кнопки публикуется в MQTT-топик `hi/inputs/button_01`.

    Пошаговая инструкция

  • Создайте поток. Разместите на поле ноды `MQTT In`, `Trigger` и `Debug`. Соедините их последовательно, как показано на схеме.
  • ASCII-схема потока `FLOW-AUTO-DEBOUNCE-001`:

        [MQTT In: button_01] -----> [Trigger: Debounce] -----> [Debug: Clean Signal]

  • Настройте `MQTT In`.
  • * Сервер: Выберите ваш MQTT-брокер.

    * Топик: `hi/inputs/button_01`.

    * Выход: `a parsed JSON object` (если кнопка шлет JSON) или `a string`. Предположим, кнопка при нажатии отправляет строку `"ON"`.

    > ℹ️ Информация: В реальной системе сигнал от физического входа (например, UI1) будет преобразован в MQTT-сообщение отдельным, очень простым потоком. Мы здесь моделируем уже результат этого преобразования.

  • Настройте `Trigger` для антидребезга. Это ключевой шаг. Наша цель — пропустить только самый первый сигнал `"ON"` и проигнорировать всю последующую "грязь" в течение короткого промежутка времени.
  • * Send: `the original message payload`. Это значит, что на выход будет передано `"ON"`.

    * then wait for: `250` milliseconds. Этого времени более чем достаточно для затухания дребезга у большинства кнопок и реле.

    * and then send: `nothing`. Нам не нужно второе событие по тайм-ауту.

    * Name: "Антидребезг 250мс".

    Галочки `Extend delay...` и `Handle every message` должны быть сняты.

  • Настройте `Debug`. Убедитесь, что нода `Debug` настроена на отображение полного объекта сообщения (`complete msg object`), чтобы видеть результат работы.
  • Анализ потока сообщений

    Давайте посмотрим, что произойдет при нажатии на физическую кнопку:

        msg.payload: "ON"
    

    msg.payload: "OFF"

    msg.payload: "ON"

    msg.payload: "OFF"

    msg.payload: "ON"

    ...

    1. Нода `Trigger` получает первое сообщение (`"ON"`).

    2. Она немедленно отправляет его на свой выход, и мы видим в `Debug` одно-единственное сообщение.

            {

    "payload": "ON",

    "topic": "hi/inputs/button_01",

    "_msgid": "..."

    }

    3. Сразу после этого нода переходит в режим ожидания на 250 мс.

    4. Все последующие сообщения дребезга (`"OFF"`, `"ON"`, `"OFF"`...), приходящие в течение этих 250 мс, будут просто проигнорированы.

    5. Через 250 мс таймер завершается. Так как в поле `and then send` выбрано `nothing`, ничего не происходит. Нода возвращается в исходное состояние и готова к обработке следующего нажатия.

    Таким образом, вместо хаотичной серии импульсов наша основная логика (которая будет подключена после `Trigger`) получает один чистый и предсказуемый сигнал.

    JSON-конфигурация для импорта

    Вы можете скопировать этот JSON и импортировать его в ваш Node-RED (`Меню -> Import`), чтобы быстро получить готовый к работе узел `Trigger`.

    [
    

    {

    "id": "e6a2b8f1.195d48",

    "type": "trigger",

    "z": "...",

    "name": "Антидребезг 250мс",

    "op1": "payload",

    "op2": "0",

    "op1type": "msg",

    "op2type": "str",

    "duration": "250",

    "extend": false,

    "overrideDelay": false,

    "units": "ms",

    "reset": "",

    "bytopic": "all",

    "topic": "topic",

    "outputs": 1,

    "x": 450,

    "y": 200,

    "wires": [

    []

    ]

    }

    ]

    ---

    Продвинутый сценарий: обработка длинных нажатий и 'залипших' кнопок

    Теперь, когда мы освоили базу, рассмотрим более сложный и востребованный на практике сценарий: как отличить короткое нажатие от длинного.

    Бизнес-задача:

    Для этого нам понадобятся оба выхода ноды `Trigger` и механизм сброса. Важно, чтобы физическая кнопка или логика её обработки отправляла разные сообщения при нажатии (`press`) и отпускании (`release`).

    > ⚠️ Внимание: При разработке логики сброса таймера убедитесь, что ваше 'сбрасывающее' сообщение гарантированно доставляется. Если сообщение об отпускании кнопки по какой-то причине потеряется, узел `Trigger` может навсегда остаться в состоянии ожидания (если он не был настроен на отправку по тайм-ауту) или ложно сработать по тайм-ауту, отправив команду длинного нажатия.

    Поток для обработки длинных нажатий `FLOW-AUTO-LIGHT-012`

    // Сигнал от физической кнопки (нажатие "press", отпускание "release")
    

    [MQTT In] --+--> [Switch: "press"/"release"] --+-- "press" --> [Trigger: Long Press] --+-- (выход 1, short)--> [Debug]

    | | +-- (выход 2, long) --> [Debug]

    | +-- "release" -> [Change: add reset] ---+

    |

    +--> [Trigger: Debounce] --> (основная логика после фильтра)

    (Для ясности, здесь показаны два пути обработки: верхний - для определения длительности, нижний - для простого антидребезга.)

    Сосредоточимся на логике определения длительности нажатия.

  • Настройка `Trigger` для детекции длинного нажатия:
  • * Send: `nothing`. Мы не знаем, будет ли нажатие коротким или длинным, поэтому не действуем сразу.

    * then wait for: `1` second. Это порог для определения длинного нажатия.

    * and then send: `{"command": "start_dimming"}` (строка или JSON). Это сообщение будет отправлено на второй выход, если кнопка удерживалась 1 секунду.

    * Включить галочку `Handle every message`. Это позволит нам сбросить таймер.

    * В поле `reset the trigger if msg.payload arrives with the value` укажите `release`. Это значение, которое будет сбрасывать таймер.

  • Логика работы:
  • 1. Пользователь нажимает кнопку. Приходит сообщение с `msg.payload: "press"`.

    2. `Trigger` получает это сообщение. Он ничего не отправляет и "взводит" таймер на 1 секунду.

    3. Сценарий 1: Короткое нажатие.

    * Пользователь отпускает кнопку через 400 мс. Приходит сообщение с `msg.payload: "release"`.

    * `Trigger` получает это "сбрасывающее" сообщение. Он немедленно прерывает таймер и возвращается в исходное состояние.

    * Но как же тогда отправить команду короткого нажатия? Для этого нам нужен отдельный узел. Сообщение `release` после сброса `Trigger`-а мы можем направить в `Change` ноду, которая сформирует `{"command": "toggle"}`.

    4. Сценарий 2: Длинное нажатие.

    * Пользователь удерживает кнопку более 1 секунды.

    * Сообщение `release` не приходит.

    * Таймер в ноде `Trigger` истекает.

    * Нода отправляет на свой второй (нижний) выход сообщение `{"command": "start_dimming"}`.

    * Когда пользователь наконец отпустит кнопку, придет сообщение `release`, которое просто сбросит уже отработавший `Trigger` в исходное состояние, не производя никаких действий.

    Обнаружение "залипшей" кнопки

    Этот же паттерн можно использовать для повышения надежности системы. Представьте, что механическая кнопка вышла из строя и "залипла" в нажатом состоянии.

    * `Send`: `nothing`.

    * `then wait for`: `10` seconds.

    * `and then send`: `{"alert": "Button stuck", "source": "hi/inputs/button_01"}`.

    * Механизм сброса тот же — по сообщению `release`.

    Если в течение 10 секунд после нажатия не пришло сообщение об отпускании, система автоматически сгенерирует тревожное сообщение. Его можно записать в `audit_log` в MySQL, отправить в Telegram администратору или отобразить на панели мониторинга. Это простой и эффективный способ проактивной диагностики неисправностей.

    ---

    Заключение: Сравнительный анализ и рекомендации

    Выбор правильного инструмента для фильтрации сигналов — залог стабильной и предсказуемой работы всей системы автоматизации. Давайте сведём ключевые отличия между `Delay` и `Trigger` в одну таблицу.

    | Критерий | Нода `Delay` (в режиме rate limit) | Нода `Trigger` |

    | :--- | :--- | :--- |

    | Тип блокировки | Блокирующий. Игнорирует все сообщения в "окне" после первого. | Неблокирующий. Обрабатывает сообщения, меняя свое внутреннее состояние. |

    | Обработка событий | Только первое событие в серии. | Первое событие, событие по тайм-ауту, событие сброса. |

    | Поддержка состояний | Нет (Stateless). Не "помнит" ничего о потоке. | Да (Stateful). Является конечным автоматом с состояниями "ожидание", "активен". |

    | Гибкость | Низкая. Только простая фильтрация. | Высокая. Антидребезг, длинные нажатия, watchdog, детекция "залипания". |

    | Сложность | Очень низкая. | Средняя, требует понимания концепции состояний и тайм-аутов. |

    | Основной сценарий | Задержка выполнения действия. Простое ограничение потока данных (не сигналов!). | Фильтрация дребезга контактов. Обработка сложных последовательностей событий. |

    Ключевые выводы и рекомендации

    Нода `Trigger` — это значительно более мощный и гибкий инструмент по сравнению с `Delay`, когда речь идет об обработке дискретных сигналов от физических устройств.

    Освоив `Trigger`, вы делаете важный шаг от простого "склеивания нод" к осознанному проектированию надежных и функциональных потоков автоматизации.

    Что дальше?

    В следующих уроках мы закрепим полученные знания в практических лабораторных работах, где вам предстоит самостоятельно реализовать и отладить потоки с использованием `Trigger` на реальном или виртуальном оборудовании, а затем проверить свои знания в итоговом тесте модуля.