homebridge-gardenwatering
v0.2.2
Published
Homebridge dynamic-platform plugin that exposes GardenWatering zones and groups as HomeKit Switches. Commands flow through gw-api (so they land in the Connector's ActiveRunRegistry), state is push-driven directly from the gw-broker RabbitMQ snapshot strea
Downloads
720
Maintainers
Readme
homebridge-gardenwatering
Homebridge dynamic-platform plugin that exposes GardenWatering zones and groups as HomeKit Switches.
Why this plugin exists: GardenWatering Phase 5 introduced a service-bus-driven KNX bridge (gw-pump-demand) that turns the garden pump on/off based on the Connector's ActiveRunRegistry. Voice-triggered runs ("Hey Siri, Pfirsichbaum an") MUST flow through the Connector so the bridge sees demand. This plugin re-routes the HomeKit surface through gw-api → bus → Connector → snapshot → bridge → KNX → pump.
Transport split (since 0.2.0):
- Commands (run / stop) flow over HTTPS to
gw-api, which keeps the slug/auth/conflict logic single-sourced. - State (zone running / idle) is push-driven directly from the
gw-brokerRabbitMQ snapshot stream — the plugin is a third snapshot-subscriber alongsidegw-pump-demandand the cloud-sideRunStateConsumer. HTTP polling is the fallback when the bus is unreachable.
Full architectural rationale: see docs/gw-homebridge-spec.md §6 in the GardenWatering repo.
What it exposes
- One HomeKit Switch per Zone — name = zone display name, runtime =
Zone.DefaultRuntimeMinutes(clamped to 60 min server-side). - One HomeKit Switch per Group — name = group display name. ON triggers the whole group (Connector fans out per-zone with each zone's own runtime).
- Disabled groups (
enabled: falsecloud-side) are hidden. - Switch state syncs in real time from
gw-broker(push). When the bus is unreachable, HTTP polling againstgw-apitakes over atpollIntervalSecscadence (default 5 s).
Install
Step 1 — Provision an API key on the cloud side
The plugin authenticates command requests against gw-api via a static X-Gw-ApiKey header. Generate a key and add it to the production environment:
ssh production-ssh
# Generate a 32-byte hex secret
KEY=$(openssl rand -hex 32)
# Add to /opt/deployment/production/.env:
# GW_API_KEY_HOMEBRIDGE=<the key>
# The deployment docker-compose maps GW_API_KEY_HOMEBRIDGE -> ApiKey__Value
# (the .NET-side config path) at container boot.
# Restart gw-api
sudo docker compose -f /opt/deployment/production/docker-compose.yml \
up -d --force-recreate gw-apiStep 1b — Provision the RabbitMQ password (since 0.2.0)
The bus listener authenticates as RabbitMQ user gw-homebridge-knoth. The user
itself + RBAC are defined in
deploy/broker/etc-rabbitmq/definitions.json.template.
Only the password needs provisioning:
ssh production-ssh
# Generate a 32-byte hex secret
PW=$(openssl rand -hex 32)
# Add to /opt/deployment/production/.env:
# GARDEN_RABBITMQ_HOMEBRIDGE_KNOTH_PASS=<the secret>
# The broker container picks this up via env-var substitution in the
# definitions.json template; user is provisioned on next broker restart.
# Restart the broker
sudo docker compose -f /opt/deployment/production/docker-compose.yml \
up -d gw-brokerThe plugin declares its own durable queue (gw.homebridge.knoth) and binding
on first connect — no broker-side queue setup needed beyond the user.
Step 2 — Install the plugin on the NAS
- Open the Homebridge UI (
http://10.130.55.18:8581). - Plugins → Search "homebridge-gardenwatering" → Install.
- Settings → paste:
apiBaseUrl:https://garten.knoth.nameapiKey: the key generated in Step 1pollIntervalSecs:5(HTTP fallback cadence)discoveryRefreshSecs:300(active while bus is healthy)bus.enabled:truebus.host:gw-broker.softics.debus.port:5671bus.username:gw-homebridge-knothbus.password: the value from Step 1bbus.queueName:gw.homebridge.knothbus.tls:true
- Save → Restart Homebridge.
Step 3 — Pair with iOS Home
If Homebridge isn't already paired with iOS Home, follow the standard pairing flow (QR code in the UI).
Step 4 — Verify
In iOS Home, the new GardenWatering accessory tile shows all zones and groups as Switches. Say "Hey Siri, Pfirsichbaum an" — within ~10 s:
- The HomeKit Switch flips ON.
tel.knoth.active-runs.snapshotshowspfirsichbaum(visible ingw-workertelemetry log).gw-pump-demandlogsKNX write GA=0/2/2 value=True ack=true.- The pump audibly starts.
Say "Pfirsichbaum aus" — the reverse happens within ~10 s.
Configuration schema
| Field | Type | Default | Notes |
|---|---|---|---|
| apiBaseUrl | string (URI) | https://garten.knoth.name | Base URL of gw-api — command path. |
| apiKey | string | required | Value of GW_API_KEY_HOMEBRIDGE from the cloud-side .env. |
| pollIntervalSecs | integer | 5 | HTTP fallback poll cadence (2–60). Active while the bus listener is disabled or disconnected. |
| discoveryRefreshSecs | integer | 300 | Topology-drift refresh cadence (60–1800) while the bus listener is healthy. State arrives from the bus push stream. |
| bus.enabled | boolean | true | Subscribe to tel.knoth.active-runs.snapshot on gw-broker for push-based state. |
| bus.host | string | gw-broker.softics.de | Broker hostname. |
| bus.port | integer | 5671 | Broker port. AMQPS by default. |
| bus.username | string | gw-homebridge-knoth | Least-privileged broker user (see definitions.json.template). |
| bus.password | string | required if bus enabled | Value of GARDEN_RABBITMQ_HOMEBRIDGE_KNOTH_PASS from the cloud-side .env. |
| bus.queueName | string | gw.homebridge.knoth | Plugin-owned durable queue, bound to gw.events / tel.knoth.active-runs.snapshot. |
| bus.tls | boolean | true | Use AMQPS. |
Compatibility
| gw-api version | homebridge-gardenwatering | Notes |
|---|---|---|
| Phase 5 (post-6575038, GwUsersOrApiKey on GET zones/groups) | 0.1.x | First version. Requires Plan 03 ApiKey scheme + the pre-plugin auth-policy patch on discovery endpoints. |
| Phase 5 + definitions.json.template carries gw-homebridge-knoth user | 0.2.x | Adds direct RabbitMQ snapshot subscriber. HTTP polling remains the fallback transport. |
Homebridge runtime: tested against Homebridge 1.8.x and 2.0.x (declared via engines.homebridge: "^1.8.0 || ^2.0.0"). Plugin uses only stable dynamic-platform APIs (DynamicPlatformPlugin, Service.Switch, Characteristic.On) — no v2-only or v1-only surface.
Error handling
gw-api (commands + HTTP fallback)
| Server response | Plugin behaviour |
|---|---|
| 200 (GET) / 202 (POST) | Happy path. |
| 401 | Logged as error; HomeKit Switch state not changed; retry on next poll. Operator action: check the apiKey config + cloud-side .env. |
| 404 on slug | Logged as warning; accessory removed on next discovery cycle. |
| 409 | Logged as info; ignored. Higher-priority command in flight; next snapshot will sync. |
| 5xx / network failure | Logged as warning; last-known state kept; retry on next poll. |
gw-broker (bus listener)
| Condition | Plugin behaviour |
|---|---|
| Connection healthy | State push-driven; HTTP poll slowed to discoveryRefreshSecs for topology-drift only. |
| Connection drops | Logged as warning; HTTP poll reverts to pollIntervalSecs cadence (covers state via zone.state). Auto-reconnect with exponential backoff (1 s → 30 s). |
| Auth / permission failure | Logged as error; reconnect loop continues (RabbitMQ does not lock out on failed logins by default). Check broker user/password + RBAC in definitions.json.template. |
| Deserialization failure | Logged as warning; message ack-and-dropped (no nack/requeue — poison-message-loop guard). Next snapshot/liveness pulse arrives within 30 s. |
| bus.enabled: false or bus.password missing | Bus listener never starts. Plugin runs purely on HTTP polling at pollIntervalSecs. |
License
MIT © 2026 Softics GmbH
