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

SCN-LIGHT-012: Сцена 'Я ушел' (выключение всего света)

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

Концепция глобального сценария 'Я ушел'

онцепция глобального сценария 'Я ушел'

Сценарий «Я ушел» (SCN-LIGHT-012) — это один из краеугольных камней любой серьезной системы умного дома. Его основное назначение — перевести дом или квартиру в режим «Отсутствие» одним действием, гарантируя, что все второстепенные потребители энергии, и в первую очередь освещение, будут отключены.

Ключевые аспекты пользы сценария

Польза этого сценария проявляется в трех магистральных аспектах:

  • Экономия электроэнергии. Сценарий предотвращает бессмысленную работу осветительных приборов, забытых включенными в разных комнатах, что напрямую влияет на снижение счетов за электричество.
  • Повышение безопасности. Выключение всего света (за исключением дежурной подсветки) снижает вероятность ложного впечатления о присутствии хозяев для посторонних. В более расширенной версии сценарий может также отключать потенциально опасные приборы, такие как утюги или обогреватели, подключенные через умные розетки.
  • Удобство пользователя (UX). Вместо того чтобы обходить все комнаты перед уходом, пользователь совершает одно простое действие — нажимает мастер-кнопку у двери, дает голосовую команду или уходит из дома, доверяя автоматике рутинную задачу. Дом самостоятельно разрешает все конфликты состояний.
  • Глобальный характер и каскадные изменения

    Ключевым отличием этого сценария является его глобальный характер. В отличие от локальных сценариев, таких как «включить свет по движению в коридоре», который оперирует одним-двумя устройствами в рамках одной зоны, глобальный сценарий затрагивает множество систем и подсистем по всему объекту. Он является действием верхнего уровня, которое не просто управляет устройствами, а меняет общее состояние дома.

    В иерархии автоматизации сценарий «Я ушел» является основным инструментом для управления глобальными режимами «Присутствие» и «Отсутствие». Активация этого сценария сигнализирует системе, что в доме никого нет. Это событие действует как системный override (переопределение правил), который служит триггером для других подсистем:

    Связь со сценарием «Имитация присутствия»

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

    Активация режима «Отсутствие» выступает жестким условием (флагом) для активации логики сценария Имитации присутствия.

    Поскольку система после запуска «Я ушел» достоверно знает, что дом пуст и локальное физическое управление отсутствует, автоматика получает разрешение (карт-бланш):

    Таким образом, мы рассматриваем сценарий «Я ушел» не просто как функционал «выключить весь свет», а как событие-инициатор, запускающее каскад логических изменений в поведении всей экосистемы умного дома.

    Триггеры активации: от настенной кнопки до геолокации

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

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

    Физические триггеры

    Это наиболее надежный и интуитивно понятный способ активации. Обычно это одна кнопка, расположенная у входной двери.

    | Плюсы физических триггеров | Минусы физических триггеров |

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

    | Высокая надежность и предсказуемость | Требуют физического нажатия, можно забыть |

    | Не зависят от работы сети Wi-Fi или интернета | Требуют монтажных работ и прокладки кабеля (часто) |

    | Интуитивно понятны всем членам семьи и гостям | Ограниченная гибкость (кнопка всегда в одном месте) |

    Виртуальные триггеры

    Это элементы управления в программных интерфейсах.

    Голосовые команды

    Интеграция с голосовыми ассистентами делает управление еще более естественным.

    Автоматические триггеры

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

    > ⚠️ Внимание: При использовании геолокации как единственного триггера необходимо предусмотреть «защиту от дурака»: ложные срабатывания GPS, разрядившийся телефон, несколько человек в доме, один из которых ушел. Рекомендуется комбинировать геолокацию с другими условиями (например, «последний пользователь покинул геозону И в доме нет движения в течение 5 минут») или использовать ее как вспомогательный, а не основной триггер.

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

    > 💡 Связанные автоматизации: Логика «Имитации присутствия»

    > Важно понимать, что переход глобальной переменной присутствия в состояние `AWAY` запускает не только каскадное выключение света, медиа и розеток. Это же системное событие является главным условием для автоматической активации сценария «Имитация присутствия».

    >

    > Логическая связь между уходом из дома и безопасностью работает так:

    > 1. Сценарий «Я ушел» (независимо от того, как он запущен — кнопкой у двери или постановкой на охрану) гасит рабочий свет и переводит систему в режим `AWAY`.

    > 2. Смена состояния на `AWAY` активирует триггеры в логике безопасности дома.

    > 3. Если наступает вечер (по датчику освещенности или координатам солнца), а дом продолжает находиться в состоянии `AWAY`, система запускает алгоритм периодического включения и выключения заданных групп освещения для отпугивания злоумышленников.

    >

    > (Подробная настройка и архитектура этой логики рассматривается в отдельном уроке, посвященном сценариям имитации присутствия).

    Формирование списка целевых устройств

    ормирование списка целевых устройств

    Прежде чем отдавать команду «выключить все», система должна точно знать, «что именно» является светом и «как» им управлять. Существует два подхода к формированию этого списка.

    Статический подход

    Самый простой, но наименее гибкий метод. Список всех устройств жестко прописывается внутри узла `function` в виде массива.

    Пример (не рекомендуется):
    let devices = [
    

    { cmd_topic: "hi/lights/living_room/main/set", type: "on_off" },

    { cmd_topic: "hi/lights/kitchen/spot/set", type: "dimmable" },

    { cmd_topic: "hi/lights/bedroom_1/desk/set", type: "on_off" },

    // ... и так далее для всех 50-100 светильников

    ];

    // ... логика обработки

    Основной недостаток этого подхода — ужасная поддерживаемость. При добавлении нового светильника или изменении MQTT-топика инженеру придется искать и редактировать код этого конкретного сценария.

    Динамический подход (рекомендуемый)

    Более профессиональный и масштабируемый метод, основанный на использовании глобального контекста (global context) Node-RED. Список устройств хранится в одном месте и может быть использован множеством разных сценариев.

  • Создаем поток инициализации. Создается отдельный поток в Node-RED, который запускается один раз при старте контроллера с помощью узла `inject` (с опцией `Inject once after 0.1 seconds`).
  • Определяем структуру. В узле `function` этого потока мы определяем полный список наших осветительных приборов в виде массива объектов. Каждый объект должен содержать всю необходимую для управления информацию.
  • 📋 Ключевые понятия: Структура объекта устройства

  • Сохраняем в глобальный контекст. Массив сохраняется в `global` для доступа из любого потока.
  • Пример кода для узла `function` в потоке инициализации:
    // FLOW-SYS-INIT-001: Инициализация глобальных переменных
    
    

    const LIGHT_DEVICES = [

    {

    id: "light_living_room_main",

    name: "Основной свет в гостиной",

    cmd_topic: "hi/lights/living_room/main/set",

    stat_topic: "hi/lights/living_room/main/state",

    type: "dimmable",

    presence_sim: true // Участвует в имитации присутствия

    },

    {

    id: "light_kitchen_spots",

    name: "Споты на кухне",

    cmd_topic: "hi/lights/kitchen/spots/set",

    stat_topic: "hi/lights/kitchen/spots/state",

    type: "dimmable",

    presence_sim: true

    },

    {

    id: "light_corridor_1",

    name: "Свет в коридоре",

    cmd_topic: "hi/lights/corridor_1/set",

    stat_topic: "hi/lights/corridor_1/state",

    type: "on_off",

    presence_sim: false // В коридоре свет для имитации не нужен

    },

    {

    id: "sockets_kitchen_worktop",

    name: "Розетки на кухне",

    cmd_topic: "hi/sockets/kitchen/worktop/set",

    stat_topic: "hi/sockets/kitchen/worktop/state",

    type: "on_off",

    presence_sim: false

    }

    // ... и остальные устройства

    ];

    // Сохраняем массив в глобальный контекст

    global.set("ALL_LIGHT_DEVICES", LIGHT_DEVICES);

    node.status({ fill: "green", shape: "dot", text: `Загружено ${LIGHT_DEVICES.length} устройств` });

    return null; // этот поток больше ничего не делает

    Теперь, чтобы добавить новый светильник, достаточно отредактировать этот единственный список. Все сценарии, которые его используют (включая «Я ушел»), автоматически начнут работать с обновленным перечнем.

    Логическая связь со сценарием «Имитация присутствия»

    Сценарий «Я ушел» — это не просто разовая команда на отключение всех потребителей в доме, но и важнейший триггер для перехода глобального режима умного дома в состояние «Никого нет» (Away). Именно это изменение состояния запускает связанные фоновые процессы охраны, включая имитацию присутствия.

    Когда система фиксирует уход жильцов (срабатывает кнопка у выхода или алгоритм определения присутствия), умный дом выполняет выключение света и переводит свой глобальный статус в режим `Away`. Отдельная логика автоматики подхватывает этот статус и начинает отслеживать наступление сумерек, чтобы случайным образом включать и выключать определенные лампы (те самые, у которых установлен флаг `presence_sim: true`), создавая реалистичную видимость присутствия людей в помещениях. Подробная реализация этой механики разбирается в отдельном уроке, посвященном сценариям имитации присутствия.

    > 💡 Архитектурный плюс глобального массива

    > Добавив свойство `presence_sim` прямо на этапе формирования списка, мы избавляем себя от необходимости создавать второй список для симуляции. Глобальный массив `ALL_LIGHT_DEVICES` служит единым источником истины: сценарий «Я ушел» использует его для выключения всего освещения, а планировщик имитации присутствия из этого же массива берет только те светильники, у которых флаг `presence_sim` установлен в `true`.

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

    еализация логики в Node-RED

    Теперь, имея триггер и динамический список устройств, мы можем собрать основной поток сценария SCN-LIGHT-012.

    Cхема потока (ASCII-диаграмма):
               +-----------+    +------------------------------+    +-------------+         +----------+
    

    [mqtt in] | | | | | | | |

    (Триггер) -->| Switch |--> | Function (Сформировать |--> | Split |--[msg]-->| mqtt out |

    `.../set` | (проверка | | команды для всех устройств) | | (Разделить | | (Отправка|

    | payload) | | | | на потоки) | | команд) |

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

    1. Узел `mqtt in` (Триггер)

    2. Узел `switch` (Фильтр)

    Этот узел проверяет, что пришла именно команда на установку режима «Отсутствие».

    3. Узел `function` (Основная логика)

    Это сердце нашего сценария. Он извлекает список устройств из глобального контекста, перебирает его и формирует массив сообщений для отправки.

    // ID: FLOW-AUTO-LIGHT-012
    

    // Узел: function 'Формирование команд выключения'

    // 1. Получаем список устройств из глобального контекста

    const devices = global.get("ALL_LIGHT_DEVICES");

    // Проверяем, что список существует и не пуст

    if (!devices || !Array.isArray(devices) || devices.length === 0) {

    node.warn("Список устройств (ALL_LIGHT_DEVICES) не найден или пуст в глобальном контексте.");

    return null;

    }

    // 2. Создаем массив для будущих MQTT-сообщений

    let messages = [];

    // 3. Перебираем все устройства в цикле

    for (const device of devices) {

    let newMsg = {};

    let payload = {};

    // 4. Формируем payload в зависимости от типа устройства

    if (device.type === 'on_off') {

    // Для обычного реле отправляем команду OFF

    payload = { "state": "OFF" };

    } else if (device.type === 'dimmable') {

    // Для диммера устанавливаем яркость в 0

    payload = { "brightness": 0 };

    } else {

    // Пропускаем устройства с неизвестным типом

    continue;

    }

    // 5. Собираем новое сообщение

    newMsg.topic = device.cmd_topic;

    newMsg.payload = payload;

    // Добавляем сообщение в наш массив

    messages.push(newMsg);

    }

    // 6. Помещаем весь массив сообщений в payload исходного msg

    // Это нужно для передачи в узел 'split'

    msg.payload = messages;

    node.status({fill:"blue", shape:"dot", text:`Сформировано ${messages.length} команд`});

    // Отправляем сообщение дальше

    return msg;

    4. Узел `split` (Итератор)

    На вход этого узла приходит одно сообщение, у которого `msg.payload` является массивом. Узел `split` разбивает этот массив на последовательность отдельных сообщений. Для каждого элемента массива будет создано и отправлено свое сообщение. `msg.payload` каждого нового сообщения будет равен элементу массива, а остальные свойства (включая `msg.topic`) будут скопированы из исходного `newMsg`, созданного в цикле `for` внутри узла `function`.

    5. Узел `mqtt out` (Исполнитель)

    Этот узел получает на вход последовательность сообщений от `split` и отправляет каждое из них в свой MQTT-топик.

    Topic: оставляем пустым*, так как топик задан в свойстве `msg.topic` для каждого сообщения. QoS: оставляем пустым* (или `0`).

    > 💡 Подсказка: Чтобы не перегружать MQTT-брокер и физические шины (RS-485, DALI, KNX) лавиной одновременных команд, можно добавить узел `delay` между `split` и `mqtt out`. Настройте его в режиме Rate Limit (например, `10 messages per second`). Это создаст небольшую паузу между командами, делая работу системы более плавной и надежной.

    6. Интеграция со сценарием «Имитация присутствия»

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

    Параллельно с выключением света, тот же самый статус `AWAY` из топика `hi/system/modes/presence/set` запускает логику иллюзии нахождения людей дома (периодическое включение торшеров, бра или настольных ламп). Эта связь позволяет автоматизировать безопасность жилья без дополнительных интерфейсных кнопок по четкому алгоритму:

  • Инициация: Пользователь нажимает мастер-кнопку у выхода или активирует режим «Я ушел» в приложении. В топик уходит `state: "AWAY"`.
  • Гашение (Текущий сценарий): Данный поток немедленно реагирует, перебирает все источники света и безусловно отправляет команды `OFF` / спад яркости до `0`. Оставленные лампы гарантированно гаснут.
  • Активация охранной логики: Параллельный поток подхватывает тот же статус `AWAY`. Включается таймер-расписание, который через определенные интервалы начинает зажигать и гасить избранные светильники, имитируя присутствие людей.
  • Такое разделение позволяет гибко управлять домом: мы сначала переводим жилье в нулевое состояние (выключено все), а затем поверх него накладываем охранный паттерн. Настройка параллельного потока, использующего этот триггер для генерации случайных задержек и управления выделенными светильниками, подробно разбирается в уроке, посвященном сценарию «Имитация присутствия» (см. модуль M07-L03).

    Обработка исключений и приоритетов

    бработка исключений и приоритетов

    В реальной жизни почти никогда не бывает так, что нужно выключить абсолютно всё. Всегда есть исключения. Кроме того, сценарий «Я ушел» не всегда должен выполняться.

    Список исключений

    Некоторые устройства не должны выключаться никогда или только в определенных условиях.

    Реализация:

    Создается еще один массив в глобальном контексте, содержащий `id` устройств-исключений.

    // В потоке инициализации (FLOW-SYS-INIT-001) добавляем:
    

    const LIGHT_EXCEPTIONS = [

    "light_aquarium_main",

    "light_corridor_duty"

    ];

    global.set("LIGHT_EXCEPTIONS", LIGHT_EXCEPTIONS);

    Затем дорабатываем код в основном узле `function` сценария «Я ушел»:

    // ... внутри узла function 'Формирование команд выключения' ...
    
    

    const devices = global.get("ALL_LIGHT_DEVICES");

    // Получаем список исключений

    const exceptions = global.get("LIGHT_EXCEPTIONS") || [];

    let messages = [];

    for (const device of devices) {

    // ====> НОВАЯ ПРОВЕРКА <====

    // Если id устройства есть в списке исключений, пропускаем его

    if (exceptions.includes(device.id)) {

    continue; // Переход к следующей итерации цикла

    }

    // ... остальная логика формирования payload ...

    }

    // ...

    Интеграция с системой приоритетов

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

    Теперь интегрируем наш сценарий с системой приоритетов. Для этого мы направим команду от триггера не напрямую в сценарий, а на вход универсального «Диспетчера приоритетов» (рассматривается в материалах по централизованному управлению моделями: Урок COURSE-07-M03-L03). Этот диспетчер (реализованный как `subflow`) централизованно управляет всеми глобальными режимами.

    Принцип работы:
  • Источник (кнопка ухода, голосовая команда) отправляет исходное намерение на специальный «входной» топик диспетчера, например, `hi/system/commands/set_presence`.
  • Диспетчер приоритетов получает команду. Он проверяет текущий глобальный режим (например, `global.get("system_mode")`), который может быть `PARTY`, `GUESTS`, `ALARM` и т.д.
  • Принятие решения. Диспетчер содержит логику, согласно которой команда «Я ушел» игнорируется, если активен режим с более высоким приоритетом (например, `GUESTS`).
  • Перенаправление. Если команда разрешена к исполнению, диспетчер публикует ее в "официальный" топик нашего сценария: `hi/system/modes/presence/set` с сообщением `{"state": "AWAY"}`.
  • Схема взаимодействия:
                                            +---------------------------------+
    

    | Диспетчер приоритетов (subflow) |

    [Триггер "Я ушел"]--(команда)-->[MQTT_вход]--| (Урок COURSE-07-M03-L03) |-->[MQTT_выход]--+

    | Проверяет global.mode | |

    +---------------------------------+ |

    | (если разрешено)

    v

    [Топик: hi/system/modes/presence/set]

    |

    v

    [Наш сценарий SCN-LIGHT-012]

    Связь со сценарием «Имитация присутствия»

    Сценарий «Я ушел» работает в неразрывной связи с механизмами безопасности умного дома. Переход глобального режима присутствия в состояние `AWAY` — это не только команда на выключение, но и логический триггер для запуска охранных алгоритмов.

    Одним из важнейших таких сценариев является логика Имитации присутствия (ее реализация подробно разбирается в уроке COURSE-07-M07-L03).

    Автоматическая цепочка событий:

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

  • Событие: Диспетчер приоритетов публикует статус `AWAY` в `hi/system/modes/presence/set`.
  • Зачистка (текущий сценарий): Сценарий «Я ушел» (SCN-LIGHT-012) немедленно выключает свет по списку устройств (за вычетом исключений).
  • Обновление состояния: По завершении цикла выключения сценарий обновляет глобальную переменную: `global.set("presence_mode", "AWAY");`.
  • Активация (сценарий имитации): Сценарий имитации присутствия, подписанный на изменение `presence_mode`, видит переход в статус `AWAY` и переходит в дежурный режим. С наступлением сумерек он начнет воспроизводить паттерны "жилого дома".
  • > 💡 Изоляция исполнения: Обратите внимание на важный нюанс: наш сценарий «Я ушел» не вызывает логику имитации напрямую. Обе ветви полностью независимы и просто подписываются на общее событие/переменную статуса системы. Благодаря тому, что «Я ушел» отрабатывает единоразово в момент изменения статуса, он не конфликтует и не будет "гасить" лампы, которые впоследствии начнёт зажигать сценарий имитации присутствия.

    Преимущества такой структуры:

    Итоги и интеграция со смежными системами

    тоги и интеграция со смежными системами

    Мы успешно спроектировали и реализовали глобальный сценарий SCN-LIGHT-012 «Я ушел». Это мощный и гибкий инструмент для централизованного управления, который строится на нескольких ключевых принципах:

  • Унифицированный триггер: Использование единого MQTT-сообщения для запуска сценария из разных источников.
  • Централизованный список устройств: Хранение перечня устройств в `global context` для легкой поддержки и масштабируемости.
  • Итеративная отправка команд: Применение связки `function` + `split` для последовательной отправки команд каждому устройству.
  • Обработка исключений и приоритетов: Реализация "умной" логики, которая учитывает особые устройства и глобальные режимы работы дома.
  • Этот сценарий является не конечной точкой, а отправной базой для более глубокой интеграции. Событие «в доме никого нет» может и должно использоваться другими подсистемами:

    > 🔗 Связанный материал: Настройка логики рандомизации и связь события ухода с активацией режима «Имитация присутствия» подробно разбираются в уроке Сценарии имитации присутствия (M07-L03). Дополнительно, методы работы с датчиками освещенности и диммированием, описанные в материалах по базовому включению (SCN-LIGHT-001) и адаптивному свету (SCN-LIGHT-005), могут быть использованы совместно с логикой отсутствия для создания максимально естественного «поведения» умного дома в вечернее и ночное время.

    Что дальше

    В следующем уроке мы рассмотрим зеркальный сценарий — SCN-LIGHT-013 «Я пришел». Мы научимся: