Data Update Coordinator¶
The coordinator manages optimization cycles and result distribution using an event-driven model.
Purpose¶
HAEO's coordinator implements Home Assistant's DataUpdateCoordinator pattern to orchestrate optimization cycles.
The implementation is in custom_components/haeo/coordinator/coordinator.py.
Network building functions are in custom_components/haeo/coordinator/network.py.
The coordinator performs these core responsibilities:
- Reads pre-loaded data from input entities
- Validates input alignment before optimization
- Builds network model from configuration and loaded data
- Runs LP solver in executor thread (non-blocking)
- Updates network parameters for warm start optimization
- Distributes results to sensors
- Triggers re-optimization on input changes or horizon boundaries
- Handles errors gracefully with UpdateFailed exceptions
Event-driven updates:
Unlike traditional coordinators with fixed polling intervals, HAEO uses event-driven triggers. Optimization runs when input entity states change or when the HorizonManager signals a period boundary crossing. This ensures optimization uses the latest data without unnecessary polling.
Subentry discovery:
The coordinator is created only for hub entries (identified by integration_type: "hub").
It discovers element subentries by querying the config entry registry for entries where parent_entry_id matches the hub's entry_id.
This discovery happens on each update cycle, supporting dynamic element addition and removal without integration reload.
Update Cycle¶
The coordinator follows this sequence for each optimization cycle:
sequenceDiagram
participant Trigger as Event Trigger
participant C as Coordinator
participant RD as RuntimeData
participant N as Network
participant LP as LP Solver
Trigger->>C: Input change / Horizon boundary
C->>RD: Read runtime_data.inputs
C->>C: Check input alignment
alt Inputs not aligned
C-->>Trigger: Skip (wait for alignment)
else Inputs aligned
alt First optimization
C->>N: create_network() from inputs
N-->>C: New network
else Subsequent optimization
C->>N: update_element() with new parameters
Note over N: Only invalidated constraints rebuilt
end
C->>LP: Optimize (executor)
LP-->>C: Optimal solution
C->>C: Extract results
C-->>Trigger: Return results
end
Update phases¶
1. Input alignment check
Before optimization, the coordinator verifies all input entities have matching horizon_id values.
This ensures temporal consistency—all inputs represent the same forecast horizon.
If inputs are misaligned (some entities haven't refreshed after a horizon change), the coordinator skips optimization and waits.
2. Data reading
The coordinator reads pre-loaded values from runtime_data.inputs, a dictionary keyed by (element_name, field_name).
Input entities populate this dictionary during their refresh cycles.
See Input Entities for details on how data loading works.
3. Optimization
The network optimization runs in an executor thread via hass.async_add_executor_job() to avoid blocking the event loop.
The coordinator extracts the solver name from configuration and passes it to network.optimize().
This blocking operation is tracked for diagnostics timing.
Network building and warm start:
On the first optimization cycle, the coordinator calls create_network() from coordinator/network.py to build the complete network from configuration.
On subsequent cycles, it calls update_element() to update element parameters without recreating the network.
The warm start pattern works by:
- Elements declare parameters using
TrackedParamdescriptors update_element()modifies these parameters directly- Changed parameters automatically invalidate dependent constraints
- Only invalidated constraints are rebuilt during optimization
- Unchanged constraints are reused from the previous solve
This selective rebuilding is more efficient than recreating the entire problem, particularly when only forecasts change between cycles.
4. Result extraction
The coordinator converts model outputs to Home Assistant-friendly structures using _collect_outputs().
Results include optimization cost, status, duration, and entity-specific outputs (power, energy, SOC, etc.).
These are stored in coordinator.data and exposed to sensor entities through the coordinator pattern.
Error Handling¶
The coordinator implements comprehensive error handling using Home Assistant's UpdateFailed exception pattern:
Error scenarios¶
Sensor unavailability (startup)
When configured sensors are not yet available, the coordinator returns PENDING status without logging an error (this is expected during startup).
Sensors show "Unavailable" state in the UI, and the coordinator retries on the next input entity update or horizon boundary.
Data loading errors
When sensor data is available but loading fails (invalid format, missing forecast, type conversion failures), the coordinator raises UpdateFailed with a descriptive message.
Optimization errors
When network optimization fails (infeasible constraints, solver not installed, numerical instabilities), the coordinator raises UpdateFailed with the solver error.
Error propagation¶
All coordinator errors raise UpdateFailed, which:
- Sets
coordinator.last_update_success = False - Logs the error message
- Makes dependent entities unavailable
- Schedules a retry on the next interval
State change triggers use the same error handling through the coordinator framework and don't crash the integration.
Event-Driven Triggers¶
The coordinator uses event-driven triggers instead of a fixed polling interval.
Trigger sources¶
Input entity state changes
When any input entity updates its state (due to external sensor changes or user modification), the coordinator receives a state change event and schedules optimization.
Horizon boundary crossings
The coordinator subscribes to the HorizonManager. When the forecast horizon advances (at period boundaries like every 1 minute for the finest tier), the manager notifies the coordinator to refresh.
Manual refresh
Users can trigger optimization via the standard Home Assistant update service or entity refresh action. Manual refreshes bypass the cooldown period.
Custom debouncing¶
The coordinator implements custom debouncing to prevent excessive optimization runs:
sequenceDiagram
participant E as Event
participant C as Coordinator
participant Timer
E->>C: State change
alt Outside cooldown
C->>C: Run optimization immediately
C->>C: Record _last_optimize_time
else Within cooldown
C->>C: Set _optimize_pending = True
Note over C: Wait for cooldown
end
Timer->>C: Cooldown expires
alt _optimize_pending
C->>C: Run optimization
C->>C: Clear _optimize_pending
end
Debouncing parameters:
- Cooldown period: Minimum time between optimizations (prevents rapid re-runs)
- Pending flag: Tracks whether optimization was requested during cooldown
- Timer: Schedules retry when cooldown expires with pending request
This approach batches rapid updates while ensuring eventual consistency.
Subscription lifecycle¶
- Initialization: Coordinator created without active subscriptions
- First refresh: Initial optimization runs, subscriptions enabled on success
- Runtime: Subscriptions active, coordinator responds to events
- Shutdown: Subscriptions cancelled via cleanup callbacks
Testing¶
Coordinator testing uses Home Assistant's test fixtures and mocks.
Comprehensive test coverage is in tests/test_coordinator.py, including:
- Successful coordinator updates
- Input alignment verification
- Debouncing behavior
- Optimization failure cases
- Event-driven trigger behavior
Example test pattern:
@pytest.fixture
async def coordinator(hass: HomeAssistant, mock_config_entry: MockConfigEntry) -> HaeoDataUpdateCoordinator:
"""Create coordinator for testing."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
return mock_config_entry.runtime_data.coordinator
Related Documentation¶
-
Horizon Manager
Synchronized forecast time windows.
-
Input Entities
How input entities load and expose data.
-
Architecture
System overview and component relationships.
-
Data Loading
How data is extracted and aligned.
-
Energy Models
Network entities and constraints.
-
Home Assistant DataUpdateCoordinator
Upstream pattern documentation.