129 lines
9.9 KiB
Markdown
129 lines
9.9 KiB
Markdown
# 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
|
||
|
||
```bash
|
||
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](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.
|