ГлавнаяАкадемияОсновы умного дома → Сценарии для офиса: Управление переговорными

Сценарии для офиса: Управление переговорными

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

Введение и архитектура решения

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

> ℹ️ Информация: Статистика показывает, что до 40% забронированного времени переговорные комнаты пустуют из-за отмены встреч или их досрочного завершения. Автоматизация помогает вернуть эти "потерянные" часы в рабочий ресурс компании, автоматически освобождая комнату при отсутствии людей.

Обзор компонентов системы

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

* Датчик присутствия: Ключевой элемент для определения фактического использования комнаты. Мы можем использовать комбинированные датчики, такие как WB-MSW v.3, которые сочетают в себе ИК-датчик движения, датчик освещенности, датчик шума и сенсор качества воздуха (CO2). Для более точного определения именно присутствия, а не движения, все чаще применяются mmWave-радары, способные обнаружить даже сидящего неподвижно человека.

* Датчик CO2: Незаменим для контроля качества воздуха. Повышенный уровень углекислого газа напрямую влияет на продуктивность и самочувствие людей.

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

* Реле и диммеры: Управляют освещением. Реле (встроенные в контроллер или внешние, как WB-MR6C) используются для включения/выключения недиммируемых групп света, диммеры (например, WB-MDM3) — для плавной регулировки яркости.

* Приводы: Электроприводы для штор, жалюзи или проекционного экрана. Управляются через реле или специализированные модули.

* Климатическое оборудование: Фанкойлы, системы вентиляции, кондиционеры. Интегрируются чаще всего по протоколу Modbus RTU/TCP.

Архитектура на базе MQTT

Центральным звеном, связывающим все компоненты в единую экосистему, является протокол MQTT. Контроллер Wirenboard выступает в роли MQTT-брокера.

Логическая схема обмена данными:
                  +-------------------------+

| Система бронирования |

| (Google/MS Calendar) |

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

| (API/CalDAV)

v

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

| Панель iRidium | <--> | Контроллер (Wirenboard) | <--> | Датчики (MSW-v3) |

| (MQTT Client) | | MQTT-брокер | | (MQTT Client) |

+----------------+ | Node-RED | +------------------+

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

| |

v v

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

| Освещение (Реле) | | Климат/AV (Modbus/RS485) |

