ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → Концепция конечного автомата (State Machine) для управления домом

Концепция конечного автомата (State Machine) для управления домом

Урок 2 · Сценарии умного дома: режимы, состояния, приоритеты · 30 мин · theory

Введение в конечные автоматы (State Machine): формальное определение и аналогии

ведение в конечные автоматы (State Machine): формальное определение и аналогии

В основе надежного управления сложными системами, будь то промышленный робот или современный умный дом, лежит концепция, позволяющая избежать хаоса и непредсказуемости. Эта концепция — конечный автомат или Finite State Machine (FSM).

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

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

Простая аналогия: бытовой выключатель

Самый простой пример FSM — это обычный настенный выключатель света.

* Если система в состоянии `Выключено` и происходит событие `Нажатие`, она переходит в состояние `Включено`. Действие — замыкание электрической цепи.

* Если система в состоянии `Включено` и происходит событие `Нажатие`, она переходит в состояние `Выключено`. Действие — размыкание электрической цепи.

Важно то, что реакция на событие (`Нажатие`) напрямую зависит от текущего состояния. Это ключевое отличие от примитивных сценариев.

Преимущества FSM для умного дома

Когда мы переносим эту модель на умный дом, мы получаем мощный инструмент для организации логики. Простой сценарный подход ( "если датчик движения сработал, то включи свет") быстро приводит к проблемам. Что, если свет уже включен? Что, если сейчас день? Что, если активирован режим "Кино", который требует приглушенного освещения?

| Подход | Простой сценарий ("Если-То") | Конечный автомат (FSM) |

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

| Логика | Реагирует на событие изолированно. `Событие -> Действие`. | Реагирует на событие с учетом контекста. `(Событие + Текущее состояние) -> Новое состояние + Действие`. |

| Предсказуемость | Низкая. Два разных сценария могут конфликтовать, пытаясь одновременно управлять одним и тем же устройством (гонка состояний, или race condition). | Высокая. Система всегда находится в одном из известных состояний, а переходы между ними строго определены. |

| Тестируемость | Сложная. Требуется проверять множество комбинаций одновременных событий. | Простая. Можно протестировать каждый переход отдельно, зная начальное состояние, событие и ожидаемое конечное состояние. |

| Масштабируемость | Низкая. Добавление нового условия часто требует переписывания существующих сценариев, что приводит к "лапше" из узлов. | Высокая. Можно добавлять новые состояния или переходы, не затрагивая остальную логику. Можно создавать иерархию автоматов (суб-автоматы). |

| Пример конфликта | Сценарий "Выключить все" выключает свет в гостиной, а сценарий "Датчик движения" тут же его включает, потому что кто-то проходит к выходу. | Глобальное состояние дома переходит в "Никого". В этом состоянии автомат освещения гостиной игнорирует события от датчика движения, предотвращая конфликт. |

