- Added detailed comments to clarify the purpose of various functions and types in the Discord bot and HA gateway. - Introduced new methods in the CommandApp for handling light and switch operations, including HandleLightOn, HandleLightOff, HandleLightToggle, and their respective autocomplete functions. - Updated the HAClient interface to include methods for fetching states and calling services, enhancing the interaction with Home Assistant. - Improved the structure of entity and light domain models to include additional attributes and clearer documentation. - Implemented logging enhancements in both the Discord bot and HA gateway to ensure better traceability and context in logs. - Refactored the configuration loading process to streamline environment variable handling and defaults. - Stubbed out switch control methods in the gRPC adapter, indicating future implementation plans. - Enhanced telemetry setup to ensure proper initialization and shutdown procedures for observability.
211 lines
6.5 KiB
Markdown
211 lines
6.5 KiB
Markdown
# 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
|