# home-services `home-services` is a Go mono-repo for internal home-control services built around a gRPC gateway for Home Assistant. Discord and Alexa clients are meant to talk to the gateway instead of integrating with Home Assistant directly. ## Architecture The repo uses hexagonal architecture: - the core domain is plain Go data and interfaces - adapters at the edges handle gRPC, HTTP, Discord, telemetry, and logging - dependencies point inward only That means the business logic does not need to know about Discord, protobuf transport details, or Home Assistant HTTP specifics. ### Service relationship ```text Discord bot ->\ \ -> ha-gateway -> Home Assistant / Alexa bridge ->/ ``` - `discord-bot` is an internal gRPC client of `ha-gateway` - `alexa-bridge` is planned as another internal gRPC client of `ha-gateway` - `ha-gateway` is the only service that talks to Home Assistant directly ### Proto-first design All service contracts are defined in `proto/ha/v1/`. Generated Go code is committed under `gen/` and used by both clients and servers. This gives every service the same: - RPC method names - request and response message types - protobuf serialization rules - gRPC client/server bindings ## Services ### ha-gateway `ha-gateway` is the single internal gRPC gateway to Home Assistant. It should not be exposed publicly. - Port: `50051` - Deployment model: internal-only, typically ClusterIP - Implemented: - `EntityService`: `GetState`, `ListStates` - `LightService`: `TurnOn`, `TurnOff`, `Toggle`, `ListLights` - `SwitchService`: `ListSwitches` - Stubbed: - `SwitchService`: `TurnOn`, `TurnOff`, `Toggle` - `EventService` - Observability: - structured logging via `slog` - `LOG_FORMAT=json` is suitable for production log pipelines - `LOG_FORMAT=text` is more readable locally - OpenTelemetry traces and metrics export over OTLP gRPC Config: | Variable | Default | Description | | --- | --- | --- | | `GRPC_PORT` | `50051` | gRPC listen port | | `HA_BASE_URL` | empty | Base URL for Home Assistant | | `HA_TOKEN` | none | Home Assistant long-lived access token | | `OTEL_ENDPOINT` | empty | OTLP gRPC collector endpoint; empty disables telemetry | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` | | `LOG_FORMAT` | `json` | `json` or `text` | Auth: Inbound auth is not implemented yet. The current recommendation is mTLS between internal services. A per-client API key interceptor is a possible alternative for simpler environments. ### discord-bot `discord-bot` provides Discord slash commands for home control and discovery. - Connects to `ha-gateway` over internal gRPC - Supports slash-command control for lights - Supports list/discovery responses for lights and switches - Observability: - structured logging via `slog` - OpenTelemetry traces and metrics via OTLP gRPC Config: | Variable | Default | Description | | --- | --- | --- | | `DISCORD_TOKEN` | none | Discord bot token | | `GUILD_ID` | empty | Guild-scoped command registration target | | `HA_GATEWAY_ADDR` | none | gRPC address of `ha-gateway` | | `OTEL_ENDPOINT` | empty | OTLP gRPC collector endpoint; empty disables telemetry | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` | | `LOG_FORMAT` | `json` | `json` or `text` | Auth: No additional app-layer auth is implemented yet. The bot currently relies on Discord authentication and the internal network boundary. ### alexa-bridge `alexa-bridge` is a planned public HTTPS webhook service that will: - validate Alexa request signatures - translate Alexa directives into gRPC calls to `ha-gateway` - keep `ha-gateway` off the public internet Status: - stubbed concept only - not implemented in this repo yet ## Repo Structure ```text home-services/ ├── proto/ # Source of truth for protobuf service contracts │ └── ha/v1/ ├── gen/ # Committed generated Go protobuf/gRPC code; do not edit ├── ha-gateway/ │ ├── cmd/gateway/ # Process entrypoint and startup wiring │ └── internal/ │ ├── core/ # Pure domain and port definitions, no framework logic │ ├── app/ # Orchestration between ports │ ├── adapters/ # gRPC handlers, HA client, and other I/O │ ├── logger/ # Context-aware slog helpers │ └── telemetry/ # OpenTelemetry setup and shutdown ├── discord-bot/ │ ├── cmd/bot/ # Process entrypoint and Discord session wiring │ └── internal/ │ ├── app/ # Command orchestration and formatting │ ├── adapters/ # Discord interaction handlers and gRPC client │ ├── core/ports/driven/ # App-facing ha-gateway contract │ ├── logger/ # Context-aware slog helpers │ └── telemetry/ # OpenTelemetry setup and shutdown ├── buf.yaml # Buf module config ├── buf.gen.yaml # Buf generation config └── go.work # Go workspace for local module development ``` ## Local Development Prerequisites: - Go `1.26+` - `buf` - `grpcurl` - a running Home Assistant instance Setup: ```bash # Clone and set up workspace git clone https://gitea.nik4nao.com/nik/home-services cd home-services go work sync # Regenerate proto (only needed if .proto files change) buf generate # Configure ha-gateway cp ha-gateway/.env.example ha-gateway/.env # Edit ha-gateway/.env — set HA_BASE_URL and HA_TOKEN # Run ha-gateway cd ha-gateway && go run ./cmd/gateway # Run discord-bot (separate terminal) cd discord-bot && go run ./cmd/bot ``` Smoke testing with `grpcurl`: ```bash # List all lights grpcurl -plaintext -d '{"domain":"light"}' \ localhost:50051 ha.v1.EntityService/ListStates # Turn on a light grpcurl -plaintext -d '{"entity_id":"light.living_room","brightness_pct":80}' \ localhost:50051 ha.v1.LightService/TurnOn ``` ## Building ```bash # Build ha-gateway image (run from repo root) docker build -f ha-gateway/Dockerfile -t ha-gateway:dev . # Build discord-bot image docker build -f discord-bot/Dockerfile -t discord-bot:dev . ``` ## What's Next - Auth: mTLS between services using an internal cert-manager CA - SwitchService control implementation - EventService with Home Assistant WebSocket fan-out broker - `alexa-bridge` implementation - Gitea CI pipeline for automated build and push