Correction (8 Oct 2026) — supersedes
heat_loss_degrees0.0315 andheat_cop3.81 below. Free-cooling nights show the building time constant is ≈ 60 h, not 32 h (C ≈ 5.5 kWh/K, seedocs/capacity_learning.md); the winter daily balance had under-estimated C. Replay over 150 winter days (tools/predheat_replay.pyfunctions, all days):
Set Elec MAE Elec bias Room MAE @6 h @24 h current (156, 0.0194, gains 400, COP 3.68) 0.85 +0.24 0.66 2.53 earlier advice (94, 0.0315, 440, 3.81) 0.91 −0.27 0.78 1.10 94, 0.0171 (C 5.5), COP 3.81 1.12 −0.82 0.36 1.11 recommended: 94, 0.0171, 440, COP 3.2 0.82 +0.04 0.36 1.11 With the correct C the room forecast halves its 6 h error, but Predheat then under-predicts electricity (its structure lacks RT modulation and the circulation pump/standby inside the COP);
heat_cop3.2 is an empirical calibration of the energy level (lower gains or higherheat_min_powerworsened the room forecast without removing the bias). Recommendedpredheat:values:heat_loss_watts: 94 heat_loss_degrees: 0.0171 heat_gain_static: 440 heat_min_power: 680 heat_cop: 3.2(keep the
heat_pump_efficiencytable,flow_difference_target5 andhysteresis1.0 / 1.0).
Update (M1): the values below were validated by replaying Predheat over 150 winter days (
tools/predheat_replay.py, report indocs/predheat_replay_report.md). The recommended values are the "fitted" set in that report, which supersede the first-pass table below where they differ (heat_loss_degrees0.0315,heat_min_power680,heat_cop3.81 with a fullheat_pump_efficiencytable). Hold-out result versus current settings: daily heating-electricity error 0.98 → 0.84 kWh/day, bias +0.40 → −0.11 kWh/day, hourly room-temperature RMSE 1.90 → 1.16 K, 24 h room error 2.56 → 1.16 K.A further "calibrated" set fits room temperature better (RMSE 0.75 K) but pushes several parameters to their search limits and over-predicts electricity by ~0.5 kWh/day; since Predbat consumes the energy forecast it is not recommended. The remaining room-temperature error is structural: Predheat does not model the Daikin's RT modulation or the overnight deviation schedule.
hysteresis/hysteresis_offstay at 1.0. Theheating_energyfix below still applies.
volume_tempnote (verified in Predheat/Predbat source): Predheat readsvolume_tempwithget_arg("volume_temp", …)withoutdomain="predheat", and Predbat'sget_argthen looks only at the top level ofpred_bat:(or HA config), so avolume_temp:inside thepredheat:block is ignored. Per the Predheat docs the sensor must measure radiator water near the room thermostat, not at the heat pump, so the Daikin return sensor (R4T) is not a suitable substitute (earlier suggestion withdrawn). Use the living-room Zigbee radiator sensor, placed at the top level ofpred_bat:, once it is back online; until then Predheat falls back to its simulatedinput_number.predbat_next_volume_temp.
Based on the daily/hourly fits in docs/data_inventory.md and the current predheat: section of apps.yaml (shared 7 October 2026). Predheat semantics verified against apps/predbat/predheat.py (batpred main):
heat_loss_watts= UA (W/K);watt_per_degree = heat_loss_watts / heat_loss_degreesis the building heat capacity C (Wh/K).heat_energy/$externalis cumulative electrical energy (heat_power_out / (heat_cop · cop_adjust)), keyed every 10 min.- COP:
heat_cop × heat_pump_efficiency[outdoor °C] / max(table). - Heat output modulates between
heat_min_powerandheat_max_powerin proportion to(flow_temp − volume_temp) / flow_difference_target.
Suggestions only. Nothing has been changed in HA; apply manually and compare forecast error over the following weeks.
| Setting | Current | Fitted / observed | Suggested | Confidence | Effect of current value |
|---|---|---|---|---|---|
heat_loss_watts |
156 | UA 94 ± 3 W/K (daily balance, R² 0.90) | 95 | high | Heat demand over-predicted by ~65 % at design conditions |
heat_gain_static |
400 | 440 ± 34 W | 420 | medium | fine |
heat_loss_degrees |
0.0194 → C = 8.0 kWh/K | C ≈ 3.0 kWh/K (daily 3.0 ± 0.8; hourly 2.7–3.2) | 0.030 (→ C ≈ 3.2 kWh/K) | medium | Room responds ~2.5× too slowly in the forecast |
heat_output |
10630 | K·50^1.3 ≈ 10.2 kW (K ≈ 63, n ≈ 1.3–1.38) | keep 10630 | high | consistent with radiator data |
heat_volume |
121 | not identifiable from data | keep | – | – |
heat_max_power |
4000 | EDLA04E2V3, 4 kW class | keep | medium | – |
heat_min_power |
500 | min. modulated output ≈ 680 W (P5), median 900 W | 750 | medium | Under-predicts cycling in mild weather |
heat_cop + efficiency table |
3.68 with default table (≈ 2.5 at 0 °C, 2.95 at 5 °C, 3.35 at 10 °C) | measured daily COP 2.8 (≤ 3 °C), 3.0 (3–6), 3.3 (6–12), 4.0 (12–16) | heat_cop: 4.0 + table below |
medium (1 kWh counter resolution) | Slightly pessimistic in cold weather |
flow_difference_target |
5 | observed flow−return ΔT ≈ 1.9 K | 3 | low | Predheat-internal tuning parameter; check forecast shape |
hysteresis / hysteresis_off |
1.0 / 1.0 | Daikin room hysteresis 9-0C = 1.0 | keep | medium | – |
weather_compensation |
−23: 47, 10: 25 | observed LWT setpoint 29.1 (≤ 3 °C) … 25.2 (≥ 9 °C) | keep (matches); note RT modulation adds ±5 K | medium | – |
Suggested heat_pump_efficiency (outdoor °C → COP, normalised by its maximum; values are measured daily medians, smoothed):
heat_cop: 4.0
heat_pump_efficiency:
-10: 2.3
-5: 2.5
0: 2.75
3: 2.85
5: 3.0
8: 3.3
10: 3.3
12: 3.6
14: 4.0
20: 4.0| Setting | Current entity | Status | Suggestion |
|---|---|---|---|
external_temperature |
sensor.ecowitt_outdoor_temperature |
valid | keep |
internal_temperature |
sensor.bridge0_sensors_temperature_room |
valid | keep |
target_temperature |
sensor.bridge0_room_room_heating_setpoint |
valid | keep |
heating_energy |
sensor.ashp_daily_electricity |
valid, but includes DHW (today 0.94 kWh = 0.12 heating + 0.82 DHW) | sensor.ashp_heating_power_consumption_daily (heating only, same sensor already used as car_charging_energy filter) |
heating_active |
binary_sensor.bridge0_unknown_climate_active_q4 (as a list) |
verified 7 Oct: = space heating enabled, not demand; and a list is never converted to on/off, so it always reads as active | heating_active: binary_sensor.bridge0_mode_valve_zone_main — single value, no - |
volume_temp |
sensor.ashp_flow_temperature_living_room_temperature |
unavailable since 26 Sep (Zigbee sensor offline/battery); also ignored inside predheat: |
fix the sensor and move the key to the top level of pred_bat: (see note above) |
-
load_forecast: predheat.heat_energy$externalwithcar_charging_energy: sensor.ashp_heating_power_consumption_dailyremoves heating from historical load and adds the Predheat forecast: consistent, no double counting for space heating. DHW remains in the historical base load, which is acceptable while Predheat models space heating only. -
Heating switched off (summer): the automation disables Predheat,
predheat.heat_energydisappears and Predbat logsWarn: Unable to load the load forecast from predheat.heat_energyevery cycle (harmless: the source is skipped). Predbat only warns when the series is empty (fetch.py,load_forecast→minute_data), so point it at a template sensor that passes Predheat'sexternallist through while Predheat is enabled and otherwise publishes a flat zero series in the same format ([{last_updated, energy}], cumulative kWh,%Y-%m-%dT%H:%M:%S%z). It also ignores the stale forecast Predheat leaves behind right after it is disabled:# configuration.yaml template: - sensor: - name: "Heating load forecast" unique_id: heating_load_forecast unit_of_measurement: kWh state: > {{ states('predheat.heat_energy') | float(0) if is_state('switch.predbat_predheat_enable', 'on') else 0 }} attributes: external: > {% set ext = state_attr('predheat.heat_energy', 'external') %} {% if is_state('switch.predbat_predheat_enable', 'on') and ext %}{{ ext }} {% else %}{% set t0 = today_at('00:00') %} [{"last_updated": "{{ t0.strftime('%Y-%m-%dT%H:%M:%S%z') }}", "energy": 0}, {"last_updated": "{{ (t0 + timedelta(days=3)).strftime('%Y-%m-%dT%H:%M:%S%z') }}", "energy": 0}] {% endif %}
and in
apps.yaml:load_forecast: - sensor.heating_load_forecast$external. -
load_ml_enable: true: confirm that Predbat's ML load model applies the samecar_charging_energyfiltering; otherwise space heating is counted twice (ML history + Predheat).
Replay Predheat's simulation with current vs suggested values against this winter's measurements once live data exists (or on last winter's hourly LTS), and report daily-energy and room-temperature error before/after.
| Setting | Read as | List allowed? |
|---|---|---|
external_temperature, internal_temperature, target_temperature, heating_energy |
entity history (minute_data_entity) |
yes (single or list) |
days_previous, days_previous_weight |
list | yes (list expected) |
heating_active |
boolean (get_arg(..., False)) |
no — list is always truthy |
flow_temp |
float (sensor or number) | no (single value); ignored while weather_compensation is set |
volume_temp |
float, top level of pred_bat: only |
no |
weather |
entity id | no |
numeric settings (heat_loss_watts, …) |
float/int | no |