home-services/README.md
Nik Afiq abb6774b77 feat: implement SwitchService with ListSwitches method
- Added ListSwitches method to SwitchService in switch_grpc.pb.go.
- Implemented SwitchGRPC adapter for ListSwitches in switch.go.
- Created SwitchApp for managing switch states and added ListSwitches logic.
- Updated core domain with Switch struct and associated methods.
- Enhanced LightApp to include ListLights functionality.
- Updated protobuf definitions for Switch and Light services to include new request and response messages.
- Introduced error handling for unimplemented methods in the gRPC server.
2026-04-06 19:25:06 +09:00

186 lines
5.0 KiB
Markdown

# 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.