Агент + MCP в osysHome: как я превратил умный дом в управляемую инженерную систему. llm.. llm. mcp-server.. llm. mcp-server. osyshome.. llm. mcp-server. osyshome. Умный дом.. llm. mcp-server. osyshome. Умный дом. умныйдом.

Когда я впервые подключил агента к умному дому через MCP, ожидал простой эффект: “ну, будет еще один способ дергать API”. На практике вышло иначе. MCP в osysHome оказался не транспортом, а рабочим интерфейсом для эксплуатации: с понятными сущностями, историей изменений, проверками перед записью и безопасным контуром для автоматизации.

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

Почему вообще MCP в доме полезен

Обычный путь автоматизации часто выглядит так:

  • пишем скрипт на коленке;

  • через месяц забываем, где и почему что-то менялось.

С MCP все иначе. Агент работает не с “сырыми URL”, а с понятными инструментами предметной области:

  • osys_list_classes и osys_list_objects для инвентаризации;

  • osys_get_property и osys_get_property_history для наблюдения;

  • osys_call_method и osys_set_property для действий;

  • osys_validate_method_code и osys_run_method_dry для безопасной разработки;

  • osys_update_object / osys_update_class с if_match для управляемых изменений.

По ощущениям это как дежурный инженер для дома: сначала проверяет, потом действует.

Модуль "MCPServer"

Модуль “MCPServer”

Быстрый старт: что нужно, чтобы агент заговорил с osysHome

В MCPServer для osysHome все строится вокруг endpoint /api/mcp и JSON-RPC поверх HTTP.
Из практики я бы выделил три вещи:

  1. Токен-авторизация (Authorization: Bearer ... или X-MCP-Token).

  2. Разделение прав (чтение отдельно, запись отдельно, управление отдельно).

  3. Аудит неудачных попыток и контроль write-инструментов.

Это критично: дому нужен не “самый умный агент”, а предсказуемый агент с ограниченными правами.

Как выглядит рабочий цикл агента

Я придерживаюсь простого рабочего цикла:

  1. Обнаружить контекст — какие классы, объекты и связи есть сейчас.

  2. Проверить гипотезу — история свойств, текущие значения, логи.

  3. Подготовить действие — dry-run, валидация кода или шаблона.

  4. Выполнить изменение — только после проверки.

  5. Верифицировать — убедиться, что эффект наступил и не зацепил соседние сценарии.

Звучит банально, но именно это отделяет “игрушку” от рабочего инструмента.

Кейс 0. Самый простой: включить свет в гостиной

Запрос агенту человеческим языком:

“Включи свет в гостиной”.

Что делает агент:

  1. Находит целевой объект освещения (например, Relay01 — “Свет(гостиная)”).

  2. Вызывает безопасное действие через MCP (osys_set_property или osys_call_method).

  3. Проверяет, что новое состояние применилось.

Технически запрос выглядит так:

{
  "tool": "osys_set_property",
  "arguments": {
    "property_name": "Relay01.status",
    "value": 1,
    "source": "MCPAgent"
  }
}

Ответ агента:

“Свет в гостиной включен.
Объект: Relay01 (Свет(гостиная)).
Новое состояние: status = 1.”

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

Кейс 1. Аналитика энергопотребления: где реально жрет, а где просто кажется

Запрос агенту человеческим языком:

“Покажи сводку по энергопотреблению всего дома: сколько сейчас, где пики и насколько нагрузка стабильна по группе силовых устройств”.

Агент делает не один запрос, а целую цепочку:

  • находит все power-объекты (Power01..Power13, PowerPlug*, TotalPower) — всего 17;

  • берет агрегаты и текущие значения по TotalPower.power;

  • строит топ потребителей по текущим значениям *.power.

Короткий ответ агента, уже обычным языком:

“Нашел 17 объектов энергомониторинга.
Сейчас суммарная мощность дома: 168.71 Вт (TotalPower.power, объект TotalPower — Общее энергопотребление).
За последний месяц средняя нагрузка: 442.93 Вт, пиковое значение: 4838.83 Вт.
Текущий топ потребителей:

  1. `Power05` — “Мощность(детские)” — 17.0 Вт

  2. `Power06` — “Мощность(компьютер)” — 4.0 Вт

  3. `Power09` — “Мощность(свет в гостиной)” — 1.48 Вт Остальные power-каналы сейчас близки к 0. По среднемесячной базе топ по вкладу в фон: `Power05` (23.63 Вт), `Power06` (8.58 Вт), `Power09` (6.86 Вт), `Power11` — “Мощность(бойлер)” (4.43 Вт).”

Что агент предлагает для снижения потребления по этой аналитике:

  1. Проверить, почему Power05 держит высокий среднемесячный фон; добавить расписание/автоотключение в ночные часы.

  2. Для Power06 (компьютер) включить сценарий “глубокий сон ночью” и отключение периферии по отсутствию активности.

  3. Для Power11 (бойлер) вынести нагрев в дешевые тарифные окна и ограничить верхний порог температуры.

  4. Добавить еженедельный отчет “топ-5 потребителей за 30 дней”, чтобы видеть эффект изменений.

Практический смысл: это уже не “посмотреть на одно реле”, а цельная картина энергопотребления дома плюс конкретный план оптимизации.

Кейс 2. Аналитика errors.log: не просто “есть ошибка”, а что чинить прямо сейчас

Запрос агенту человеческим языком:

“Проверь, нет ли системных проблем за последний час. Смотри не только errors.log, а несколько логов модулей, чтобы понять масштаб.”

Агент смотрит сразу несколько источников:

  • errors.log — системные stacktrace и сетевые ошибки;

  • OpenHasp.log — ошибки интеграции устройства/шины;

  • ESPHome.log — телеметрия и стабильность данных;

  • Modules.log — фоновая активность ядра/плагинов.

Короткий ответ агента:

“Проблемы действительно системные, не в одном файле.
В errors.log вижу TLS-ошибку при обращении к api.telegram.org (SSLError: UNEXPECTED_EOF_WHILE_READING).
В OpenHasp.log повторяется ошибка разбора события (Error processing message: 'event').
При этом ESPHome.log и Modules.log выглядят стабильными (регулярные INFO-записи без ошибок).
Значит, инцидент локализуется в двух интеграционных зонах: сеть/Telegram и обработка OpenHasp-сообщений.”

Что агент предлагает как фиксы:

  1. Для Telegram/TLS — проверить цепочку proxy/SSL, таймауты и актуальность cert store на хосте.

  2. Для OpenHasp — валидировать входящий payload на ключ event и логировать raw-пакет при его отсутствии.

  3. Добавить guard в обработчики: неполные сообщения не должны валить поток обработки.

Это не “магия ИИ”, а обычная инженерная рутина, просто заметно быстрее.

Кейс 3. Устройства, которые давно не отвечают, и устройства с риском обслуживания

Инвентаризация без эксплуатационных флагов мало полезна. Нужна именно “карта риска”.

Запрос агенту человеческим языком:

“Составь список: какие устройства давно не выходят на связь и каким скоро нужно обслуживание (батарейки/связь)”.

Агент проходит по группе устройств и собирает единый список проблем:

  • устройства без связи по alive;

  • устройства с риском обслуживания по *.battery и minBattery;

  • при необходимости добавляет контекст по alive/aliveTimeout.

Короткий ответ агента:

“Сформировал список проблемных устройств.
По alive = 0 сейчас:

  • Door03 — Дверь (лоджия)

  • Door07 — Дверь(Саша)

  • Door08 — Дверь(Ваня)

  • Door10 — Дверь(шкаф 1)
    Низкий заряд батареи:

  • Motion01 — Движение(коридор) — 17%

  • Motion02 — Движение(гостиная) — 17%
    Зона внимания: Motion06 — Движение(Саша) — 43%.
    Рекомендация: сначала восстановить связь/питание по объектам с alive = 0, затем заменить батарейки в Motion01/02.”

Так получается не точечная проверка одного объекта, а нормальная сервисная ведомость.

Кейс 4. Выявление аномалий по истории: где поведение ушло от нормы

Вместо сложной ML-модели часто хватает базовой статистики + здравого смысла.

Запрос агенту человеческим языком:

“Найди аномалии по климату: где значения выбиваются из обычного диапазона, и что проверить первым делом”.

Агент проверяет не один датчик, а весь пул Climat01..Climat09: берет текущее значение temp и сравнивает с историческим avg для каждого.

Короткий ответ агента:

“Проверил 9 климатических датчиков на отклонение от исторической базы.
Топ аномалий:

  1. `Climat07` — “Климат(лоджия)”: 19.5°C при среднем 13.55°C (сильное положительное отклонение).

  2. `Climat03` — “Климат(туалет)”: 23.8°C при среднем 23.03°C (умеренное отклонение).

  3. `Climat05` — “Климат(Ваня)”: 24.3°C при среднем 23.56°C (умеренное отклонение). Для `Climat08` — “Климат (кухня)” — среднее не рассчиталось (`avg = null`), нужно проверить полноту истории. Рекомендация: проверить сценарии отопления/проветривания на лоджии и восстановить корректное накопление истории для кухонного датчика.”

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

Кейс 5. Новый режим “Кинотеатр”: включение и выключение под ключ

Это уже не аналитика, а реальное внедрение логики через MCP, где агент не просто “советует”, а сам собирает рабочую сущность.

Запрос агенту человеческим языком:
“Сделай режим Кинотеатр: отдельный объект, метод включения и метод выключения. Перед запуском проверь код безопасно.”

1) Агент создает объект режима

{
  "tool": "osys_add_object",
  "arguments": {
    "object_name": "CinemaMode",
    "class_name": "Modes",
    "description": "Режим кинотеатр",
    "update": true
  }
}

2) Добавляем методы activate и deactivate

{
  "tool": "osys_add_object_method",
  "arguments": {
    "object_name": "CinemaMode",
    "name": "activate",
    "description": "Включить сценарий кинотеатра",
    "code": "target = getProperty('targetBrightness')nif target is None:n    target = 20nprev = getProperty('Dimmer01.status')nsetProperty('previousBrightness', prev, source='CinemaMode')nsetProperty('active', 1, source='CinemaMode')nsetProperty('sceneName', 'Cinema', source='CinemaMode')nsetProperty('lastActivated', datetime.now(), source='CinemaMode')nsetProperty('Relay15.status', 0, source='CinemaMode')nsetProperty('Dimmer01.status', target, source='CinemaMode')nsetProperty('Rgb05.status', 1, source='CinemaMode')nsetProperty('Rgb05.brightness', target, source='CinemaMode')",
    "update": true
  }
}
{
  "tool": "osys_add_object_method",
  "arguments": {
    "object_name": "CinemaMode",
    "name": "deactivate",
    "description": "Выключить сценарий кинотеатра",
    "code": "prev = getProperty('previousBrightness')nif prev is None:n    prev = 0nsetProperty('active', 0, source='CinemaMode')nsetProperty('Dimmer01.status', prev, source='CinemaMode')nsetProperty('Rgb05.status', 0, source='CinemaMode')nsetProperty('Relay15.status', 1, source='CinemaMode')",
    "update": true
  }
}

3) Агент добавляет свойства объекта, чтобы режимом было удобно управлять

Чтобы режимом можно было пользоваться и в сценариях, и в интерфейсе, агент добавляет базовые свойства:

  • active (int) — текущий статус режима (0/1);

  • targetBrightness (int) — яркость, которую пользователь задает для режима;

  • previousBrightness (int) — яркость, которая была до включения режима;

  • sceneName (str) — человекочитаемое имя сцены;

  • lastActivated (datetime) — когда режим запускался последний раз.

Технически это выглядит так (пример для одного свойства):

{
  "tool": "osys_add_object_property",
  "arguments": {
    "object_name": "CinemaMode",
    "name": "active",
    "type": "int",
    "description": "Статус режима кинотеатр",
    "update": true
  }
}

По аналогии агент добавляет остальные свойства (targetBrightness, previousBrightness, sceneName, lastActivated).

4) Итог: что именно создал агент (с кодом методов)

После выполнения шагов выше в системе появляется новый объект:

  • Объект: CinemaMode — “Режим кинотеатр”

  • Класс: Modes

  • Свойства: active, targetBrightness, previousBrightness, lastActivated

  • Методы: activate, deactivate