| (MQTT Client) | +-------------------------+

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

  • Node-RED подписывается на данные API календарей, чтобы знать о запланированных встречах.
  • Датчики публикуют свои показания (движение, уровень CO2, освещенность) в соответствующие MQTT-топики.
  • Node-RED, получая данные из календаря и от датчиков, анализирует ситуацию и принимает решение.
  • Node-RED публикует команды в MQTT-топики для исполнительных устройств (например, включить свет, изменить уставку температуры).
  • Панель iRidium подписывается на MQTT-топики статусов, чтобы отображать актуальное состояние комнаты, и публикует команды при ручном управлении.
  • Базовые состояния переговорной

    Для управления логикой мы вводим конечный автомат (State Machine) с четырьмя основными состояниями. Текущее состояние хранится в переменной контекста Node-RED.

    | Состояние | Триггер перехода | Действия системы |

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

    | Свободна (Free) | Встреча завершена; бронь отменена из-за отсутствия людей. | Все оборудование выключено, климат в эконом-режиме (+25°C). На панели горит зеленый индикатор. |

    | Забронирована (Booked) | Пришло событие из календаря (встреча начнется через 15 минут). | Включается дежурное освещение (30%), климат переходит в комфортный режим (+22°C). На панели - желтый. |

    | Идет встреча (In Progress)| Статус "Забронирована" И пришло событие от датчика присутствия. | Включается основной свет, AV-оборудование. На панели горит красный индикатор. |

    | Требует проветривания | Встреча завершилась И уровень CO2 > 1200 ppm. | Выключается свет, но вентиляция переходит в усиленный режим. На панели отображается спец. статус. |

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

    ---

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

    Чтобы автоматизация была действительно "умной", она должна знать о планах использования переговорной. Для этого система должна интегрироваться с корпоративными календарями, такими как Google Calendar или Microsoft 365 (Outlook).

    > ⚠️ Внимание: Никогда не храните API-ключи, токены и учетные данные напрямую в узлах Node-RED. Это небезопасно, так как при экспорте потока они сохранятся в виде простого текста. Используйте встроенный механизм `credentials` или переменные окружения для их безопасного хранения.

    Способы получения данных из календарей

    Существует два основных подхода к получению данных о событиях:

  • Polling через API (опрос по API): Это наиболее гибкий метод. Node-RED периодически (например, раз в минуту) отправляет запрос к API сервиса (Google Calendar API, Microsoft Graph API), чтобы получить список предстоящих событий для конкретного календаря (переговорной). Этот метод позволяет не только читать, но и изменять события (например, отменять бронь при "no-show"). Однако он требует создания приложения в консоли разработчика Google/Microsoft, получения API-ключей и настройки OAuth 2.0.
  • Стандарт CalDAV/iCal: Большинство календарных сервисов предоставляют "секретную ссылку" в формате iCalendar (.ics). Эта ссылка дает доступ к данным календаря в режиме "только чтение". Это более простой в настройке способ, не требующий сложных манипуляций с API, и идеально подходящий для нашей задачи, если нам нужно только получать информацию о бронировании.
  • Мы сфокусируемся на втором, более простом и универсальном методе с использованием стандарта iCal.

    Настройка узла `node-red-contrib-ical-events`

    Для работы с iCal-ссылками мы будем использовать специализированный узел `node-red-contrib-ical-events`.

    Пошаговая настройка:
  • Установка узла: В интерфейсе Node-RED перейдите в "Manage palette" -> "Install" и найдите `node-red-contrib-ical-events`. Нажмите "Install".
  • Получение iCal-ссылки:
  • * Для Google Calendar: Зайдите в настройки нужного календаря, найдите раздел "Интеграция календаря" и скопируйте "Секретный адрес в формате iCal".

    * Для Microsoft 365: В Outlook Web App зайдите в "Настройки" -> "Календарь" -> "Общие календари". Опубликуйте календарь и скопируйте ICS-ссылку.

  • Добавление и настройка узла:
  • * Перетащите узел `ical events` на поле редактора.

    * Дважды кликните по нему для открытия настроек.

    * Нажмите на иконку карандаша для добавления новой конфигурации `ical-config`.

    * В поле `URL` вставьте скопированную iCal-ссылку.

    * Задайте имя, например, "Календарь Переговорной №1".

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

    Парсинг данных о событии

    Когда узел `ical events` обнаруживает предстоящее или текущее событие, он генерирует сообщение `msg`. Его содержимое — это ключ к нашей логике.

    Пример `msg.payload` для текущего события:

    {
    

    "summary": "Еженедельный синк по проекту 'Альфа'",

    "topic": "Календарь Переговорной №1",

    "id": "a1b2c3d4e5f6g7h8@google.com",

    "location": "Переговорная 'Сириус'",

    "description": "Обсуждаем прогресс, блокираторы и следующие шаги.",

    "start": "2023-10-27T10:00:00.000Z",

    "end": "2023-10-27T11:00:00.000Z",

    "attendees": [

    { "email": "user1@company.com", "status": "accepted" },

    { "email": "user2@company.com", "status": "needsAction" }

    ],

    "allDay": false,

    "calendar": "Переговорная №1",

    "state": "on",

    "on": true,

    "off": false

    }

    📋 Ключевые поля:

    Безопасное хранение учетных данных

    Даже если вы используете простую iCal-ссылку, она является секретной. Ее не следует хранить в открытом виде. При настройке узла `ical-config`, вы вводите URL в стандартное поле. Node-RED по умолчанию сохранит его в файле потока. Чтобы повысить безопасность:

  • Используйте переменные окружения: Вы можете задать URL как переменную окружения для Node-RED. Например, в файле настроек `settings.js`: `process.env.ICAL_URL_ROOM1`. В самом узле вы затем сможете указать `${ICAL_URL_ROOM1}`.
  • Механизм `credentials`: Если бы мы работали с API, требующим логин и пароль, мы бы вводили их в поля, помеченные иконкой ключа. Node-RED сохраняет эти данные в отдельном, зашифрованном файле (`_cred.json`), который не следует добавлять в систему контроля версий (Git). Это стандартная лучшая практика.
  • Интеграция с календарем — это первый шаг к созданию контекстно-зависимой автоматизации. Далее мы объединим эту информацию с данными реального мира от датчиков.

    ---

    Логика управления: присутствие и бронь

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

    Разработка state-машины в Node-RED

    Для реализации state-машины мы будем активно использовать контекст потока (flow context). Это позволяет хранить переменные (в нашем случае, текущее состояние переговорной) между различными запусками потока.

  • Инициализация состояния: Создайте узел `Inject`, который запускается один раз при старте Node-RED (`Inject once after 0.1 seconds`). Он устанавливает начальное состояние комнаты в "Свободна".
  • * Узел `Change`: `Set flow.room_state to "Free"`.

  • Обработка событий: Все входящие события (от календаря и от датчиков) поступают в центральный узел `Switch`, который маршрутизирует их в зависимости от текущего состояния `flow.room_state`.
  • Пример логики для сценария "No-show":
  • Узел `ical events` присылает сообщение о начале бронирования.
  • Логика меняет `flow.room_state` на `"Booked"`.
  • Запускается узел `Trigger`, который ждет 15 минут.
  • Если за это время от датчика присутствия не придет сообщение, `Trigger` отправит сигнал на отмену.
  • Если же датчик присутствия сработал, другой узел `Trigger` отменит таймер "no-show".
  • Обработка данных с датчиков присутствия

    Датчики присутствия — источник частых проблем из-за ложных срабатываний или, наоборот, "потери" неподвижных людей.

    * Фильтрация: Не выключайте свет сразу после того, как датчик перестал видеть движение. Используйте узел `Trigger`: после получения сигнала `motion: false`, он ждет (например, 5 минут) и только потом отправляет команду на выключение. Любое новое движение за это время должно сбрасывать таймер.

    Создание функции на JS для объединения статусов

    Центральный узел `Function` является ядром принятия решений. Он получает на вход данные (от датчика или календаря) и анализирует их в контексте текущего состояния.

    // Получаем текущее состояние комнаты из контекста потока
    

    let roomState = flow.get("room_state") || "Free";

    let booking = flow.get("current_booking") || null; // {start, end, ...}

    let presence = flow.get("presence_detected") || false;

    // Входящее сообщение может быть от датчика или календаря

    // msg.topic используется для идентификации источника

    if (msg.topic === "sensor/presence") {

    presence = msg.payload.value; // payload: { value: true, ... }

    flow.set("presence_detected", presence);

    } else if (msg.topic === "calendar/event") {

    // Если пришло событие из календаря (on/off)

    if (msg.payload.on) {

    booking = msg.payload;

    // Запускаем таймер no-show

    node.send({ "topic": "start_noshow_timer" });

    } else {

    booking = null;

    }

    flow.set("current_booking", booking);

    }

    // =================================================================

    // ОСНОВНАЯ ЛОГИКА STATE-МАШИНЫ

    // =================================================================

    let newState = roomState;

    switch (roomState) {

    case "Free":

    if (booking && presence) {

    newState = "In Progress";

    } else if (booking) {

    newState = "Booked";

    }

    break;

    case "Booked":

    if (presence) {

    newState = "In Progress";

    // Отменяем таймер no-show

    node.send({ "topic": "cancel_noshow_timer" });

    } else if (!booking) {

    // Бронь закончилась, а никто не пришел

    newState = "Free";

    }

    break;

    case "In Progress":

    if (!presence && !booking) {

    // Все ушли и бронь закончилась

    newState = "Free";

    } else if (!presence && booking) {

    // Люди ушли раньше, но бронь еще есть.

    // Запускаем таймер (5 мин), если не вернутся - освобождаем.

    node.send({ "topic": "start_early_leave_timer" });

    }

    break;

    }

    // Если состояние изменилось, сохраняем его и отправляем команду

    if (newState !== roomState) {

    flow.set("room_state", newState);

    node.status({ fill: "blue", shape: "dot", text: "New state: " + newState });

    // Отправляем сообщение для управления светом, климатом и т.д.

    return { payload: { state: newState } };

    }

    // Ничего не изменилось, останавливаем поток

    return null;

    Этот код — упрощенный пример, но он демонстрирует основной принцип:

  • Получаем текущие статусы из контекста.
  • Обновляем статусы на основе пришедшего сообщения.
  • Применяем логику state-машины.
  • Если состояние изменилось, сохраняем новое и генерируем команду для следующего узла.
  • ---

    Управление светом, климатом и AV

    Когда наша state-машина определила новое состояние для комнаты (`"In Progress"`, `"Free"` и т.д.), ее задача — отдать команды исполнительным устройствам.

    > 🔗 Связанный материал: Подробно принципы управления освещением и климатом через MQTT и Modbus рассмотрены в уроках COURSE-01-M05-L05: Сценарии для офиса: Управление освещением и COURSE-01-M05-L02: Сценарии для дома: Климат-контроль по расписанию. Здесь мы применяем эти знания на практике.

    На выходе из нашего основного `Function` узла появляется сообщение вида `{"payload": {"state": "InProgress"}}`. Узел `Switch` направляет его в соответствующую ветку для активации сцены.

    Формирование MQTT-сообщений для управления Wirenboard

    Устройства Wirenboard управляются по стандартной MQTT-конвенции. Чтобы включить первое реле на модуле `WB-MR6C` с MQTT-именем `wb-mr6c_34`, нужно отправить сообщение `1` в топик `/devices/wb-mr6c_34/controls/K1/on`.

    Ветка `Switch` для состояния `"In Progress"` может вести к узлу `Change`, который формирует несколько сообщений для включения разных групп света.

    | Входящее состояние | Устройство | MQTT Topic | MQTT Payload |

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

    | `In Progress` | Основной свет (реле) | `/devices/wb-mr6c_34/controls/K1/on` | `1` |

    | `In Progress` | Подсветка (диммер) | `/devices/wb-mdm3_21/controls/Channel 1/on` | `80` (80%) |

    | `Free` | Основной свет (реле) | `/devices/wb-mr6c_34/controls/K1/on` | `0` |

    | `Free` | Подсветка (диммер) | `/devices/wb-mdm3_21/controls/Channel 1/on` | `0` |

    Интеграция с климатом по Modbus

    Если фанкойл или вент-установка управляется по Modbus RTU/TCP, логика следующая:

  • После узла `Switch`, который определил состояние, ставится узел `Function`.
  • Этот узел формирует `msg.payload`, как того требует узел `node-red-contrib-modbus`. Например, для установки уставки температуры 22°C в регистр `40101` (адрес 100) устройства с ID=5:
  • // Пример для состояния "In Progress"
    

    msg.payload = {

    'value': 220, // Уставка 22.0C, если устройство требует умножения на 10

    'fc': 6, // Function Code 6: Preset Single Register

    'unitid': 5,

    'address': 100,

    'quantity': 1

    };

    return msg;

  • Это сообщение подается на вход узла `Modbus-Write`.
  • Управление проектором и экраном

    AV-оборудование часто управляется через последовательный порт RS-232/RS-485 или ИК-команды.

    Через RS-232/485: Используем модуль WB-MIO-E v.2, который предоставляет виртуальный COM-порт в системе. В Node-RED используем узел `Serial Out`. В него нужно отправить specific-команду из документации проектора. Например, для включения проектора BenQ это может быть строка `\rpow=on#\r`.

    Создание "сцен"

    Сцена — это заранее определенный набор состояний для нескольких устройств. Это упрощает логику, так как state-машине нужно активировать всего одну сцену, а не управлять каждым устройством по отдельности.

    // Узел Function, который активирует сцену "Презентация"
    

    const sceneName = msg.payload.scene; // Ожидаем { "payload": { "scene": "Presentation" } }

    let messages = [];

    if (sceneName === "Presentation") {

    // 1. Приглушить основной свет

    messages.push({ topic: "/devices/wb-mdm3_21/controls/Channel 1/on", payload: 20 });

    // 2. Опустить экран (управляется двумя реле)

    messages.push({ topic: "/devices/wb-mr6c_34/controls/K3/on", payload: 1 }); // Команда "вниз"

    // 3. Включить проектор

    messages.push({ topic: "serial/projector/send", payload: "\r*pow=on#\r" });

    }

    //... другие сцены

    // Узел Function может возвращать массив сообщений, чтобы отправить их все сразу

    return [messages];

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

    ---

    Панель управления и обратная связь (iRidium)

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

    > 💡 Подсказка: Используйте двустороннюю связь (two-way binding). Когда состояние устройства меняется на физическом уровне (например, свет включили настенным выключателем), его статус должен немедленно обновиться на панели iRidium. Это достигается через подписку панели на status-топики MQTT.

    Проектирование интерфейса

    Хороший интерфейс для переговорной должен быть интуитивно понятным и предоставлять всю необходимую информацию с одного взгляда.

    Ключевые элементы на главном экране: * Сцена "Презентация"

    * Сцена "Обсуждение" (яркий свет)

    * Кнопки "Продлить встречу" и "Завершить досрочно"

    Реализация двусторонней связи по MQTT

    Чтобы интерфейс всегда был актуальным, iRidium и Node-RED должны обмениваться данными в обе стороны. Для этого используется простая конвенция MQTT-топиков.

    Пример для управления светом:
  • Команда от панели: На панели iRidium есть кнопка "Включить свет". При нажатии она публикует сообщение `1` в топик `/devices/myroom/controls/light/on`.
  • Обработка в Node-RED: Узел `mqtt in` подписан на этот топик. Получив `1`, он передает команду на физический топик реле Wirenboard: `/devices/wb-mr6c_34/controls/K1/on`.
  • Обратная связь (статус): Модуль реле Wirenboard, включив свет, автоматически публикует свой новый статус `1` в топик `/devices/wb-mr6c_34/controls/K1`.
  • Обновление на панели: Панель iRidium подписана на этот status-топик. Получив `1`, она меняет иконку кнопки на "включено".
  • Этот цикл гарантирует, что даже если свет включили с обычного настенного выключателя, который также подключен к контроллеру, статус на панели iRidium все равно обновится.

    Сценарии "Продлить встречу" / "Завершить досрочно"

    Эти функции значительно повышают удобство использования системы.

    1. Пользователь нажимает кнопку на панели.

    2. iRidium публикует команду в топик, например, `myroom/booking/command` с payload `"END_EARLY"`.

    3. Node-RED получает эту команду.

    4. Логика переводит state-машину в состояние `Free` и запускает сцену "Никого нет" (выключает свет и климат).

    5. (Опционально, более сложный вариант) Node-RED через API календаря изменяет время окончания текущего события, формально освобождая комнату в системе бронирования.

    1. За 5 минут до окончания встречи на панели появляется кнопка "Продлить на 30 мин".

    2. При нажатии iRidium шлет команду `myroom/booking/command` с payload `"EXTEND_30"`.

    3. Node-RED получает команду и через API календаря проверяет, свободна ли комната после текущего слота.

    4. Если свободна — Node-RED изменяет время окончания текущей встречи.

    5. Если занята — на панели iRidium отображается уведомление "Невозможно продлить, комната забронирована".

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

    ---

    Итоги и отладка

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

    Обзор полного цикла работы сценария

  • Бронирование: Сотрудник создает событие в Google/MS календаре переговорной.
  • Ожидание: За 15 минут до начала Node-RED получает данные по CalDAV, переводит комнату в состояние `"Booked"` и активирует сцену "Ожидание" (включает дежурный свет, готовит климат).
  • Начало встречи: Первый участник входит в комнату. Датчик присутствия срабатывает, Node-RED получает MQTT-сообщение, переводит комнату в состояние `"In Progress"` и активирует сцену "Обсуждение" (основной свет).
  • Ход встречи: Система поддерживает комфортный климат. Пользователи могут вручную запустить сцену "Презентация" с панели iRidium.
  • Завершение: Встреча заканчивается.
  • * Сценарий А (ушли вовремя): Время брони истекло, датчик не видит людей — Node-RED переводит комнату в состояние `"Free"` и выключает все оборудование.

    * Сценарий Б (ушли раньше): Люди покинули комнату, датчик не видит присутствия 5 минут. Node-RED досрочно переводит комнату в `"Free"`, освобождая ее для других.

    * Сценарий В (забыли отменить): Бронь есть, но в течение 15 минут никто не пришел ("no-show"). Node-RED автоматически переводит комнату в `"Free"`.

    Основные инструменты отладки

    * Датчики корректно отправляют данные.

    * Node-RED правильно формирует команды для исполнительных устройств.

    * Панель iRidium подписывается на нужные топики и отправляет команды.

    Частые проблемы и их решение

    | Проблема | Возможная причина | Решение |

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

    | Свет выключается во время встречи. | ИК-датчик движения "потерял" неподвижных людей. | 1. Увеличить время задержки перед выключением. 2. Использовать `mmWave`-радар присутствия. |

    | Комната не освобождается после ухода людей. | "Дребезг" датчика (ложные срабатывания). Некорректная логика state-машины. | Проверить логику таймера "досрочного ухода". Отфильтровать короткие импульсы с датчика. |

    | Бронирование в календаре есть, а система не реагирует. | Неправильная CalDAV-ссылка. Нет связи с интернетом. Рассинхронизация времени на контроллере. | Проверить ссылку в браузере. Проверить сетевые настройки контроллера (`ping google.com`). Настроить NTP-синхронизацию времени. |

    | Команды на климат/AV не проходят. | Ошибка в настройках Modbus (ID, адрес регистра). Ошибка в строке команды для RS-485. Обрыв шины. | Использовать узел `Catch` для отлова ошибок от Modbus/Serial узлов. Проверить документацию на оборудование. "Прозвонить" физическую линию. |

    Что дальше

    В этом уроке мы спроектировали и реализовали один из самых востребованных и комплексных сценариев автоматизации для коммерческих объектов. Вы научились объединять данные из облачных сервисов и локальных датчиков, строить сложную логику на базе state-машин и управлять разнообразным оборудованием через MQTT, Modbus и RS-485.

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