cacto 3ade5c2512 Дашборд с реальными данными + ручное управление устройствами
device-control-service: HTTP/JSON API (internal/httpapi) рядом с gRPC —
POST /devices/{id}/turn-on|turn-off|set-level, тот же server.Server внутри,
без дублирования логики. Решение вместо gRPC-клиента на PHP: grpc/grpc
через PECL компилируется в Alpine 10-20+ минут и утяжеляет образ, а
диаграмма архитектуры в ТЗ и так допускала HTTP для Laravel→device-control.

Laravel: DeviceShadow (чтение Device Shadow из Redis, MGET одним запросом
для списка устройств), ClickHouseClient (HTTP-интерфейс ClickHouse,
параметризованные {name:Type}-запросы), DeviceControlClient (HTTP-вызовы
к новому Go-эндпоинту). Redis-клиент — predis (чистый PHP), а не phpredis,
по той же причине, что и решение по gRPC — не добавлять ещё одну
C-компиляцию в образ.

DeviceController::show — страница устройства: live-статус/last_seen/
desired-reported state из Redis, история показаний из ClickHouse (для
сенсоров), кнопки ручного управления (для актуаторов, только owner,
с проверкой capability устройства). В devices/index — бейдж online/
offline/unknown. Дашборд дополнен счётчиком онлайн-устройств.

Два реальных бага найдены и исправлены при сквозной проверке:
1. Пустой action_params сериализовался в JSON-массив "[]" (PHP не
   различает пустой список и пустой объект), а Go ждёт объект —
   rule-engine-service падал на unmarshal. Фикс — JsonObjectCast
   (JSON_FORCE_OBJECT) на AutomationRule::action_params.
2. Redis-ключи device shadow — общее пространство имён с Go-сервisами
   (сырые ключи без префикса), а Laravel по умолчанию добавляет ко всем
   ключам префикс "app-name-database-" — Laravel никогда не видел
   реальные данные. Фикс — REDIS_PREFIX="" в окружении контейнера
   (важно: пустое значение в docker-compose YAML нужно задавать явно
   через "", просто "KEY:" означает "взять из окружения хоста").

Проверено сквозным тестом через docker compose: полный цикл телеметрия →
правило → команда воспроизведён вживую с реальным исправлением на лету;
ручное управление (turn_on/turn_off/set_level) из Laravel UI подтверждено
через браузер — HTTP-вызов к device-control-service, обновление
desired_state (merge-patch), реальная MQTT-команда поймана мониторингом
топика. 38/38 тестов Laravel, все Go-тесты device-control-service зелёные.
2026-08-11 19:48:17 +05:00

Платформа домашней автоматизации

Pet-проект на микросервисной архитектуре для портфолио, демонстрирующий Go (конкурентность, очереди сообщений, MQTT), PHP/Laravel (API, авторизация) и работу с разными БД по назначению (PostgreSQL, ClickHouse, Redis).

Это не «проект гроубокса». Гроубокс — первая реализованная зона с первым набором типов устройств (свет, полив, вентиляция, датчик температуры). Ядро системы — управление устройствами, телеметрия, правила автоматизации, пользователи, уведомления — оперирует исключительно абстракциями зона, устройство, тип устройства, показание датчика, команда, правило. Ничего специфичного для гроубокса не зашито в ядре: добавление зоны «гостиная» с типом устройства «умная розетка» не должно требовать изменений в коде сервисов — только новые строки в device_types / zones / devices.

Архитектура

ESP32 (или эмулятор)
   │ MQTT
   ▼
ingest-service (Go) ──► ClickHouse (сырая телеметрия)
   │
   ▼ RabbitMQ (событие "новое показание")
rule-engine-service (Go) ──► PostgreSQL (правила, кэшируются)
   │ gRPC (при срабатывании правила)
   ▼
device-control-service (Go) ──► MQTT (команда) ──► устройство
   │
   ▼
Redis (device shadow: desired/reported state, status, last_seen)

Laravel API (PHP) ──► PostgreSQL / ClickHouse / Redis
   │ gRPC / HTTP
   ▼
device-control-service (ручные команды из UI)

Стек

Назначение Технология
Прошивка устройства / эмулятор Go (services/esp32-emulator)
Протокол устройство ↔ сервер MQTT (Mosquitto)
Backend телеметрии / команд / правил Go
Бизнес-логика / API / дашборд PHP (Laravel)
Пользователи, зоны, устройства, правила PostgreSQL
Телеметрия (time-series) ClickHouse
Состояние устройств в реальном времени Redis (паттерн Device Shadow)
Асинхронные события между сервисами RabbitMQ
Синхронные вызовы между сервисами gRPC / Protobuf
Метрики (этап 2.5) Prometheus + Grafana
Контейнеризация Docker Compose
Веб-фронтенд (этап 3) Vue.js + Inertia.js
Мобильное приложение (этап 3) Flutter
Уведомления Telegram-бот (MVP) / Firebase Cloud Messaging (позже)

Структура репозитория

services/
  ingest-service/           Go — MQTT → ClickHouse + RabbitMQ
  device-control-service/   Go — gRPC + MQTT + Redis device shadow
  rule-engine-service/      Go — консьюмер RabbitMQ + оценка правил
  health-check-service/     Go — тикер обнаружения офлайн-устройств
  esp32-emulator/           Go — фейковое устройство для локальной разработки
laravel-app/                PHP/Laravel — API, авторизация, дашборд (этап 2)
                            владеет схемой Postgres (database/migrations/*.php:
                            users, zones, devices, device_types, automation_rules)
proto/                      Общие gRPC-контракты (device_control.proto)
migrations/
  clickhouse/               таблица telemetry
configs/mosquitto/          Конфиг MQTT-брокера
monitoring/                 Конфиги Prometheus + Grafana (этап 2.5)

Каждый services/*/README.md описывает зону ответственности сервиса и явно то, что в неё не входит, — ещё до того, как там появится код.

Этапы разработки

  1. Go-сервисы — ingest, rule-engine, device-control, эмулятор ESP32.
  2. Laravel — авторизация (Sanctum, owner/viewer), CRUD для зон/устройств/ правил, Blade-дашборд, ручное управление устройствами. MVP считается готовым на этом этапе.
  3. (опционально, но сильно повышает ценность) Observability — метрики Prometheus с Go-сервисов, один-два дашборда в Grafana.
  4. Расширения (не спеша) — Telegram-уведомления, фронтенд на Vue.js/Inertia, приложение на Flutter, подключение реального ESP32.

Запуск локально

Пока только инфраструктура (сервисы добавляются в docker-compose.yml по мере реализации):

cp .env.example .env
docker compose up -d

Поднимутся Mosquitto (1883), PostgreSQL (5432), ClickHouse (8123/9000), Redis (6379) и RabbitMQ (5672, веб-интерфейс управления на 15672).

S
Description
No description provided
Readme
583 KiB
Languages
PHP 38.8%
Go 24.9%
Blade 20.3%
Vue 14.5%
JavaScript 0.8%
Other 0.7%