Skip to content

Architecture

HAEO follows Home Assistant integration patterns with specialized optimization components. This guide focuses on HAEO-specific architecture. For Home Assistant fundamentals, see the Home Assistant developer documentation.

System Overview

graph TD
    CF[Config Flow] --> CE[Config Entry]
    CE --> Coord[Coordinator]
    Coord --> Loaders[Data Loaders]
    Coord --> Builder[Network Builder]
    Builder --> Model[Network Model]
    Model --> Solver[LP Solver]
    Solver --> Results[Results]
    Results --> Sensors[Sensors]

    style Coord fill:#FFE4B5
    style Solver fill:#90EE90

Core Components

Config Flow (config_flow.py, flows/)

User-facing configuration via the Home Assistant UI. The hub flow creates the main entry and exposes additional flows so users can add and manage elements without leaving the standard interface. See the config entry documentation for the underlying Home Assistant patterns.

Coordinator (coordinator.py)

Central manager scheduling optimization cycles (default 5 min), loading data, building network, running solver, distributing results. Each hub entry creates one coordinator instance.

See the data update coordinator documentation for the base pattern. HAEO's coordinator gathers sensor values, assembles the optimization network, runs the solver in an executor, and pushes the results back to the entities. It listens for element additions or removals and triggers a refresh whenever the underlying data changes.

Data loaders (data/)

Data loaders translate configuration into time series the model can consume. They validate values during the config flow and fetch real sensor data at runtime, including support for common forecast formats. Keep new loaders focused on a single responsibility and reuse the shared parser utilities where possible.

Network Builder

Creates optimization model from config:

  • Instantiates element objects (Battery, Grid, etc.)
  • Creates Connection objects
  • Builds Network container
  • Validates structure

Network Model (model/)

LP representation using PuLP:

  • Element: Base class for all model elements with power/energy variables
  • Battery: Storage with charge/discharge power, SOC constraints
  • Grid: Import/export with optional limits and pricing
  • Photovoltaics: Solar generation with optional curtailment
  • ConstantLoad, ForecastLoad: Consumption elements
  • Node: Virtual balance point enforcing Kirchhoff's law
  • Connection: Power flow path with optional min/max limits
  • Network: Container with optimize(), cost(), and constraints() methods

LP Solver

Multiple solvers supported via PuLP:

  • HiGHS (default): Fast, open-source, no external dependencies
  • CBC, GLPK, COIN-OR, SCIP, CyLP: Alternative solvers

Solves linear programming minimization problem, returns optimal cost and decision variable values.

Sensors (sensors/)

Sensor entities expose optimization outputs through standard Home Assistant constructs. Separate modules handle network-level metrics and per-element values, and every sensor carries a forecast attribute so downstream automations can look ahead. Refer to the sensor entity documentation when adding new measurements.

Model Architecture (model/)

Separate subsystem implementing the optimization model:

Design principles: - Pure Python linear programming using PuLP - Elements generate their own variables and constraints - Network assembles elements and runs solver - No Home Assistant dependencies in model layer

Key components: - Element: Base class with power/energy variable patterns - Entity classes: Battery, Grid, Photovoltaics, Loads, Node - Connection: Power flow with limits - Network: Container with optimize() method

Code Organization

The integration lives under custom_components/haeo/ and follows Home Assistant layout conventions. Rather than documenting every file, focus on how the major areas collaborate:

  • Entry points: __init__.py, config_flow.py, and coordinator.py bootstrap the integration, collect user input, and run optimizations on schedule.
  • Flows (flows/): Houses hub, element, and options flows; each submodule owns the UI schema for a related group of entries.
  • Data layer (data/): Loader modules turn Home Assistant sensors and forecasts into normalized time series for the optimizer.
  • Model (model/): Pure Python optimization layer composed of elements, connections, and network orchestration.
  • Metadata (elements/ and schema/): Describe configuration defaults, validation, and runtime metadata for every element type.
  • Presentation (sensors/): Builds coordinator entities and sensor platforms that publish optimization results back to Home Assistant.
  • Translations (translations/): Provides user-facing strings for config flows and entity names.

Extension Points

Adding Element Types

  1. Create model class in model/:
  2. Inherit from Element
  3. Define power/energy variables
  4. Implement cost() and constraints() methods

  5. Add element metadata in elements/:

  6. *ConfigSchema: For config flow validation
  7. *ConfigData: For runtime with loaded values
  8. Define field metadata using annotations

  9. Register element type in elements/__init__.py:

  10. Add to ELEMENT_TYPES mapping

  11. Create config flow in flows/elements/:

  12. Inherit from appropriate base
  13. Implement validation and schema generation

  14. Update translations in translations/en.json:

  15. Add device and selector entries

  16. Write tests:

  17. Model tests in tests/test_model.py
  18. Config flow tests in tests/flows/
  19. Integration tests

Custom Solvers

Add solver support in model/network.py:

  • Map solver names in const.py
  • Add solver validation
  • Update optimize() to handle new solver options

Custom Field Types

Extend schema/fields.py:

  • Create new FieldMeta subclass
  • Define validation schema
  • Implement loader logic
  • Register with field type system