home-services/README.md
Nik Afiq 6ea4e84949
All checks were successful
CI / test (push) Successful in 4s
CI / build-ha-gateway (push) Successful in 1m7s
CI / build-discord-bot (push) Successful in 51s
Enhance Discord bot and HA gateway with improved structure and documentation
- 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.
2026-04-09 06:00:59 +09:00

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