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
2026-03-25 19:51:34 +09:00
2026-03-25 19:52:15 +09:00
2026-03-25 19:52:15 +09:00
2026-03-25 19:52:15 +09:00

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

.
├── 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.

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:

buf generate

Generated files are written to gen/ha/v1.

Build

Sync the workspace, then build the gateway:

go work sync
cd ha-gateway
go build ./...

Run Locally

Create a local env file:

cp ha-gateway/.env.example ha-gateway/.env

Fill in HA_TOKEN and HA_BASE_URL, then start the server:

cd ha-gateway
go run ./cmd/gateway

The gateway listens on :50051 by default.

Smoke Test With grpcurl

Examples against a locally running gateway:

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

docker build -f ha-gateway/Dockerfile -t ha-gateway:dev .

Run it with the same env file:

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 explicitly calls out API-key and mTLS as future options before exposing the gateway outside a trusted network.

Description
No description provided
Readme 326 KiB
Languages
Go 99.2%
Dockerfile 0.8%