ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Создание универсального subflow для антидребезга

Создание универсального subflow для антидребезга

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

Введение в Subflows: инкапсуляция логики и переиспользование

В процессе разработки сложных систем автоматизации на платформе Node-RED инженеры неизбежно сталкиваются с повторяющимися задачами: обработка данных с однотипных датчиков, управление стандартными исполнительными механизмами, реализация типовых алгоритмов. Копирование и вставка групп узлов для решения этих задач — путь к созданию запутанных, труднообслуживаемых и подверженных ошибкам проектов. Решением этой проблемы является Subflow (подпоток).

Subflow — это механизм Node-RED, позволяющий инкапсулировать, или "упаковать", последовательность узлов и их логику в единый, переиспользуемый компонент. Его можно рассматривать как аналог функции или процедуры в традиционных языках программирования. Создав Subflow один раз, вы можете многократно использовать его в разных частях вашего проекта, как если бы это был стандартный узел из палитры.

> 💡 Подсказка: Используйте Subflow, если планируете применять одну и ту же логику более двух раз в проекте. Это значительно упростит дальнейшее обслуживание и обновление системы.

Преимущества использования Subflows

  • Сокращение дублирования (Принцип DRY - Don't Repeat Yourself): Вместо того чтобы десятки раз создавать одну и ту же цепочку узлов для фильтрации дребезга контактов от кнопок, вы создаете один Subflow `debounce-filter` и используете его экземпляры.
  • Упрощение визуальной структуры: Сложная логика, состоящая из 5-10 узлов, "сворачивается" в один аккуратный блок. Основной поток становится чище, его логика читается значительно легче, что соответствует паттерну "Читаемость" из фреймворка нашей Академии.
  • Централизованное управление логикой: Если вы обнаружили ошибку или решили улучшить алгоритм (например, добавить логирование), вам достаточно отредактировать только один Subflow. Все его экземпляры в проекте автоматически обновятся. Это кардинально снижает трудозатраты на поддержку и модернизацию.
  • Создание стандартных библиотек: Subflows можно экспортировать в виде JSON-файлов и использовать в других проектах или передавать коллегам. Это позволяет формировать корпоративную библиотеку проверенных решений (`FLOW-AUTO-DEBOUNCE-001`), повышая качество и скорость разработки в рамках всей компании.
  • Структура Subflow

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

    | Элемент | Описание |

    | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

    | Узел `input` | Определяет одну или несколько точек входа для сообщений (`msg`) в Subflow. Каждое входящее сообщение поступает на этот узел и передается дальше по внутренней логике. |

    | Узел `output` | Определяет одну или несколько точек выхода. Когда сообщение достигает этого узла, оно покидает Subflow и передается на узлы, подключенные к выходу экземпляра Subflow в основном потоке. |

    | Узел `status` | Особый узел, который позволяет экземпляру Subflow отображать свой собственный статус (цвет, форма, текст) в основном потоке, так же как это делают стандартные узлы. Незаменим для визуальной диагностики. |

    | Панель свойств | Позволяет определить настраиваемые параметры для каждого экземпляра Subflow. Эти параметры называются переменными окружения (environment variables) и делают Subflow по-настоящему гибким и универсальным. |

    | Вкладка `Appearance` | Содержит поля для задания иконки, цвета, имени и, что самое важное, документации для вашего Subflow. Текст, введенный здесь, будет отображаться в стандартной панели "Info" Node-RED. |

    Ключевое отличие от групп: группа — это лишь визуальное объединение на холсте, она не создает нового узла и не позволяет централизованно управлять логикой. Subflow — это шаблон, на основе которого создаются независимые, но связанные с шаблоном экземпляры.

    ---

    Проектирование универсального Subflow для антидребезга

    Прежде чем приступать к созданию Subflow, необходимо четко спроектировать его внутреннюю логику и внешний интерфейс. Наша задача — создать универсальный фильтр дребезга, который можно будет применять для любых дискретных сигналов: кнопок, выключателей, герконов на дверях, реле давления и других "сухих контактов".

    Как мы рассмотрели в предыдущих уроках (`LESSON-04-M03-L02` и `LESSON-04-M03-L03`), для борьбы с дребезгом можно использовать узлы `Delay` и `Trigger`. Узел `Trigger` является более гибким и мощным инструментом для этой задачи, поэтому он ляжет в основу нашего решения. Однако сам по себе он не решает проблему множественных срабатываний одного и того же состояния.

    Выбор оптимальной комбинации узлов

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

  • Узел `rbe` (Report by Exception): Этот узел пропускает сообщение дальше только в том случае, если его `msg.payload` отличается от `msg.payload` предыдущего сообщения. При дребезге контактов (`1 -> 0 -> 1 -> 0 -> ... -> 1`) узел `rbe` пропустит только первое изменение состояния (`1 -> 0`), заблокировав все последующие "ложные" переключения в то же состояние `0`, идущие подряд. Это значительно снижает нагрузку на последующие узлы.
  • Узел `trigger`: Этот узел станет сердцем нашего фильтра. Мы настроим его так, чтобы он реагировал на входящее сообщение (прошедшее через `rbe`), но отправлял стабильный сигнал только по истечении заданного тайм-аута. Это позволяет "переждать" всю серию колебаний контакта и выдать только одно, финальное значение.
  • Логика работы будет следующей:

    `Сырой сигнал -> rbe (блокировка дублей) -> trigger (ожидание стабилизации) -> Чистый сигнал`

    Определение настраиваемых параметров

    Чтобы наш Subflow был универсальным, он должен быть настраиваемым. Разные физические устройства имеют разное время дребезга. Для быстрой кнопки может быть достаточно задержки в 20 мс, а для медленного контактора — 100 мс или больше.

    > 📋 Ключевые понятия:

    > Главным настраиваемым параметром нашего Subflow будет время задержки фильтрации (debounce time). Мы вынесем его в переменные окружения Subflow, чтобы инженер мог задавать это значение прямо в настройках узла-экземпляра, не погружаясь в его внутреннюю реализацию.

    Это позволит использовать один и тот же Subflow для разных задач: один экземпляр с задержкой 50 мс для настенного выключателя, другой — с задержкой 200 мс для датчика уровня воды с поплавком.

    Проектирование входов и выходов

    Контракт нашего Subflow должен быть простым и понятным:

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

    ---

    Практика: создание Subflow с настраиваемой задержкой

    Теперь перейдем от проектирования к реализации. Мы создадим Subflow `DEBOUNCE-DIGITAL-INPUT`, который реализует описанную выше логику.

    Шаг 1: Создание пустого Subflow

  • В интерфейсе Node-RED откройте главное меню (три горизонтальные линии в правом верхнем углу).
  • Выберите пункт `Subflows`.
  • В открывшемся меню нажмите кнопку `Create Subflow`.
  • Откроется новая вкладка-редактор. Node-RED автоматически добавит в нее узлы `input` и `output`.
  • Шаг 2: Построение внутренней логики

    Перетащите из палитры и соедините узлы в следующей последовательности:

    [input 1] -> [rbe] -> [trigger] -> [output 1]
    

    Эта простая цепочка и есть скелет нашего фильтра.

    Шаг 3: Настройка узлов

    Теперь детально настроим каждый узел внутри Subflow.

    1. Узел `rbe` (режим "block unless value changes"): 2. Узел `trigger`:

    Это самый важный узел. Его настройка определяет поведение всего фильтра.

    * `Единицы измерения`: выберите `milliseconds`.

    Пример конечного `msg` от узла `trigger` будет содержать `payload`, который был у последнего сообщения, пришедшего на его вход.

    Шаг 4: Настройка свойств Subflow

    Теперь сделаем наш параметр `DEBOUNCE_MS` доступным для настройки извне.

  • Находясь в редакторе Subflow, нажмите кнопку `Edit properties` вверху.
  • В секции Environment Variables нажмите кнопку `+add`.
  • Откроется форма для добавления переменной:
  • * Property Name: `DEBOUNCE_MS`. Это имя должно точно совпадать с тем, что мы указали в узле `trigger` (`$(DEBOUNCE_MS)`).

    * UI Label: `Задержка, мс`. Это та надпись, которую инженер увидит в настройках узла.

    * Type: `number` (число).

    * Default Value: `50`. Это значение будет использоваться, если инженер не задаст свое. 50 мс — хорошее универсальное значение для начала.

    * Icon: Можете выбрать иконку, например, `fa-clock-o`.

    После этого нажмите `Done`. Теперь наш Subflow готов. Переименуйте его (например, в `DEBOUNCE-DIGITAL-INPUT`) и нажмите `Close` для сохранения. В вашей палитре узлов (в категории `subflows`) появится новый узел с заданным именем.

    // Пример входящего потока сообщений от дребезжащей кнопки.
    

    // Интервал между сообщениями ~5-15 мс.

    msg.payload: 1

    msg.payload: 0

    msg.payload: 1

    msg.payload: 0

    msg.payload: 1

    msg.payload: 1 // Узел rbe заблокирует это сообщение

    // Пример msg, который будет на выходе из Subflow DEBOUNCE-DIGITAL-INPUT

    // после того, как пройдет 50 мс с момента прихода последнего сообщения.

    {

    "payload": 1,

    "topic": "",

    "_msgid": "..."

    // ... другие свойства оригинального последнего сообщения

    }

    ---

    Пример: интеграция и тестирование антидребезга на 'сухом контакте'

    Рассмотрим, как применить созданный Subflow для фильтрации сигнала от физической кнопки, подключенной к универсальному входу `UI-05` контроллера HI.

    Шаг 1: Интеграция Subflow в основной поток

  • Перейдите на вкладку вашего основного проекта.
  • Найдите в палитре узел `subflow DEBOUNCE-DIGITAL-INPUT` и перетащите его на холст.
  • Подключите к его входу узел, который опрашивает "сухой контакт". В нашем случае это может быть узел `rpi gpio in`, настроенный на пин, соответствующий `UI-05`.
  • Шаг 2: Настройка экземпляра

    Дважды щелкните по узлу Subflow в вашем потоке. Откроется окно его свойств. Вы увидите поле `Задержка, мс` со значением по умолчанию `50`. Для нашей кнопки, которая оказалась довольно "шумной" в ходе тестов, мы установим значение `70`.

    > ⚠️ Внимание: Не устанавливайте слишком большое время задержки для датчиков, требующих быстрой реакции (например, датчик протечки). Для каждого типа сигнала подбирайте минимально необходимое значение антидребезга, используя тестовый стенд, разработанный нами в уроке `LESSON-04-M03-L04`. Слишком большая задержка может быть воспринята пользователем как "торможение" системы.

    Шаг 3: Тестирование и сравнение "до" и "после"

    Чтобы наглядно увидеть результат работы фильтра, построим простую тестовую схему:

                              +-> [debug] (Название: "Сырой сигнал")
    

    |

    [rpi gpio in] (UI-05)-+

    |

    +-> [DEBOUNCE-DIGITAL-INPUT] -> [debug] (Название: "Чистый сигнал")

    (Задержка, мс: 70)

  • Разверните проект, нажав `Deploy`.
  • Откройте панель отладки (`debug`).
  • Нажмите физическую кнопку, подключенную к `UI-05`.
  • Результат в панели отладки:

    Вы увидите примерно следующую картину:

    // Логи от "Сырой сигнал"
    

    11.03.2024, 15:30:01.102, msg: 1

    11.03.2024, 15:30:01.108, msg: 0

    11.03.2024, 15:30:01.115, msg: 1

    11.03.2024, 15:30:01.124, msg: 0

    11.03.2024, 15:30:01.131, msg: 1

    // Лог от "Чистый сигнал" (появится через 70 мс после последнего "сырого" сообщения)

    11.03.2024, 15:30:01.201, msg: 1

    Как видите, вместо хаотичного потока из пяти сообщений за 30 миллисекунд, наша основная логика, подключенная после Subflow, получит только одно, стабильное и достоверное сообщение `msg.payload: 1`. Задача решена. Мы создали надежный, настраиваемый и переиспользуемый компонент.

    ---

    Итоги и лучшие практики документирования и экспорта Subflows

    В этом уроке мы сделали важный шаг от простого создания потоков к профессиональной инженерной практике — инкапсуляции логики. Создание переиспользуемых компонентов (Subflows) является одним из ключевых паттернов для построения масштабируемых и поддерживаемых систем на платформе HI. Это позволяет не только экономить время, но и повышать надежность всей системы за счет использования многократно проверенных стандартных блоков.

    Лучшие практики документирования

    Чтобы ваши Subflows были действительно полезны для вас и вашей команды, следуйте этим простым правилам:

    Экспорт и версионирование

    Что дальше?

    Теперь, когда у нас есть надежный инструмент для фильтрации дискретных сигналов, мы готовы перейти к работе с более сложными типами входов. В следующем модуле мы погрузимся в мир аналоговых сигналов (0-10В, 4-20мА) и научимся их калибровать, масштабировать и фильтровать от помех.