2026-10-26 18:13:00 +02:00
2026-10-26 18:13:00 +02:00
2026-10-26 17:34:32 +02:00
2026-10-26 17:34:32 +02:00
2026-10-26 18:13:00 +02:00
2026-10-26 17:34:32 +02:00
2026-10-26 18:13:00 +02:00
2026-10-26 18:13:00 +02:00

Heating MPC 0.2.1 — custom integration for Home Assistant OS

Experimental, observation-only (shadow mode). It never changes the Generic Thermostat, the physical relay, the boiler's setpoint, heat/off, or Comfort/Away/Sleep. No Docker add-on, MQTT or InfluxDB connection is needed.

This project targets Home Assistant OS on a Raspberry Pi 5, with one existing ON/OFF central-heating relay, generic_thermostat, and individual indoor temperature sensors.

Install / upgrade

  1. Create a Home Assistant backup.
  2. Copy the entire folder custom_components/heating_mpc into /config/custom_components/heating_mpc (replace its contents when upgrading from v0.1.0).
  3. Restart Home Assistant Core.
  4. If new: Settings → Devices & services → Add integration → Heating MPC. If installed already: select Heating MPC → Configure (Options).
  5. Choose the existing thermostat and physical heating switch (read-only), then individual room sensor entities.
  6. Choose ordered lists of outdoor sensor entity IDs. First valid sensor is active; if missing, unavailable, nonnumeric or outside reasonable bounds, the next valid sensor is used automatically.
  7. Assign a relative comfort weight (0.1–10) to each selected room.

No entity IDs are hard-coded. Every room and outdoor measurement can be changed later via Configure, without editing YAML or Python.

Reconfigurable weather inputs

Measurement Required? Used in the thermal model in 0.2.0?
Outdoor temperature Yes (1–10 prioritized sensors) Yes: estimates thermal losses; constant over the 2 h forecast window
Wind speed No No, diagnostics/source comparison only
Cloud cover No No, diagnostics/source comparison only
Humidity No No, diagnostics/source comparison only
Feels-like temperature No No, diagnostics/source comparison only
Atmospheric pressure No No, diagnostics/source comparison only
Visibility No No, diagnostics/source comparison only
Rain / snow No No, diagnostics/source comparison only

Choose multiple sensors for a single variable, e.g. OpenWeatherMap then another provider, in priority order. Switch order in Configure to run A/B comparisons on successive days, or simply let the second sensor act as fallback. The active source and all current alternative readings are visible in the Heating MPC Status entity attributes (weather, weather_active_sources, weather_comparison). The MPC Outdoor Temperature sensor also has an active_source attribute and an alternatives map.

Measurements are normalized where possible: outdoor temperatures to °C; wind to m/s; pressure to hPa; visibility to meters. Unknown units or values outside plausibility bounds are rejected in favor of the next selected sensor. Clouds and humidity are expected in %, rain/snow in mm or mm/h as represented by their upstream sensor. A fallback source may have a different sampling delay; configurable report-age limits now reject stale inputs (see below).

Switching only the weather-provider sensors does not reset learned thermal parameters. The update is applied after the integration reloads, and it skips learning one transition when the primary temperature source changes, avoiding a jump in the training series. Nevertheless, two sensors with a persistent offset can bias predictions; compare their readings and validate the model again before relying on them. Replacing the physical heating switch discards incompatible model parameters. Existing room-specific parameters are retained if room entity IDs remain unchanged.

Model, sampling and output

  • Every 5 minutes: reads HA sensor states and observed relay state; learns a per-room linear thermal model dT = a*(T_out-T_room) + b*effective_heating + c.
  • Learns only from valid 5-minute transitions; uses a smoothed heating-demand proxy to approximate radiator lag.
  • After at least 200 transitions and samples with both heating states, runs an ON/OFF MPC search for the next 60–180 minutes (default 120) in 15-minute command blocks. Protects against rapid simulated toggling.
  • Uses room comfort weights and the existing Generic Thermostat's target and heat/off state. The simulated ON/OFF demand never operates hardware.
  • Persists model parameters using HA's .storage so HA restarts do not discard the trained data.

Entities (entity IDs may vary):

  • sensor.heating_mpc_status — learning/ready/paused status and diagnostics, including outside weather, active source, all valid alternative weather values, model coefficients, proposed 15-minute plan.
  • sensor.heating_mpc_weighted_temperature — own room-weighted average, informative only.
  • sensor.mpc_outdoor_temperature — selected external temp and alternatives.
  • Per-room predicted temperatures after 60 minutes.
  • binary_sensor.heating_mpc_proposed_heat — hypothetical heating demand (unavailable until ready).

