ГлавнаяАкадемияСценарии умного дома: режимы, состояния, приоритеты → SCN-CLIMATE-008: 'Проветривание' (отключение отопления при открытом окне)

SCN-CLIMATE-008: 'Проветривание' (отключение отопления при открытом окне)

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

Введение в сценарий "Проветривание": логика и компоненты

Данный урок посвящен разработке одного из самых востребованных и эффективных сценариев энергосбережения в системах умного дома и автоматизации зданий — "Проветривание".

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

Базовая логика и компоненты

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

ЕСЛИ `статус окна изменился на "открыто"` ТОГДА `перевести систему отопления в режим "Выключено (Проветривание)"` ИНАЧЕ ЕСЛИ `статус окна изменился на "закрыто"` ТОГДА `вернуть систему отопления в ее предыдущий рабочий режим`

Для физической реализации этого сценария на объекте требуется минимальный набор аппаратных компонентов:

  • Датчик открытия окна: Чаще всего используется магнитоконтактный датчик (геркон). Он состоит из двух частей: магнита, установленного на подвижной створке, и самого геркона на раме. При закрытии окна магнит замыкает контакты геркона, формируя сигнал "закрыто". При открытии — контакты размыкаются. Этот датчик подключается к универсальному входу контроллера HI как "сухой контакт".
  • Исполнительное устройство системы отопления: Устройство, которым контроллер может управлять для прекращения подачи тепла. В зависимости от типа системы отопления это может быть:
  • * Термоэлектрический сервопривод на клапане радиатора.

    * Реле, управляющее электрическим конвектором.

    * Клапан на коллекторе водяного теплого пола.

    * Клапан фанкойла.

    Эти устройства подключаются к релейным выходам контроллера HI или управляются по цифровым шинам, таким как Modbus или KNX.

    Коммуникационная модель

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

    Такой подход дает несколько ключевых преимуществ:

    В следующих разделах мы пошагово реализуем этот сценарий на платформе HI с использованием Node-RED.

    ---

    Шаг 1: Получение статуса окна по MQTT

    Первым шагом в реализации нашего сценария является получение данных от датчика открытия окна. Мы настроим в Node-RED узел, который будет "слушать" MQTT-брокер и реагировать на сообщения об изменении состояния окна.

    Проектирование структуры топиков MQTT

    Правильное проектирование иерархии топиков — залог создания поддерживаемой и легко расширяемой системы.

    > 💡 Подсказка: Используйте единую и предсказуемую конвенцию именования топиков во всем проекте. Это значительно упрощает отладку, масштабирование и интеграцию с системами верхнего уровня (например, HMI-панелями).

    Рекомендуемая структура топика для устройств:

    `hi////`

    Для нашего датчика открытия окна в гостиной топик будет выглядеть так:

    `hi/living_room/sensors/main_window/contact`

    Стандартизация формата сообщений

    Чтобы избежать путаницы со строками типа `"open"`, `"closed"`, `1`, `0`, мы будем использовать стандартизированный JSON-контракт для всех сообщений. Это делает сообщения самодокументируемыми и легко расширяемыми в будущем.

    Для датчика контакта мы будем использовать следующий формат `msg.payload`:

    Настройка потока в Node-RED

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

  • Добавьте узел `mqtt in`: Перетащите узел `mqtt in` на рабочую область Node-RED.
  • Настройте узел `mqtt in`:
  • * Server: Выберите ваш предварительно настроенный MQTT-брокер.

    * Topic: Укажите топик нашего датчика: `hi/living_room/sensors/main_window/contact`.

    * Output: Установите `a parsed JSON object`. Это заставит Node-RED автоматически разбирать входящую JSON-строку в объект JavaScript.

    * Name: Дайте узлу осмысленное имя, например, `Статус окна (гостиная)`.

  • Добавьте узел `debug`: Соедините выход узла `mqtt in` с входом узла `debug`. Настройте узел `debug` на отображение `complete msg object`.
  • Разверните поток: Нажмите кнопку `Deploy`.
  • ASCII-схема потока:
                      +--------------------------+     +-----------------------+
    

    (MQTT Broker) --> | mqtt in | --> | debug |

    | Статус окна (гостиная) | | (complete msg object) |

    +--------------------------+ +-----------------------+

    Теперь, когда вы будете открывать и закрывать окно, в панели отладки (Debug) вы будете видеть входящие сообщения.

    Пример сообщения при открытии окна:
    {
    

    "_msgid": "a1b2c3d4.e5f6g7",

    "topic": "hi/living_room/sensors/main_window/contact",

    "payload": {

    "contact": false

    },

    "qos": 1,

    "retain": false

    }

    Мы успешно настроили получение данных. Следующим шагом будет добавление логики, которая будет реагировать на эти данные.

    ---

    Шаг 2: Реализация логики в Node-RED с сохранением состояния

    аг 2: Реализация логики в Node-RED с сохранением состояния

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

    Маршрутизация потока с помощью узла `switch`

    Узел `switch` идеально подходит для направления потока сообщений в зависимости от содержимого `msg.payload`.

  • Удалите узел `debug`.
  • Добавьте узел `switch` после узла `mqtt in`.
  • Настройте узел `switch`:
  • * Property: `msg.payload.contact` (мы проверяем значение поля `contact` внутри объекта `payload`).

    * Правило 1: `is false` (логическое `false`). Это соответствует открытому окну.

    * Правило 2: `is true` (логическое `true`). Это соответствует закрытому окну.

    * Name: `Окно открыто/закрыто?`

    Теперь узел `switch` имеет два выхода: первый сработает, когда окно откроется, второй — когда закроется.

    Сохранение состояния отопления с помощью `global context`

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

    Предположим, что текущее состояние нашего термостата транслируется в глобальную переменную `global.climate_living_room_state`. Этот объект может выглядеть так:

    {
    

    "mode": "auto",

    "target_temperature": 22.5,

    "current_state": "HEATING"

    }

    > 💡 Важно: Использование `global context` позволяет другим потокам (flow) учитывать, что отопление было выключено именно сценарием проветривания, а не вручную пользователем.

    Логика при открытии окна (выход 1 узла `switch`):
  • Сохранить текущее состояние: Используем узел `change` для копирования текущего состояния отопления в "резервную" глобальную переменную.
  • Сформировать команду на выключение: Используем второй узел `change` для создания команды выключения.
  • Поток для ветки "Окно открыто":
    [switch: выход 1] --> [change: Сохранить состояние] --> [change: Команда ВЫКЛ] --> [mqtt out: Упр. радиатором]
    
    * Правило 1: `Set` `global.saved_heating_state` `to` `global.climate_living_room_state`.

    * Name: `Сохранить состояние климата`.

    * Правило 1: `Set` `msg.payload` `to` (JSON) `{"state": "OFF"}`.

    * Name: `Сформировать команду OFF`.

    Восстановление состояния при закрытии окна

    Когда окно закрывается, нам нужно выполнить обратное действие: извлечь сохраненное состояние из `global.saved_heating_state` и отправить его термостату или исполнительному устройству.

    Логика при закрытии окна (выход 2 узла `switch`):
  • Восстановить сохраненное состояние: Используем узел `change`, чтобы скопировать значение из `global.saved_heating_state` в `msg.payload`.
  • Отправить команду: Отправляем это сообщение для восстановления работы климатической системы.
  • Поток для ветки "Окно закрыто":
    [switch: выход 2] --> [change: Восстановить состояние] --> [mqtt out: Упр. радиатором]
    
    * Правило 1: `Set` `msg.payload` `to` `global.saved_heating_state`.

    * Name: `Восстановить состояние климата`.

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

    Шаг 3: Интеграция со сценарием термостата и управление приоритетами

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

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

    > 💡 Что такое флаг блокировки?

    > Это переменная в глобальном контексте Node-RED (`global`), которая показывает, какой сценарий в данный момент обладает эксклюзивным правом на управление устройством. Другие сценарии обязаны проверять этот флаг перед отправкой своих команд.

    Механизм управления через флаг блокировки

    Наш сценарий "Проветривание", помимо отправки команды, будет управлять флагом в глобальном объекте состояния `HI_STATE`.

    При открытии окна (ветка 1 узла `switch`):

    Мы устанавливаем флаг блокировки, а затем отправляем команду на выключение.

    1. `Set` `global` `HI_STATE.zones.living_room.climate.override` `to` (string) `airing`. При закрытии окна (ветка 2 узла `switch`):

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

    1. `Set` `global` `HI_STATE.zones.living_room.climate.override` `to` (string) ` ` (пустая строка или `null`).

    Как это работает для других сценариев?

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

    Пример логики для сценария термостата:
    // Получаем текущее значение флага блокировки
    

    const override = global.get('HI_STATE.zones.living_room.climate.override') || '';

    // Если флаг установлен и установлен не нами, прекращаем работу

    if (override !== '' && override !== 'thermostat') {

    // Возвращаем null, чтобы остановить поток сообщений

    // Термостат временно "заморожен"

    return null;

    }

    // ... остальная логика термостата ...

    return msg;

    Почему этот подход эффективнее?

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

    ---

    Итоги, тайм-ауты и лучшие практики

    Мы успешно спроектировали и реализовали полнофункциональный сценарий "Проветривание", который корректно интегрируется с другими системами автоматизации.

    Обзор полного потока данных

  • Пользователь открывает окно.
  • Геркон на раме размыкает цепь.
  • Контроллер HI фиксирует изменение на "сухом контакте" и публикует в MQTT-топик `hi/living_room/sensors/main_window/contact` сообщение: `{ "contact": false }`.
  • Узел `mqtt in` в Node-RED получает это сообщение.
  • Узел `switch` направляет поток по ветке "окно открыто".
  • Цепочка узлов `change` устанавливает флаг `global.HI_STATE...override` в значение `airing` и формирует команду `{"state": "OFF"}`.
  • Узел `mqtt out` публикует команду `{"state": "OFF"}` напрямую в топик исполнительного устройства (`hi/living_room/climate/radiator_1/set`). Сервопривод закрывает клапан.
  • Сценарий термостата в это время может продолжать работать, но на входе он проверяет флаг блокировки. Увидев значение `airing`, он прекращает свою работу на этой итерации.
  • Когда окно закрывается, сценарий проветривания снимает флаг блокировки и отправляет команду на восстановление предыдущего состояния климата.
  • При следующем запуске сценарий термостата видит, что флаг блокировки пуст, и возобновляет свою работу в штатном режиме.
  • Расширение сценария: защита от "дребезга" и тайм-ауты

    В реальных условиях возможны ложные или быстрые срабатывания.

    🔗 Связанный материал: Студент может легко перейти к базовым урокам по антифлаппингу для повторения — COURSE-07-M04-L02 и COURSE-07-M04-L03.

    📋 Ключевые понятия для улучшения:

    * Реализация: При открытии окна запускается узел `trigger` в режиме `timeout`. Если за 30 минут не приходит сообщение о закрытии, он отправляет сигнал на другой выход. Этот сигнал можно использовать для отправки PUSH-уведомления пользователю: "Окно в гостиной открыто уже 30 минут!".

    Важность абстракции через MQTT API

    Этот урок наглядно демонстрирует мощь подхода, основанного на абстрагировании устройств. Наша логика в Node-RED не имеет ни малейшего представления о том, какой именно датчик стоит на окне (проводной геркон, беспроводной Zigbee-датчик) или чем управляется отопление (реле, Modbus-привод). Она оперирует исключительно логическими MQTT-сообщениями. Это и есть основа построения по-настоящему гибких, масштабируемых и независимых от конкретного "железа" систем автоматизации.

    Что дальше

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