# home-service This workspace contains a Home Assistant gRPC gateway and the protobuf contract it serves. The current implementation is centered on `ha-gateway`, a Go service that: - exposes Home Assistant operations over gRPC - translates gRPC requests into Home Assistant REST API calls - emits OpenTelemetry traces and metrics when configured - keeps protobuf definitions and generated Go stubs in-repo `EntityService` and `LightService` are implemented. `SwitchService` and `EventService` are scaffolded but currently return `Unimplemented`. ## Workspace Layout ```text . ├── proto/ # Source protobuf definitions ├── gen/ # Generated Go protobuf/grpc code (committed) ├── ha-gateway/ # Go gRPC server ├── buf.yaml # Buf module config ├── buf.gen.yaml # Buf codegen config └── go.work # Go workspace linking gen + ha-gateway ``` ## Architecture `ha-gateway` follows a ports-and-adapters structure: - `internal/core/domain`: pure domain types - `internal/core/ports/driving`: interfaces exposed to primary adapters - `internal/core/ports/driven`: interfaces the app layer depends on - `internal/app`: application logic for entity and light operations - `internal/adapters/primary/grpc`: gRPC handlers and proto/domain mapping - `internal/adapters/secondary/ha`: Home Assistant REST client - `internal/telemetry`: OpenTelemetry setup The runtime flow is: 1. A gRPC client calls `EntityService` or `LightService`. 2. The gRPC adapter maps protobuf messages into domain parameters. 3. The app layer orchestrates the use case. 4. The HA adapter calls Home Assistant's REST API. 5. The response is mapped back into the protobuf response. ## Services ### Implemented - `ha.v1.EntityService` - `GetState` - `ListStates` - `ha.v1.LightService` - `TurnOn` - `TurnOff` - `Toggle` ### Stubbed - `ha.v1.SwitchService` - `ha.v1.EventService` The event path is planned around Home Assistant WebSocket subscriptions, but the WebSocket adapter and fan-out broker are not implemented yet. ## Configuration `ha-gateway` reads configuration from environment variables. A sample file lives at [ha-gateway/.env.example](/Users/nik-macbookair/repo/home-service/ha-gateway/.env.example). | Variable | Required | Default | Notes | | --- | --- | --- | --- | | `HA_TOKEN` | yes | none | Home Assistant long-lived access token | | `GRPC_PORT` | no | `50051` | gRPC listen port | | `HA_BASE_URL` | effectively yes | empty | Example: `http://ha.home.arpa:8123` | | `OTEL_ENDPOINT` | no | empty | OTLP gRPC endpoint; empty disables telemetry | Notes: - startup fails if `HA_TOKEN` is missing - `HA_BASE_URL` is not validated on load, but the gateway cannot reach Home Assistant without it - if `OTEL_ENDPOINT` is empty, the service installs no-op telemetry providers ## Prerequisites - Go `1.26` - `buf` for protobuf generation - a reachable Home Assistant instance - a valid Home Assistant long-lived access token ## Generate Protobuf Code Run from the repo root: ```bash buf generate ``` Generated files are written to `gen/ha/v1`. ## Build Sync the workspace, then build the gateway: ```bash go work sync cd ha-gateway go build ./... ``` ## Run Locally Create a local env file: ```bash cp ha-gateway/.env.example ha-gateway/.env ``` Fill in `HA_TOKEN` and `HA_BASE_URL`, then start the server: ```bash cd ha-gateway go run ./cmd/gateway ``` The gateway listens on `:50051` by default. ## Smoke Test With grpcurl Examples against a locally running gateway: ```bash # List all light entities grpcurl -plaintext -d '{"domain":"light"}' \ localhost:50051 ha.v1.EntityService/ListStates # Get one entity grpcurl -plaintext -d '{"entity_id":"light.living_room"}' \ localhost:50051 ha.v1.EntityService/GetState # Turn on a light at 80% brightness grpcurl -plaintext -d '{"entity_id":"light.living_room","brightness_pct":80}' \ localhost:50051 ha.v1.LightService/TurnOn # Toggle a light grpcurl -plaintext -d '{"entity_id":"light.living_room"}' \ localhost:50051 ha.v1.LightService/Toggle ``` ## Docker Build from the repo root: ```bash docker build -f ha-gateway/Dockerfile -t ha-gateway:dev . ``` Run it with the same env file: ```bash docker run --env-file ha-gateway/.env -p 50051:50051 ha-gateway:dev ``` ## Telemetry When `OTEL_ENDPOINT` is set, the gateway exports: - traces via OTLP/gRPC - metrics via OTLP/gRPC The service name is `ha-gateway`. When `OTEL_ENDPOINT` is unset, telemetry is disabled for local development. ## Current Limitations - no authentication/authorization on inbound gRPC requests yet - `SwitchService` is not implemented - `EventService` is not implemented - Home Assistant event streaming over WebSocket is not implemented - there are currently no unit tests in the repo The auth note in [ha-gateway/cmd/gateway/main.go](/Users/nik-macbookair/repo/home-service/ha-gateway/cmd/gateway/main.go) explicitly calls out API-key and mTLS as future options before exposing the gateway outside a trusted network.