ГлавнаяАкадемияОсновы умного дома → Сценарий vs. Flow: где живёт логика

Сценарий vs. Flow: где живёт логика

Урок 3 · Основы умного дома · 30 мин · theory

Введение: Два подхода к автоматизации логики

В предыдущих уроках мы установили, что современный умный дом оперирует не просто сырыми сигналами, а событиями и состояниями. Как мы рассмотрели в уроке `COURSE-01-M02-L02`, событие — это стандартизированное сообщение, например, JSON-объект, описывающий, что, где и когда произошло. А в `COURSE-01-M02-L03` мы определили состояние как зафиксированное значение системы в определенный момент времени.

Теперь мы подходим к ключевому вопросу: как система должна реагировать на эти события и изменять свои состояния? Где именно "живет" та самая интеллектуальная составляющая, которая отличает "умный" дом от простого набора дистанционно управляемых устройств?

В мире автоматизации исторически сложились две фундаментальные парадигмы для реализации логики:

  • Сценарии (декларативный подход): Пользователь или инженер описывает что должно произойти в ответ на определенное событие. Это высокоуровневый, часто визуальный способ, который скрывает сложность реализации за простым интерфейсом. Логика строится по принципу "Если произошло событие А и выполнено условие Б, то совершить действие В".
  • Потоки (императивный подход): Инженер детально проектирует как именно система должна обработать событие, шаг за шагом. Этот подход использует инструменты визуального программирования, где данные проходят через последовательность узлов-обработчиков, каждый из которых выполняет свою специфическую функцию.
  • Чтобы лучше понять разницу, представим простую аналогию.

    > Сценарий — это кулинарный рецепт в поваренной книге: "Возьмите яйца, муку, молоко. Взбейте, испеките. Подавайте с джемом". Он говорит, что* делать, но опускает детали: как именно взбивать, при какой температуре печь, как проверить готовность.

    > Поток (Flow) — это полностью оборудованная кухня со сборочной линией. Яйца попадают на конвейер, узел-миксер их взбивает, узел-печь выпекает при заданной температуре ровно заданное время, узел-контроля качества проверяет готовность, и только потом узел-сервировки добавляет джем. Этот подход описывает как* именно, шаг за шагом, получить конечный результат, контролируя каждый этап процесса.

    В рамках нашей экосистемы мы будем фокусироваться на потоковом подходе как на более гибком, мощном и профессиональном инструменте, но понимание сценарной модели необходимо для оценки всего спектра решений на рынке.

    ---

    Сценарий: Логика в GUI-конфигураторах (iRidium, Wirenboard)

    Сценарий — это набор правил, создаваемых в графическом интерфейсе (GUI) и описывающих логику системы в формате "Триггер -> Условие -> Действие" (Trigger-Condition-Action, TCA). Это самый интуитивно понятный способ создания простых автоматизаций, не требующий навыков программирования.

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

    > * Триггер (Trigger): Событие, запускающее правило. Например, "нажатие кнопки", "изменение показаний датчика движения", "наступление 22:00".

    > * Условие (Condition): Дополнительная проверка, которая должна быть истинной, чтобы правило выполнилось. Например, "только если на улице темно" И "система не стоит на охране".

    > * Действие (Action): Исполнительная команда, которая отправляется устройству. Например, "включить свет в коридоре", "отправить PUSH-уведомление", "установить температуру кондиционера на 22°C".

    Многие платформы, особенно ориентированные на конечного пользователя или быстрый ввод в эксплуатацию, предлагают встроенные редакторы сценариев. Например, в iRidium Studio или в ранних версиях ПО для контроллеров Wirenboard можно было создавать правила, выбирая триггеры, условия и действия из выпадающих списков.

    Пример гипотетического правила в GUI-редакторе:

    | Компонент | Значение |

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

    | Триггер | `Датчик движения (corridor_motion_sensor)` изменил состояние на `ON` |

    | Условие 1 | `Датчик освещенности (outdoor_light_sensor)` значение `< 100` люкс |

    | Условие 2 | `Переменная (System.Security)` значение `!= 'ARMED'` |

    | Действие | `Реле (corridor_light)` установить состояние `ON` |

    Это правило читается очень просто: "Если сработал датчик движения в коридоре, и при этом на улице темно, и дом не на охране, то включить свет в коридоре".

    > ℹ️ Информация:

    > В современных версиях программного обеспечения для контроллеров Wirenboard основным инструментом для реализации логики является Node-RED, который предустановлен на контроллер. Исторический движок правил `wb-rules` используется реже, но понимание его принципов полезно для анализа старых проектов и быстрого прототипирования очень простых задач.

    Преимущества сценарного подхода:

    Недостатки сценарного подхода:

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

    ---

    Поток (Flow): Визуальное программирование в Node-RED

    Поток (Flow) — это графическое представление программы, где логика строится путем соединения функциональных блоков (узлов) линиями связи. Для нашей платформы и для мира IoT в целом стандартом де-факто для такого подхода является Node-RED. Node-RED — это инструмент flow-based programming (FBP), который позволяет инженерам создавать сложные приложения, соединяя между собой готовые блоки. Он предустановлен на контроллер HI, что делает его основным средством реализации логики.

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

    > * Узел (Node): Базовый строительный блок в Node-RED. Каждый узел выполняет одну конкретную задачу: получает сообщение на входе, обрабатывает его и передает на выход. Примеры: прочитать MQTT-сообщение, проверить значение, выполнить математическую операцию, отправить команду на реле.

    > * Поток (Flow): Совокупность узлов, соединенных вместе для выполнения комплексной задачи. Визуально это граф, по которому "текут" данные.

    > * Сообщение (Message, `msg`): Объект JavaScript, который передается от узла к узлу. Это кровь системы автоматизации. Он несет в себе данные и метаинформацию.

    Ключевым элементом является объект `msg`. Вся работа в Node-RED — это манипуляция объектами `msg`. Основные его свойства:

    Обзор базовых узлов

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

    Пример: Поток "Включить свет по нажатию MQTT-кнопки"

    Задача: Физическая или виртуальная кнопка публикует в MQTT-топик `hi/living_room/light_switch/click` сообщение с `payload` `"TOGGLE"`. Нужно отправить команду на включение/выключение реле, которое слушает топик `hi/living_room/light_main/set`. ASCII-схема потока:
    [MQTT In] -> [Function: Toggle Logic] -> [MQTT Out]
    

    | | |

    [Debug] [Debug] [Debug]

    Логика работы:
  • Узел `mqtt in` подписывается на топик `hi/living_room/light_switch/click`. При получении сообщения он передает его дальше по потоку.
  • Сообщение попадает в узел `function` (более сложный узел, который мы рассмотрим позже, но он содержит логику переключения) или в цепочку из узлов `switch` и `change`, которая проверяет текущее состояние света и формирует противоположную команду.
  • Например, если свет был выключен (`OFF`), узел `change` установит `msg.payload` в `"ON"`.
  • Новое сообщение с `msg.payload = "ON"` и `msg.topic = "hi/living_room/light_main/set"` отправляется в узел `mqtt out`.
  • `mqtt out` публикует это сообщение в MQTT-брокере, и релейный модуль, подписанный на этот топик, включает свет.
  • Этот подход, в отличие от сценарного, дает полный контроль над каждым шагом обработки данных и позволяет создавать логику практически любой сложности.

    ---

    Практика: Реализация сценария "Я ушел" в Node-RED

    Давайте перейдем от теории к практике и реализуем классический сценарий "Я ушел", используя потоковый подход в Node-RED.

    Задача: При постановке дома на охрану система должна выполнить следующие действия:
  • Выключить все основные группы освещения.
  • Выключить все розетки, кроме критически важных (например, холодильник).
  • Перевести систему климат-контроля в экономичный режим.
  • Входное событие: MQTT-сообщение в топике `/devices/booking/controls/armed/on` со значением `1`. (Мы используем пример топиков, схожих с Wirenboard, для наглядности). Пошаговая сборка потока: Шаг 1: Прием события

    Создаем узел `mqtt in` и настраиваем его на подписку на топик `/devices/booking/controls/armed/on`.

    Шаг 2: Фильтрация события

    Нам нужно реагировать только на постановку на охрану (значение `1`). Добавляем узел `switch` после `mqtt in`. Настраиваем его так:

    Теперь только сообщения с `payload`, равным `1`, будут проходить дальше по потоку.

    Шаг 3: Формирование и отправка команд (параллельные ветки)

    От единственного выхода узла `switch` мы создадим несколько параллельных веток — по одной на каждое действие.

    > 💡 Подсказка:

    > Для улучшения читаемости и структурирования сложных потоков используйте узлы `link in` и `link out`. Они позволяют создавать "беспроводные" соединения, разбивая один большой граф на несколько визуально независимых блоков, например, 'Логика', 'Управление светом', 'Управление климатом'.

    Ветка 1: Выключить свет
  • Добавляем узел `change`. Он будет формировать команду для первой группы света.
  • * Set `msg.topic` to `/devices/wb-mr6c_33/controls/K1/on`

    * Set `msg.payload` to `0`

  • Копируем этот узел и изменяем топик для второй группы света:
  • * Set `msg.topic` to `/devices/wb-mr6c_33/controls/K2/on`

    * `msg.payload` остается `0`.

  • И так далее для всех групп света.
  • Ветка 2: Выключить розетки
  • Аналогично создаем узел `change`, который формирует команду для группы розеток:
  • * Set `msg.topic` to `/devices/wb-mr6c_34/controls/K1/on`

    * Set `msg.payload` to `0`

    Ветка 3: Перевести климат в эконом-режим
  • Создаем еще один узел `change`:
  • * Set `msg.topic` to `/devices/hvac_control/controls/mode`

    * Set `msg.payload` to `"eco"` (string)

    Шаг 4: Отправка команд

    Все выходы узлов `change` из всех веток мы соединяем с одним общим узлом `mqtt out`. Этот узел-публикатор возьмет `topic` и `payload` из каждого пришедшего на него сообщения и отправит их в MQTT-брокер.

    Результат в виде JSON (экспорт потока):
    [
    

    {

    "id": "1",

    "type": "mqtt in",

    "name": "Security Armed Event",

    "topic": "/devices/booking/controls/armed/on",

    "wires": [["2"]]

    },

    {

    "id": "2",

    "type": "switch",

    "name": "is Armed?",

    "property": "payload",

    "rules": [{"t": "eq", "v": "1", "vt": "num"}],

    "wires": [["3", "4", "5"]]

    },

    {

    "id": "3",

    "type": "change",

    "name": "Set Topic: Light Group 1 OFF",

    "rules": [

    {"t": "set", "p": "topic", "pt": "msg", "to": "/devices/wb-mr6c_33/controls/K1/on", "tot": "str"},

    {"t": "set", "p": "payload", "pt": "msg", "to": "0", "tot": "num"}

    ],

    "wires": [["99"]]

    },

    {

    "id": "4",

    "type": "change",

    "name": "Set Topic: Sockets Group OFF",

    "rules": [

    {"t": "set", "p": "topic", "pt": "msg", "to": "/devices/wb-mr6c_34/controls/K1/on", "tot": "str"},

    {"t": "set", "p": "payload", "pt": "msg", "to": "0", "tot": "num"}

    ],

    "wires": [["99"]]

    },

    {

    "id": "5",

    "type": "change",

    "name": "Set HVAC to ECO",

    "rules": [

    {"t": "set", "p": "topic", "pt": "msg", "to": "/devices/hvac_control/controls/mode", "tot": "str"},

    {"t": "set", "p": "payload", "pt": "msg", "to": "eco", "tot": "str"}

    ],

    "wires": [["99"]]

    },

    {

    "id": "99",

    "type": "mqtt out",

    "name": "Send Command to Devices",

    "wires": []

    }

    ]

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

    ---

    Централизация vs. Децентрализация: Где должна выполняться логика?

    Мы определились, что для профессиональных инсталляций мы используем Node-RED. Но возникает следующий архитектурный вопрос: где физически должен быть запущен этот Node-RED? На борту каждого контроллера? Или на одном мощном центральном сервере в стойке? Правильный ответ — гибридная модель.

    > ⚠️ Внимание:

    > Никогда не размещайте логику, отвечающую за физическую безопасность (управление замками, защита от протечек, пожарная сигнализация), на центральном сервере, если он зависит от нестабильной сетевой связи. Такая логика должна быть максимально автономной и исполняться на edge-контроллере.

    Рассмотрим два полюса и их компромисс.

    1. Логика на контроллере (Edge, децентрализованный подход)

    В этом случае Node-RED запущен на самом контроллере HI, который непосредственно управляет реле и считывает данные с датчиков.

    * Высокая надежность и автономность: Логика продолжает работать даже при полном отказе локальной сети (ЛВС) или интернета. Если выключатель и лампа подключены к одному контроллеру, свет будет включаться всегда.

    * Минимальная задержка (Low Latency): Путь сигнала "датчик -> логика -> реле" минимален, реакция системы практически мгновенная. Это критично для управления освещением.

    * Ограниченные ресурсы: Процессор и память контроллера (4 ядра / 4 ГБ RAM) не безграничны. Сложные вычисления, работа с большими базами данных или десятками потоков могут привести к замедлению работы.

    * Сложность межконтроллерного взаимодействия: Если кнопка на одном контроллере должна управлять светом на другом, их взаимодействие идет через сеть (MQTT), и мы частично теряем преимущество автономности.

    2. Логика на сервере (Central, централизованный подход)

    В этом варианте на контроллерах остается только функция шлюза I/O (ввод-вывод) — они лишь транслируют состояния входов в MQTT и исполняют команды, приходящие из MQTT. Вся логика, все потоки Node-RED исполняются на отдельном, более мощном сервере в ЛВС.

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

    * Централизация и удобство управления: Вся логика дома находится в одном месте. Проще обновлять, отлаживать и резервировать.

    * Интеграция с внешним миром: Серверу проще "ходить" в интернет для получения данных о погоде, курсах валют, интеграции с голосовыми ассистентами (Алиса, Google Assistant) и облачными API.

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

    * Зависимость от сети: Если у контроллера пропала сетевая связь с сервером, он становится "слепым" и "немым".

    3. Гибридная модель ("Золотой стандарт")

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

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

    * Все, что должно работать 24/7, даже если "упал" роутер.

    * Комплексные, некритичные сценарии: "Доброе утро" (плавное включение света, запуск музыки, подогрев полов), интеграция с голосовыми помощниками, сбор и анализ статистики, отправка отчетов, сценарии, завязанные на геолокацию или прогноз погоды.

    Этот подход сочетает надежность децентрализации с мощью и гибкостью централизации.

    ---

    Резюме: Сценарий vs. Поток

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

    | Критерий | Сценарий (Декларативный) | Поток (Императивный) |

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

    | Философия | "Что сделать?" | "Как именно это сделать?" |

    | Инструмент | GUI-редакторы (iRidium, wb-rules) | Flow-based programming (Node-RED) |

    | Порог входа | Низкий | Средний (требует инженерного мышления) |

    | Гибкость | Низкая, ограничена возможностями редактора | Очень высокая, ограничена только фантазией инженера |

    | Отладка | Затруднена | Удобна, полный контроль над потоком данных |

    | Проф. стандарт | Для простых задач и DIY-сегмента | Стандарт де-факто для профессиональных инсталляций |

    Ключевые выводы:

    Что дальше?

    В этом уроке мы увидели, как потоки реагируют на внешние события. Но для создания по-настоящему сложной логики (например, "включить свет, только если он был выключен более 5 минут назад") потоку нужно "помнить" свои предыдущие действия. Ему нужно внутреннее состояние. В следующем уроке мы подробно разберем, как хранить состояния внутри Node-RED с помощью переменных контекста (flow и global).