Место FSM в архитектуре сценариев

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

  • Антифлаппинга (M04): Чтобы игнорировать "дребезг" датчиков, система должна четко контролировать состояние ожидания.
  • Гистерезиса (M06): Управление климатом невозможно без фиксации промежуточных состояний системы между включением и выключением нагрева.
  • Использование FSM заставляет инженера-автоматизатора мыслить структурированно: сначала определить все возможные состояния системы (например, дома или комнаты), а затем — правила игры, по которым она будет жить. Это путь от реактивной автоматизации к проактивному, интеллектуальному управлению.

    "Глобальное состояние" дома как центральный конечный автомат

    Глобальное состояние" дома как центральный конечный автомат

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

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

    Ключевые глобальные состояния дома

    Для типичного жилого объекта можно выделить несколько основных состояний:

    События и переходы

    Переходы между этими состояниями вызываются конкретными событиями в системе:

    | Начальное состояние | Событие | Конечное состояние | Действия при переходе |

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

    | `Никого` | `Пришел первый жилец` (first_person_arrived) | `Дома` | Запустить сцену "Возвращение домой": включить свет в прихожей, установить комфортную температуру, включить медиасистему. |

    | `Дома` | `Ушел последний жилец` (last_person_left) | `Никого` | Запустить сцену "Выключить все": погасить свет, отключить неприоритетные розетки, перевести климат-контроль в эконом-режим, активировать датчики на вход. |

    | `Дома` | `Активирован ночной режим` (night_mode_on) | `Сон` | Приглушить свет, активировать ночники, понизить температуру для сна, отключить звук уведомлений. |

    | `Сон` | `Утреннее пробуждение` (morning_wakeup) | `Дома` | Плавно включить свет в спальне, запустить утренний плейлист, повысить температуру. |

    | `Никого` | `Активирован режим отпуска` (vacation_on) | `Отпуск` | Перекрыть воду, полностью отключить климатические системы, активировать полный периметр охраны и сценарий имитации присутствия. |

    События могут поступать из разных источников:

    Хранение состояния на контроллере HI

    Критически важно, чтобы глобальное состояние дома не терялось при перезагрузке контроллера, будь то плановое обслуживание или сбой питания. Если после включения контроллер "забудет", что дом был в состоянии `Никого`, он может неверно отреагировать на первое же событие.

    Для этого в Node-RED используется персистентный контекст. На контроллере HI, оснащенном EEPROM и стабильной файловой системой на базе Debian, можно и нужно настроить хранение переменных контекста в файлах. Это гарантирует, что при старте Node-RED переменная, хранящая состояние FSM, будет восстановлена.

    Пример объекта, описывающего состояние, который будет храниться в `global.home_fsm`:

    {
    

    "currentState": "Away",

    "previousState": "Home",

    "lastTransition": "2023-10-27T18:30:00Z",

    "triggeredBy": {

    "source": "mqtt_presence_tracker",

    "event": "last_person_left"

    }

    }

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

    ---

    Итак, мы рассмотрели теоретические основы конечных автоматов и их ключевую роль в создании центрального "мозга" умного дома. Эта концепция является фундаментом для всей дальнейшей логики курса. Прежде чем переходить к прикладным сценариям, нам необходимо научиться "чистить" входные данные, чтобы избежать ложных срабатываний FSM. В следующих уроках мы изучим механизмы антифлаппинга и гистерезиса, которые строятся на базе состояний, а также разберем инструменты управления приоритетами и создания переиспользуемых блоков (Subflows). Только обеспечив стабильность входных сигналов и иерархию команд, мы приступим к финальной сборке сложных алгоритмов управления.

    Декомпозиция: суб-автоматы для управления подсистемами

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

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

    > 🔗 Связанный материал: Вспомните урок COURSE-07-M01-L02, где мы разделяли понятия 'Режим' и 'Сцена'. Глобальное состояние FSM ('Сон') — это по сути 'Режим', который инициирует запуск конкретных 'Сцен' (включение ночников, установка t°).

    Существует два основных типа декомпозиции:

  • Параллельные суб-автоматы: Несколько FSM работают одновременно и независимо, управляя каждый своей подсистемой (климат, освещение, безопасность).
  • Иерархические суб-автоматы: Один FSM верхнего уровня (глобальный) может принудительно изменять состояния "дочерних" FSM.
  • На практике чаще всего используется гибридный подход. Глобальный FSM определяет общий "контекст" или "режим" дома, а суб-автоматы реализуют детальную логику внутри этого контекста.

    Пример 1: Глобальный FSM и суб-автомат климата

    Представим систему климат-контроля, которая имеет свой собственный FSM для управления кондиционером:

    В обычном режиме (когда глобальное состояние `Дома`), этот суб-автомат работает автономно, поддерживая комфортную температуру. Но что происходит, когда глобальный FSM меняет состояние?

    Сценарий: Последний жилец уходит, и глобальный FSM переходит из `Дома` в `Никого`.
  • Глобальный FSM генерирует исходящее сообщение: `{ payload: "Away", ... }`.
  • Это сообщение поступает на специальный "управляющий" вход суб-автомата климата.
  • Суб-автомат климата имеет правило: при получении внешнего события `force_eco`, он принудительно переходит в состояние `Эко` из любого другого состояния.
  • В `Эко` состоянии суб-автомат игнорирует показания датчиков температуры и просто поддерживает минимально допустимую температуру (например, +18°C), экономя энергию.
  • Таким образом, глобальный автомат не управляет напрямую кондиционером. Он делегирует это суб-автомату, но оставляет за собой право устанавливать "правила игры".

    Пример 2: Суб-автомат для освещения в домашнем кинотеатре

    Логика освещения при просмотре кино может быть довольно сложной. Ее идеально вынести в отдельный суб-автомат.

    * Состояния: `Выключено` (Off), `Просмотр` (Viewing), `Пауза` (Paused), `Полный свет` (FullLight).

    * События: `Нажата кнопка Play`, `Нажата кнопка Pause`, `Воспроизведение остановлено`.

    * Действия:

    * Переход в `Просмотр`: плавно погасить основной свет, оставить только контурную подсветку.

    * Переход в `Пауза`: плавно поднять яркость основного света до 30%.

    * Переход в `Полный свет`: установить яркость на 100%.

    Этот суб-автомат активируется и принимает события от медиаплеера только тогда, когда глобальное состояние дома `Дома`. Если дом переведен в режим `Ночь` или `Никого`, суб-автомат кинотеатра либо принудительно переводится в состояние `Выключено`, либо просто перестает получать события.

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

    ---

    Пример: Конечный автомат для управления поливом

    Рассмотрим практический пример создания сложного сценария с помощью FSM — автоматической системы полива газона. Простой таймер, включающий полив каждый день в 6 утра, неэффективен: он будет работать и во время дождя, и когда почва еще влажная. Умная система должна учитывать множество факторов.

    Задача

    Создать надежный и экономичный FSM для управления клапаном полива, который будет учитывать:

    Проектирование FSM

  • Определяем состояния:
  • * `Idle` (Ожидание): Основное состояние, в котором система находится большую часть времени. Клапан полива закрыт.

    * `Watering` (Полив): Идет процесс полива. Клапан открыт.

    * `RainPause` (Пауза из-за дождя): Полив отложен или прерван из-за текущего или прогнозируемого дождя.

  • Определяем события (входящие `msg.topic`):
  • * `schedule_trigger`: Наступило время полива по расписанию (например, от узла `cron-plus`).

    * `rain_forecasted`: Получен прогноз о дожде в ближайшие часы (от погодного API).

    * `rain_cleared`: Прогноз дождя отменен.

    * `soil_is_dry`: Датчик влажности почвы показал значение ниже порогового.

    * `watering_timer_expired`: Истек таймер запланированной длительности полива.

    * `manual_start`: Пользователь нажал кнопку ручного запуска.

    * `manual_stop`: Пользователь нажал кнопку ручной остановки.

  • Определяем переходы и действия:
  • | Из состояния | Событие (`Input`) | В состояние | Действия (Actions) |

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

    | `Idle` | `schedule_trigger` | `Watering` | Если нет флага `rain_forecasted`: Открыть клапан полива (Modbus-команда), запустить таймер на N минут. |

    | `Idle` | `rain_forecasted` | `RainPause` | Записать в лог: "Полив отложен из-за прогноза дождя". |

    | `Idle` | `manual_start` | `Watering` | Открыть клапан полива, запустить таймер на N минут. |

    | `Watering` | `watering_timer_expired` | `Idle` | Закрыть клапан полива. Отправить MQTT-уведомление "Полив завершен". |

    | `Watering` | `rain_forecasted` | `RainPause` | Закрыть клапан полива. Отправить MQTT-уведомление "Полив прерван из-за дождя". Остановить таймер. |

    | `Watering` | `manual_stop` | `Idle` | Закрыть клапан полива. Остановить таймер. |

    | `RainPause` | `rain_cleared` | `Idle` | Записать в лог: "Запрет на полив снят". |

    | `RainPause` | `soil_is_dry` | `Watering` | Принудительный полив: Открыть клапан, запустить таймер (игнорируем дождь, т.к. почва сухая). |

    Реализация в Node-RED

    ASCII-схема потока:
    //========= Sources of Events =========
    

    [cron-plus: 6am daily] -> [function: set topic 'schedule_trigger'] --+

    |

    [http request: weather API] -> [function: parse rain] --------------+--> [fsm: Watering FSM] -> [switch: by state]

    | |

    [modbus-read: soil sensor] -> [function: check threshold] -----------+ +-- (Watering) -> [function: Open Valve] -> [modbus-write]

    | |

    [mqtt in: manual_control] ------------------------------------------+ +-- (Idle/Rain) -->[function: Close Valve]-> [modbus-write]

    |

    +-- (any change) -> [function: Log & Notify] -> [mqtt out]

    Логика узлов:
        // Код в "Open Valve"
    

    msg.payload = {

    value: true,

    'fc': 5, // Force Single Coil

    'unitid': 1,

    'address': 10 // Адрес реле клапана

    };

    return msg;

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

    ---

    Итоги и лучшие практики проектирования

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

    > 💡 Подсказка: Используйте онлайн-инструменты, такие как diagrams.net (draw.io), для визуализации ваших конечных автоматов. Такая диаграмма — лучшая документация для вашего проекта, понятная как вам, так и вашим коллегам.

    Резюмируя, FSM — это ваш главный инструмент для управления состояниями, режимами и сложными взаимодействиями в проектах автоматизации на платформе HI.

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

    Чтобы ваши конечные автоматы были эффективными и легко поддерживаемыми, следуйте четырем ключевым правилам:

  • Всегда начинайте с проектирования на бумаге или в диаграмме.
  • Прежде чем перетащить хоть один узел в Node-RED, возьмите лист бумаги или откройте редактор диаграмм. Определите все возможные состояния вашей системы (дома, комнаты, подсистемы). Затем нарисуйте стрелками все легитимные переходы между ними. Подпишите каждую стрелку событием, которое ее вызывает. Этот простой шаг сэкономит вам часы отладки в будущем.

  • Используйте иерархию: глобальный FSM и дочерние суб-автоматы.
  • Не пытайтесь создать один автомат для всего. Выделите глобальный FSM для основных режимов дома (`Дома`, `Никого`, `Сон`). Для каждой сложной подсистемы (климат, полив, медиа) создайте свой, отдельный FSM. Глобальный автомат должен задавать "контекст", а суб-автоматы — действовать в рамках этого контекста.

  • Храните состояния в персистентном контексте.
  • Это не рекомендация, а требование для создания профессиональной системы. Состояние вашего дома должно переживать любые перезагрузки контроллера. Используйте файловую систему контроллера HI для хранения переменных контекста (`global` или `flow`), настроив `contextStorage` в вашем `settings.js`.

  • Делайте состояния и переходы как можно более "чистыми".
  • Старайтесь разделять логику управления состоянием и логику выполнения действий. Идеальный FSM-узел (`node-red-contrib-fsm`) должен заниматься только одним: получать события и менять состояние. А уже после него узел `switch` должен анализировать новое состояние и запускать соответствующие потоки действий (включение света, отправка команд по Modbus, отправка уведомлений). Это делает систему более модульной и тестируемой.

    Что дальше?

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