Adds a self-contained omni-pca/grafana/ bundle (InfluxDB v2 + Grafana with pre-provisioned datasource and dashboard) plus dev-stack wiring so iterating against the mock or real panel is one docker-compose-up. The dashboard has four rows plus an insights row: System health AC, battery, trouble, 24h event count Security area arming state, recent events table, zone trips Climate thermostat temperatures, HVAC mode Activity event rate by type, top toggled units Insights active zone bypasses, button press log, event distribution Color-coded event_type tags persist across panels (alarms red, restores green, batteries orange, etc.); explicit no-purple palette per CLAUDE.md. The bundle is portable: any HA install can use it by running grafana/ docker compose up -d and pasting ha-snippet.yaml into configuration.yaml. For the dev stack, dev/docker-compose.yml mounts the same provisioning files so dev and prod stay in lockstep. Verified end-to-end against the real Our House.pca panel (192.168.1.9): the dashboard fills with live zone trips, X-10 unit toggles, and push-event traffic within 30s of HA bootup.
176 lines
6.1 KiB
YAML
176 lines
6.1 KiB
YAML
# Local dev stack: real Home Assistant talking to a MockPanel running on
|
|
# the host. Lets you click around the UI and grab screenshots without a
|
|
# physical Omni controller.
|
|
#
|
|
# make dev-up # start
|
|
# make dev-logs # tail HA logs
|
|
# make dev-down # stop and clean
|
|
#
|
|
# On every container start the HA service pip-installs the local
|
|
# `omni-pca` library from ../ into site-packages (the version pinned in
|
|
# the integration manifest isn't on PyPI yet, and we want our latest
|
|
# v1/ subpackage available either way). Source changes in src/omni_pca
|
|
# require a ``docker compose restart homeassistant`` to take effect.
|
|
#
|
|
# Once running, open http://localhost:8123 and:
|
|
# 1. Onboard with any name / location.
|
|
# 2. Settings -> Devices & Services -> Add Integration ->
|
|
# "HAI/Leviton Omni Panel".
|
|
# 3. Use one of:
|
|
# Mock panel (TCP):
|
|
# host host.docker.internal
|
|
# port 14369
|
|
# transport TCP
|
|
# controller_key 000102030405060708090a0b0c0d0e0f
|
|
# Real panel (UDP, v1 wire protocol):
|
|
# host <panel IP, e.g. 192.168.1.9>
|
|
# port 4369
|
|
# transport UDP
|
|
# controller_key <32 hex chars from the panel's .pca file>
|
|
|
|
services:
|
|
mock-panel:
|
|
image: ghcr.io/astral-sh/uv:python3.14-bookworm-slim
|
|
working_dir: /tmp/mock
|
|
volumes:
|
|
- ../src:/tmp/mock/src:ro
|
|
- ./run_mock_panel.py:/tmp/mock/run_mock_panel.py:ro
|
|
# Mount the captured .pca fixtures read-only so the mock can
|
|
# optionally seed its state from a real export. Set
|
|
# OMNI_PCA_FIXTURE in dev/.env (or pass on the command line) to
|
|
# activate; left unset, the mock uses the hard-coded sample.
|
|
- /home/kdm/home-auto/HAI:/fixtures:ro
|
|
environment:
|
|
PYTHONPATH: /tmp/mock/src
|
|
OMNI_PCA_FIXTURE: ${OMNI_PCA_FIXTURE:-}
|
|
command:
|
|
- sh
|
|
- -c
|
|
- "uv pip install --system --quiet cryptography && python /tmp/mock/run_mock_panel.py --host 0.0.0.0 --port 14369"
|
|
ports:
|
|
- "14369:14369"
|
|
networks:
|
|
- default
|
|
|
|
homeassistant:
|
|
image: ghcr.io/home-assistant/home-assistant:2026.5
|
|
container_name: omni-pca-dev-ha
|
|
depends_on:
|
|
- mock-panel
|
|
volumes:
|
|
- ./ha-config:/config
|
|
- ../custom_components/omni_pca:/config/custom_components/omni_pca:ro
|
|
# Make the whole library project (pyproject + src/ + dist/) available
|
|
# so the entrypoint override below can pip-install from local source
|
|
# before /init starts. This gives HA real dist-info for
|
|
# ``omni-pca==2026.5.10`` (which isn't on PyPI yet) and ensures the
|
|
# v1 subpackage is present.
|
|
- ../:/opt/omni-pca-src:ro
|
|
# Keep 8123 mapped on localhost for direct access during development;
|
|
# public traffic comes in via caddy-docker-proxy on the `caddy` net.
|
|
ports:
|
|
- "8123:8123"
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
environment:
|
|
- TZ=America/Boise
|
|
networks:
|
|
- default
|
|
- caddy
|
|
labels:
|
|
caddy: juliet.warehack.ing
|
|
caddy.reverse_proxy: "{{upstreams 8123}}"
|
|
# HA uses WebSockets for the frontend (lovelace state updates,
|
|
# config flow, etc.) so we need the streaming-friendly settings
|
|
# from CLAUDE.md, otherwise caddy closes the socket every ~15s.
|
|
caddy.reverse_proxy.flush_interval: "-1"
|
|
caddy.reverse_proxy.transport: http
|
|
caddy.reverse_proxy.transport.read_timeout: "0"
|
|
caddy.reverse_proxy.transport.write_timeout: "0"
|
|
caddy.reverse_proxy.transport.keepalive: 5m
|
|
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
|
|
caddy.reverse_proxy.stream_timeout: 24h
|
|
caddy.reverse_proxy.stream_close_delay: 5s
|
|
# HA's image entrypoint is /init (s6-overlay). We pre-install our
|
|
# local library against site-packages so HA's manifest-requirement
|
|
# check finds it, then exec /init normally.
|
|
entrypoint:
|
|
- sh
|
|
- -c
|
|
- |
|
|
set -e
|
|
pip install --quiet --no-deps --upgrade /opt/omni-pca-src
|
|
exec /init
|
|
|
|
# InfluxDB v2 + Grafana stack — kept inline rather than `extends:`-ing
|
|
# ../grafana/docker-compose.yml so this file stays self-contained and
|
|
# the named volumes get scoped to this compose project. The bundle
|
|
# compose stays the canonical ship-to-users version; we share its
|
|
# provisioning files via the volume mount on the grafana service.
|
|
influxdb:
|
|
image: influxdb:2.7-alpine
|
|
container_name: omni-pca-dev-influxdb
|
|
restart: unless-stopped
|
|
environment:
|
|
DOCKER_INFLUXDB_INIT_MODE: setup
|
|
DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUX_USERNAME:-admin}
|
|
DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUX_PASSWORD}
|
|
DOCKER_INFLUXDB_INIT_ORG: omni-pca
|
|
DOCKER_INFLUXDB_INIT_BUCKET: ha
|
|
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUX_TOKEN}
|
|
DOCKER_INFLUXDB_INIT_RETENTION: 30d
|
|
volumes:
|
|
- influxdb-data:/var/lib/influxdb2
|
|
- influxdb-config:/etc/influxdb2
|
|
ports:
|
|
- "8086:8086"
|
|
networks:
|
|
- default
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8086/health"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
grafana:
|
|
image: grafana/grafana:11.4.0
|
|
container_name: omni-pca-dev-grafana
|
|
restart: unless-stopped
|
|
depends_on:
|
|
influxdb:
|
|
condition: service_healthy
|
|
environment:
|
|
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
|
|
GF_AUTH_ANONYMOUS_ENABLED: "false"
|
|
GF_USERS_ALLOW_SIGN_UP: "false"
|
|
GF_LOG_LEVEL: warn
|
|
INFLUX_URL: http://influxdb:8086
|
|
INFLUX_TOKEN: ${INFLUX_TOKEN}
|
|
volumes:
|
|
- grafana-data:/var/lib/grafana
|
|
- ../grafana/provisioning:/etc/grafana/provisioning:ro
|
|
ports:
|
|
- "3000:3000"
|
|
networks:
|
|
- default
|
|
- caddy
|
|
labels:
|
|
caddy: grafana-omni.juliet.warehack.ing
|
|
caddy.reverse_proxy: "{{upstreams 3000}}"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
start_period: 15s
|
|
|
|
volumes:
|
|
influxdb-data:
|
|
influxdb-config:
|
|
grafana-data:
|
|
|
|
networks:
|
|
caddy:
|
|
external: true
|