Known limitations / safety

  • Do not connect the proposed binary sensor directly to the heating switch or build an automation from it. A production controller would need watchdog, manual override, safety handling, and an exclusive relay owner with Generic Thermostat fallback.
  • The other meteorological variables besides temperature are intentionally captured but not yet fitted into the thermal model. This allows source tests without falsely treating weak inputs as validated improvements. Later versions can test whether wind or solar proxy reduces held-out forecast error.
  • All rooms share one heating actuator. The model does not command individual radiators.
  • No weather forecast: assumes outdoor temperature remains constant during simulated horizon.
  • No Recorder/InfluxDB training backfill. It learns only from samples collected after installation.
  • The demand switch is not a burner-flame or real gas consumption measurement.
  • Full HAOS/UI runtime integration has not been tested; Python/model/unit/source tests are offline checks only.
  • Home Assistant Core APIs and config-flow selectors can change; take a backup before trying this experimental custom integration.

Offline tests

python -m unittest discover -s tests -v

v0.2.1: integration visibility and clean uninstall

  • Corrects the manifest classification from helper to service. Existing config entries should move from the Helpers listing to Settings → Devices & services → Integrations after replacing the files and restarting Home Assistant Core. No deletion/reconfiguration is needed to upgrade.
  • When the integration config entry is deleted from the Integrations page, Home Assistant removes its registered entities, and async_remove_entry removes the locally persisted learned-model data (.storage/heating_mpc.<entry_id>). The custom component source folder remains on disk until manually removed.
  • MPC behavior is otherwise unchanged and remains read-only / shadow-only.

Unreleased: v0.2.1 reliability audit

See AUDIT.md for findings, fixes, test evidence and remaining gaps. No active control was added; the manifest version has not been advanced.

  • Fix config-entry v1 migration, obsolete room forecast cleanup and coordinator cleanup after a raised platform setup error.
  • Validate saved models atomically and add an explicit payload schema version. Compatible legacy coefficients survive; readiness now requires at least 30 new accepted ON and 30 OFF samples per room when loading legacy models without per-room counters. The existing 200-total-sample requirement also applies.
  • Reject intervals containing relay changes or outside-provider changes. Accept only 270–330-second intervals and normalize small timing differences. This can slow learning; it never generates extra heating cycles.
  • Normalize thermostat targets to Celsius; reject invalid weights and optimizer parameters. Status can report invalid_weights or inputs_changed; neither publishes a proposal. Input changes during calculation discard the prediction.
  • Model diagnostics include each room's accepted total/ON/OFF sample counts. Predictions remain counterfactual: the proposed plan is not the actual Generic Thermostat's future command sequence.

Offline lifecycle tests use HA doubles. Actual HA/HAOS lifecycle validation and held-out prediction accuracy remain unfinished. Back up before trying these changes; follow the safe trial and rollback notes in AUDIT.md.

Unreleased: sensor freshness

Room and weather report-age limits are available during setup and in Options (5–1440 minutes). Defaults are 30 minutes for rooms and 120 minutes for weather; existing entries use these defaults until changed. Celsius/Fahrenheit handling, compatible learned models and entity IDs are unchanged.

Stale room readings or an absence of fresh outdoor temperature sources pause learning and predictions. Weather selection skips stale sources; optional weather outages do not block predictions. Recovery begins a new sampling interval, so no training spans an outage. Status attribute input_quality lists each room and each weather source by metric, with report age in seconds and a reason: valid, missing, unknown, unavailable, stale, invalid_timestamp, future_timestamp or invalid_value_or_unit.

Freshness uses HA last_reported, falling back to last_updated only on older HA versions without that field. It measures HA state reports, not the age of the original physical measurement: a provider republishing cached data can look fresh. Some integrations report only changed values; choose limits appropriate to their reporting behavior. The relay and thermostat are event-driven references and do not receive these numeric-sensor age limits. Sensor alignment and relay event history remain future work. These checks run on the existing five-minute poll.

After backing up and upgrading, check report ages in Status, adjust limits in Options to match your sensors, and verify fallback/recovery with an unavailable source. Generic Thermostat remains the sole controller. No HAOS trial was performed.

S
Description
A smarter predictive way to control your thermostat in Home Assistant
Readme
1 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 99.9%