Local Home Assistant simulation¶
Use uv run sim to spin up a real, browsable Home Assistant instance for interactive development and testing.
The simulator loads scenario input data from tests/scenarios/, time-shifts forecasts and prices to track the current (or accelerated) clock, optionally configures HAEO from the scenario config, and tears down when you press Ctrl+C.
This replaces the previous config/packages/ command_line sensor workflow.
Quick start¶
By default it uses the repo config/ directory on port 8123, applies the scenario timezone, skips onboarding, and opens your browser to http://127.0.0.1:8123/.
From there you can inspect entities, HAEO sensors, and the frontend while the simulator pushes updated input states on an interval.
Login is automatic: the instance registers a trusted_networks auth provider that logs in the single dev user for any request from loopback, so the frontend completes its OAuth flow without any token bootstrap.
This is the same auth setup the guide tests use, so there is a single login mechanism across both runners.
If auto-login does not take, testuser / testpass works as a fallback.
Scenario data¶
Each scenario directory under tests/scenarios/ provides:
inputs.json— Home Assistant entity states (including forecast attributes)environment.json— anchor time (optimization_start_time) and timezoneconfig.json— HAEO hub and element configuration (used when HAEO setup is enabled)
The simulator shifts all ISO 8601 timestamps in the input attributes so the scenario's captured "now" aligns with the simulated clock. HAEO re-optimizes when input states change, the same way it would with live forecast sensors.
Options¶
# Faster updates (every 30 seconds)
uv run sim scenario1 --interval 30
# Accelerated time: 60× real time (experimental)
uv run sim scenario1 --speed 60 --interval 5
# Load inputs only; configure HAEO manually in the UI
uv run sim scenario1 --no-config
# Ephemeral config directory and random port (for CI or isolated runs)
uv run sim scenario1 --ephemeral
# Custom config directory or port
uv run sim scenario1 --config-dir config --port 8123
| Flag | Default | Description |
|---|---|---|
scenario |
scenario1 |
Scenario name under tests/scenarios/ or path to a scenario directory |
--interval |
60 |
Seconds between input state updates |
--speed |
1.0 |
Time multiplier; 1.0 uses wall clock, >1 accelerates simulated time |
--no-config |
off | Skip automatic HAEO setup from config.json |
--config-dir |
config/ |
Home Assistant config directory |
--port |
8123 |
HTTP port |
--no-open |
off | Do not open the browser on startup |
--ephemeral |
off | Use a temporary config directory and ephemeral port |
How it works¶
tools/live_hass.pyboots an in-process Home Assistant with HTTP, frontend, auth, and recorder (default:config/on port 8123). The sim binds HTTP to127.0.0.1and adds atrusted_networksprovider withallow_bypass_login, so loopback requests log in automatically.tools/time_shift.pyapplies a uniform timestamp delta to scenario input attributes.tools/sim.pyruns a loop that recomputes the delta each tick, pushes shifted states viahass.states.async_set(), and optionally callssetup_haeo_entry()from the scenario config.
Accelerated mode (--speed > 1) uses freezegun to advance Home Assistant's clock alongside the shifted data.
This mode is experimental; recorder timing and debouncers may behave differently than in production.
Related workflows¶
- Scenario regression tests:
uv run pytest tests/scenarios/ -m scenario— snapshot comparison at a single frozen instant - Offline diagnostics:
uv run diag --file tests/scenarios/scenario1/— model-only optimization without Home Assistant - Guide screenshots:
uv run pytest -m guide— Playwright walkthroughs using the same live HA runner
For scenario authoring, see tests/scenarios/README.md.
Plain Home Assistant¶
uv run sim is the recommended replacement for uv run hass -c config when developing with HAEO.
It uses the same config/ directory and port 8123 by default, but also loads time-shifted scenario inputs and can configure HAEO automatically.
To run Home Assistant without scenario inputs: