Model windows, ventilation, wind exposure and recovery
Opening a window adds heat exchange that the envelope model mistook for
poor insulation or a constant cooling bias.
windows.py adds windows as config subentries ("Add window"): a contact
sensor (optionally inverted; unknown/unavailable stays unknown, never
"closed"), its zone, the direction its outside faces (default 345°,
editable) and an opening factor. Each poll computes the share of the
interval each window was open (one change located by its timestamp, a
round trip is unknown), the wind exposure with proper circular angles
(meteorological "from" direction vs the window's facing) and a recovery
weight after closing that decays towards 0, pulling the air back
towards its pre-ventilation temperature. A bounded event log records
opening/closing, duration, temperatures before/lowest/at close/30 min
after, weather and other open windows.
While a zone's window is open, unknown or recovering, the base and
extended models skip it; a separate ventilation learner fits the
closed-window model's residual with natural exchange, wind speed, a
directional term bounded by the wind term (a leeward window still
ventilates), recovery, and optional gust excess and cross-ventilation
terms. Forecasts assume an open window closes after a configurable time
(default 15 min), then recovers. New poll outcome "ventilation".
Weather gains optional wind direction (degrees, 360 -> 0) and wind gust
sources with the same priorities and fallback; knots and ft/s accepted.
On a synthetic week with ventilation events every four hours and a
daily outdoor swing, the configured zone keeps loss/heat/bias close to
the truth and recovers the combined natural+wind effect within 15 %,
recovery within 15 % and direction within 30 %. The same data without
the window configured produces a -0.013 °C/5 min cooling bias and an
11 % inflated boiler effect.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
00e70c612b
commit
ed8f9fe2e2
13 files changed
+1157
-39
No files matched your search
@@ -23,7 +23,9 @@
|
||||
"data": {
|
||||
"outside_temperature_sources": "Outdoor temperature sources (ordered: preferred first)",
|
||||
"outside_wind_sources": "Wind speed sources (optional)",
|
||||
"outside_clouds_sources": "Cloud coverage sources (optional)"
|
||||
"outside_clouds_sources": "Cloud coverage sources (optional)",
|
||||
"outside_wind_direction_sources": "Wind direction sources (optional; degrees the wind comes from)",
|
||||
"outside_wind_gust_sources": "Wind gust sources (optional)"
|
||||
}
|
||||
},
|
||||
"weather_extra": {
|
||||
@@ -68,11 +70,21 @@
|
||||
"room_max_age_minutes": "Maximum room sensor report age (minutes)",
|
||||
"weather_max_age_minutes": "Maximum weather sensor report age (minutes)",
|
||||
"room_stale_use_last_value": "Keep using the last value of a room sensor that stopped reporting",
|
||||
"internal_heat_half_life_minutes": "Extra electrical heat: forecast half-life (minutes)"
|
||||
"internal_heat_half_life_minutes": "Extra electrical heat: forecast half-life (minutes)",
|
||||
"window_open_minutes": "Open window: assumed remaining open time (minutes)",
|
||||
"recovery_minutes": "Recovery after closing a window (minutes)",
|
||||
"ventilation_wind": "Ventilation: use wind speed and direction",
|
||||
"ventilation_gust": "Ventilation: use wind gusts",
|
||||
"ventilation_cross": "Ventilation: cross-ventilation between zones"
|
||||
},
|
||||
"data_description": {
|
||||
"room_stale_use_last_value": "Off: a room sensor older than its report-age limit is left out and the other rooms are re-weighted. On: its last value is still used, for up to 24 hours without a report; for sensors that report only when the value changes. Unavailable or invalid room sensors are always left out. Nothing pauses unless no room is usable.",
|
||||
"internal_heat_half_life_minutes": "Forecasts assume heat above the baseline fades with this half-life, for example when a gaming session ends. 0 assumes it stops now."
|
||||
"internal_heat_half_life_minutes": "Forecasts assume heat above the baseline fades with this half-life, for example when a gaming session ends. 0 assumes it stops now.",
|
||||
"window_open_minutes": "Forecasts assume an open window closes after this many more minutes, then the room recovers.",
|
||||
"recovery_minutes": "Time constant of the air warming back towards the walls' temperature.",
|
||||
"ventilation_wind": "Needs wind sources; direction also needs wind direction sources.",
|
||||
"ventilation_gust": "Adds a term for gusts above the mean wind. Keep it only if Forecast Error improves.",
|
||||
"ventilation_cross": "Adds a term for windows open in several zones at once. Needs windows in two or more zones."
|
||||
}
|
||||
},
|
||||
"weather": {
|
||||
@@ -81,7 +93,9 @@
|
||||
"data": {
|
||||
"outside_temperature_sources": "Outdoor temperature sources (ordered: preferred first)",
|
||||
"outside_wind_sources": "Wind speed sources (optional)",
|
||||
"outside_clouds_sources": "Cloud coverage sources (optional)"
|
||||
"outside_clouds_sources": "Cloud coverage sources (optional)",
|
||||
"outside_wind_direction_sources": "Wind direction sources (optional; degrees the wind comes from)",
|
||||
"outside_wind_gust_sources": "Wind gust sources (optional)"
|
||||
}
|
||||
},
|
||||
"weather_extra": {
|
||||
@@ -109,6 +123,7 @@
|
||||
"first_sample": "First sample",
|
||||
"sensors_changed": "Zone sensors changed",
|
||||
"learned": "Learned",
|
||||
"ventilation": "Window open or recovering",
|
||||
"partly_rejected": "Partly rejected (outlier)",
|
||||
"interval_out_of_range": "Irregular interval",
|
||||
"relay_changed": "Relay switched",
|
||||
@@ -236,6 +251,60 @@
|
||||
"reconfigure_successful": "The heat source was updated.",
|
||||
"no_zones": "Add a zone first."
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"entry_type": "Window",
|
||||
"initiate_flow": {
|
||||
"user": "Add window",
|
||||
"reconfigure": "Edit window"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Window",
|
||||
"description": "A window contact sensor. Open-window periods are kept out of the zone's normal heat-loss learning and modeled as ventilation instead. Unknown or unavailable states count as unknown, never as closed.",
|
||||
"data": {
|
||||
"name": "Name",
|
||||
"sensor": "Contact sensor",
|
||||
"zone": "Zone",
|
||||
"inverted": "Sensor reports on when closed",
|
||||
"azimuth": "Facing direction (°)",
|
||||
"opening_factor": "Opening factor",
|
||||
"enabled": "Enabled"
|
||||
},
|
||||
"data_description": {
|
||||
"inverted": "Turn on for sensors whose polarity is the reverse of a standard window sensor.",
|
||||
"azimuth": "Direction the outside of the window faces, clockwise from north (0 = N, 90 = E, 180 = S, 270 = W). Used with the wind direction.",
|
||||
"opening_factor": "Relative ventilation when open: 1.0 for a normal window, lower for tilted, higher for a large or double window."
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"title": "Window",
|
||||
"description": "A window contact sensor. Open-window periods are kept out of the zone's normal heat-loss learning and modeled as ventilation instead. Unknown or unavailable states count as unknown, never as closed.",
|
||||
"data": {
|
||||
"name": "Name",
|
||||
"sensor": "Contact sensor",
|
||||
"zone": "Zone",
|
||||
"inverted": "Sensor reports on when closed",
|
||||
"azimuth": "Facing direction (°)",
|
||||
"opening_factor": "Opening factor",
|
||||
"enabled": "Enabled"
|
||||
},
|
||||
"data_description": {
|
||||
"inverted": "Turn on for sensors whose polarity is the reverse of a standard window sensor.",
|
||||
"azimuth": "Direction the outside of the window faces, clockwise from north (0 = N, 90 = E, 180 = S, 270 = W). Used with the wind direction.",
|
||||
"opening_factor": "Relative ventilation when open: 1.0 for a normal window, lower for tilted, higher for a large or double window."
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"window_name_required": "Enter a name.",
|
||||
"sensor_in_other_window": "This sensor is already used by another window.",
|
||||
"too_many_windows": "At most 24 windows are supported."
|
||||
},
|
||||
"abort": {
|
||||
"reconfigure_successful": "The window was updated.",
|
||||
"no_zones": "Add a zone first."
|
||||
}
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
|
||||
Reference in new issue
Block a user