Pytest harness (in-process HA + MockPanel)
==========================================
pyproject.toml — bumps requires-python to 3.14.2 to align with HA 2026.5.x
which is what pytest-homeassistant-custom-component pins. Dev group 'ha'
pulls the harness; .python-version updated to 3.14.
src/omni_pca/mock_panel.py — Thermostat (6) and Button (3) RequestProperties
handlers added (previous commit). Without these the HA coordinator's
discovery walk produced empty thermostat/button dicts.
custom_components/omni_pca/services.py — fix CONF_ENTRY_ID import: HA
exports it as ATTR_CONFIG_ENTRY_ID, not CONF_ENTRY_ID. Aliased on import.
tests/conftest.py — re-enables sockets globally (the HA harness installs
pytest_socket which otherwise blocks our network e2e tests).
tests/ha_integration/ — new directory with full HA boot harness:
conftest.py:
- autouse enable_custom_integrations so HA loads our component
- autouse expected_lingering_tasks=True (background event listener)
- autouse _short_scan_interval (1s instead of 30s for fast tests)
- panel fixture: MockPanel on a random localhost port for each test
- configured_panel fixture: builds a MockConfigEntry, runs setup,
yields, then unloads on teardown so the coordinator's reader task
and OmniClient socket close cleanly (otherwise verify_cleanup hangs)
test_setup.py — 12 tests:
- integration loads + system_info populated
- alarm_control_panel/light/switch/climate/button/event/binary_sensor
entities materialise per platform
- unload_entry tears down cleanly
- turning a light on via HA service updates the mock state
- arming via HA service with the right code transitions the area
- arming with wrong code keeps the area disarmed and surfaces error
Total: 351 passed, 1 skipped (PCA fixture). Ruff clean across src/ tests/
custom_components/. The 12 HA integration tests run in <1s end-to-end —
they boot HA in-process, drive the config flow, exercise services, and
verify state mutations on the mock side.
Docker dev stack (manual smoke / screenshots)
=============================================
dev/docker-compose.yml — HA 2026.5 container + MockPanel sidecar.
dev/run_mock_panel.py — long-running mock with a populated state
(5 zones, 4 units, 2 areas, 2 thermostats, 3 buttons, codes 1234/5678).
dev/Makefile — make dev-up / dev-logs / dev-down / dev-mock / dev-reset.
dev/README.md — onboarding walkthrough (host=host.docker.internal,
port=14369, controller_key=000102030405060708090a0b0c0d0e0f).
.gitignore — adds ha-config/ so the persisted HA state from the dev
stack doesn't get committed.
47 lines
1.3 KiB
YAML
47 lines
1.3 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
|
|
#
|
|
# 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:
|
|
# host host.docker.internal
|
|
# port 14369
|
|
# controller_key 000102030405060708090a0b0c0d0e0f
|
|
# (matches scripts/run_mock_panel.py defaults)
|
|
|
|
services:
|
|
mock-panel:
|
|
image: ghcr.io/astral-sh/uv:python3.14-bookworm-slim
|
|
working_dir: /app
|
|
volumes:
|
|
- ..:/app:ro
|
|
command: >
|
|
uv run --project /app
|
|
python /app/dev/run_mock_panel.py
|
|
--host 0.0.0.0
|
|
--port 14369
|
|
ports:
|
|
- "14369:14369"
|
|
|
|
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
|
|
ports:
|
|
- "8123:8123"
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
environment:
|
|
- TZ=America/Boise
|