# device-control-service (Go) Статус: реализован (MVP). Зона ответственности: - Предоставляет gRPC API (см. `proto/device_control/device_control.proto`: `TurnOn`, `TurnOff`, `SetLevel` → `CommandResult`) для отправки команд устройствам — вызывается из Laravel (ручное управление) и из rule-engine-service (действия по срабатыванию правил). - Публикует команду в MQTT-топик устройства (`devices/{device_id}/commands`) и слушает подтверждения (`devices/{device_id}/ack`). - Поддерживает паттерн Device Shadow в Redis: `desired_state` (чего хочет пользователь) против `reported_state` (что подтвердило устройство), плюс `status` и `last_seen`. - Ведёт health-check горутиной-тикером: переводит устройство в `offline`, когда `last_seen` превышает таймаут, и публикует событие в RabbitMQ (`device.status_changed`) для будущего notification-service — как при уходе в офлайн, так и при возврате online. Не входит в зону ответственности: решение о том, *когда* отправлять команду на основе показаний датчиков — это логика rule-engine-service. Этот сервис только исполняет команды и отслеживает состояние для той команды, что ему дали. ## Архитектурные решения - **gRPC — не ждёт подтверждения устройства.** `CommandResult.success` означает «desired_state обновлён и команда опубликована в MQTT», а не «устройство подтвердило выполнение». Это соответствует Device Shadow: мгновенный отклик в UI, даже если устройство офлайн или ответит с задержкой. `reported_state` обновляется позже, асинхронно, по приходу ack. - **last_seen обновляется и по телеметрии, и по ack.** Сервис подписан на `devices/+/telemetry` только ради отметки «устройство живо» (сами данные телеметрии парсит и хранит ingest-service) — иначе датчики без исходящих команд (и, соответственно, без ack) никогда не считались бы online. - **Нет зависимости от PostgreSQL.** Список известных устройств — это Redis Set (`devices:known`), который пополняется по мере поступления телеметрии/ack, а не выгружается из таблицы `devices`. Это удерживает сервис в границах MQTT+Redis+RabbitMQ+gRPC, как и в диаграмме архитектуры корневого README. ## Запуск ```bash cd services/device-control-service go test ./... go build ./cmd/device-control-service ``` Конфигурация — через переменные окружения (секция device-control-service в корневом `.env.example`). `proto/` — отдельный Go-модуль, подключается через `replace` в `go.mod` на относительный путь `../../proto`.