Код метода activate:

target = self.getProperty('targetBrightness')
if target is None:
    target = 20
prev = getProperty('Dimmer01.status')
self.setProperty('previousBrightness', prev, source='CinemaMode')
self.setProperty('active', 1, source='CinemaMode')
self.setProperty('lastActivated', datetime.now(), source='CinemaMode')
setProperty('Relay15.status', 0, source='CinemaMode')
setProperty('Dimmer01.status', target, source='CinemaMode')
setProperty('Rgb05.status', 1, source='CinemaMode')
setProperty('Rgb05.brightness', target, source='CinemaMode')

Код метода deactivate:

prev = self.getProperty('previousBrightness')
if prev is None:
    prev = 0
self.setProperty('active', 0, source='CinemaMode')
setProperty('Dimmer01.status', prev, source='CinemaMode')
setProperty('Rgb05.status', 0, source='CinemaMode')
setProperty('Relay15.status', 1, source='CinemaMode')

5) Проверяем перед публикацией

  • osys_validate_method_code — синтаксис и ограничения runtime.

  • osys_run_method_dry — dry-run без побочных эффектов.

Именно так можно проверить, что созданные свойства реально используются, а не просто “задекларированы”:

{
  "tool": "osys_run_method_dry",
  "arguments": {
    "object_name": "CinemaMode",
    "code": "target = getProperty('targetBrightness')nif target is None:n    target = 20nprev = getProperty('Dimmer01.status')nsetProperty('previousBrightness', prev, source='CinemaMode')nsetProperty('active', 1, source='CinemaMode')nsetProperty('sceneName', 'Cinema', source='CinemaMode')nsetProperty('lastActivated', datetime.now(), source='CinemaMode')nsetProperty('Dimmer01.status', target, source='CinemaMode')"
  }
}

Ожидаемый результат проверки: в captured_actions будут ключевые действия по свойствам:

  • active

  • targetBrightness

  • previousBrightness

  • lastActivated

Практический смысл этой схемы:

  1. Пользователь заранее задает targetBrightness (например, 12 или 20).

  2. На activate агент применяет именно это значение.

  3. Перед применением агент сохраняет текущую яркость в previousBrightness.

  4. На deactivate яркость возвращается к previousBrightness, то есть в состояние “как было до кинотеатра”.

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

Что важно по безопасности, если пускаете агента в дом

Ниже набор правил, который у меня реально работает:

  • перед любой работой агента с write-операциями делайте бэкап (минимум БД и критичных конфигов) и проверяйте, что восстановление реально работает;

  • выдавайте агенту read-only токен по умолчанию;

  • write-права открывайте только под конкретные задачи;

  • отдельно ограничивайте dangerous-инструменты (массовые апдейты, удаление сущностей);

  • все изменения через этап “validate/dry-run”;

  • ведите журнал “кто/что/когда” менял.

Главная мысль: не “слепо доверять агенту”, а строить контур, где ошибка локальна и обратима.

Ограничения и анти-паттерны

Что делать не стоит:

  • давать полные write-права 24/7 “потому что так удобнее”;

  • смешивать диагностику и изменение состояния в одном автоматическом шаге;

  • обновлять классы/объекты без ревизий и проверки актуальности;

  • считать dry-run “лишней формальностью”.

С агентами правило простое: чем аккуратнее дисциплина в начале, тем меньше ночных приключений потом.

Итого

MCP в osysHome для меня — это не про “поговорить с домом на естественном языке”.
Это скорее ощущение, что рядом появился спокойный и внимательный технапарник: ты формулируешь задачу обычными словами, а в ответ получаешь не магию, а понятный, проверяемый результат.

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

И вот здесь для меня случился главный сюрприз.
В начале я ожидал “удобный интерфейс к API”. На выходе получил заметно больше: агент реально берет на себя кусок рутинной инженерной работы — от диагностики до безопасного внедрения изменений.

Если честно, это и есть тот самый вау-эффект: результат оказался намного сильнее стартовых ожиданий.

Автор: Anisan

Источник