Skip to content

Commit 07fa7af

Browse files
committed
Release 1.8.0
1 parent ea80193 commit 07fa7af

23 files changed

Lines changed: 2623 additions & 532 deletions

.homeychangelog.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"1.8.0": {
3+
"en": "Backported the adaptive control and building model improvements from the sister Modbus project. Building model learning is now more resilient with sample gating for non-heating and defrost states, per-sample persistence, stronger state validation, covariance safeguards, and excitation diagnostics. Adaptive control now uses a fixed comfort anchor, improved accumulator settlement, additive wind correction, nullable outdoor-temperature handling, and expanded unit/simulation tests.",
4+
"nl": "De verbeteringen voor adaptieve regeling en gebouwmodel uit het zuster Modbus-project zijn overgenomen. Het gebouwmodel leert nu robuuster met sample-gating voor niet-verwarmen en ontdooien, persistentie per geaccepteerde sample, strengere state-validatie, covariance-bescherming en excitation-diagnostiek. De adaptieve regeling gebruikt nu een vast comfort-anker, betere accumulator-settlement, additieve windcorrectie, expliciete afhandeling van ontbrekende buitentemperatuur en uitgebreide unit-/simulatietests."
5+
},
26
"1.7.2": {
37
"en": "Improved Modbus connection resilience with TCP keep-alive and by clearing the connect timeout after a successful connection. The dashboard now calculates poll age using server time, and the ambient temperature capability always shows the direct Aurora III Modbus sensor value while external ambient data remains available separately for COP and adaptive control.",
48
"nl": "Verbeterde Modbus-verbindingsstabiliteit met TCP keep-alive en het wissen van de connect-timeout na een succesvolle verbinding. Het dashboard berekent de poll-leeftijd nu met servertijd, en de buitentemperatuurcapability toont altijd de directe Aurora III Modbus-sensorwaarde terwijl externe buitentemperatuur apart beschikbaar blijft voor COP en adaptieve regeling."

.homeycompose/app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "org.hhi.adlar3-heatpump-modbus",
3-
"version": "1.7.2",
3+
"version": "1.8.0",
44
"compatibility": ">=12.3.0",
55
"sdk": 3,
66
"platforms": ["local"],

app.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"_comment": "This file is generated. Please edit .homeycompose/app.json instead.",
33
"id": "org.hhi.adlar3-heatpump-modbus",
4-
"version": "1.7.2",
4+
"version": "1.8.0",
55
"compatibility": ">=12.3.0",
66
"sdk": 3,
77
"platforms": [
@@ -6478,12 +6478,12 @@
64786478
"fr": "Contrôleur PI: Gain Proportionnel (Kp)"
64796479
},
64806480
"hint": {
6481-
"en": "⚠️ Advanced: How aggressively the system responds to temperature errors. Higher = faster response, risk of overshooting. Only adjust if you understand PI control. Default: 3.0",
6482-
"nl": "⚠️ Geavanceerd: Hoe agressief het systeem reageert op temperatuur afwijkingen. Hoger = snellere reactie, risico op overshoot. Pas alleen aan als je PI regeling begrijpt. Standaard: 3.0",
6483-
"de": "⚠️ Erweitert: Wie aggressiv das System auf Temperaturfehler reagiert. Höher = schnellere Reaktion, Überschwingungsrisiko. Nur anpassen, wenn Sie PI-Regelung verstehen. Standard: 3.0",
6484-
"fr": "⚠️ Avancé: L'agressivité de réponse du système aux erreurs de température. Plus élevé = réponse plus rapide, risque de dépassement. N'ajuster que si vous comprenez le contrôle PI. Défaut: 3.0"
6481+
"en": "⚠️ Advanced: How aggressively the system responds to temperature errors. Higher = faster response, risk of overshooting. Only adjust if you understand PI control. Default: 5.0",
6482+
"nl": "⚠️ Geavanceerd: Hoe agressief het systeem reageert op temperatuur afwijkingen. Hoger = snellere reactie, risico op overshoot. Pas alleen aan als je PI regeling begrijpt. Standaard: 5.0",
6483+
"de": "⚠️ Erweitert: Wie aggressiv das System auf Temperaturfehler reagiert. Höher = schnellere Reaktion, Überschwingungsrisiko. Nur anpassen, wenn Sie PI-Regelung verstehen. Standard: 5.0",
6484+
"fr": "⚠️ Avancé: L'agressivité de réponse du système aux erreurs de température. Plus élevé = réponse plus rapide, risque de dépassement. N'ajuster que si vous comprenez le contrôle PI. Défaut: 5.0"
64856485
},
6486-
"value": 3,
6486+
"value": 5,
64876487
"attr": {
64886488
"min": 0.5,
64896489
"max": 10,
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# ADR-061 - Building model persistence over software reset and Homey app update
2+
3+
**Project:** org.hhi.adlar3-heatpump-modbus
4+
**Status:** voorgesteld
5+
**Datum:** 2026-06-11
6+
**Gerelateerd:** ADR-037 store-persistentie, ADR-056 building model hardening, ADR-057 learner safeguards, ADR-060 adaptive harmonisatie
7+
**Codegebied:** `lib/services/building-model-service.ts`, `lib/services/adaptive-control-service.ts`, `lib/services/service-coordinator.ts`, `drivers/intelligent-heatpump-modbus/device.ts`
8+
9+
## Context
10+
11+
Het gebouwmodel leert thermische parameters van de woning via `BuildingModelLearner`:
12+
13+
- `C`: thermische massa
14+
- `UA`: warmteverlies
15+
- `g`: zonnewinst
16+
- `P_int`: interne warmtelast
17+
- `sampleCount`, `theta`, `P`, `lastMeasurement` en excitation counters als interne RLS-state
18+
19+
Deze state is `engine-state` en hoort persistent te zijn over:
20+
21+
- software reset van de Homey app
22+
- Homey reboot
23+
- app update/install
24+
- coordinator restart door gewijzigde Modbus/poll-settings
25+
26+
De user-facing instellingen voor het gebouwmodel zijn Homey device settings:
27+
28+
- `building_model_enabled`
29+
- `building_model_forgetting_factor`
30+
- `building_profile`
31+
- `enable_dynamic_pint`
32+
- `reset_building_model`
33+
34+
Deze settings horen door Homey zelf persistent beheerd te worden. De geleerde modelstate hoort door de app in device store te worden beheerd onder `building_model_state`.
35+
36+
## Vraagstelling
37+
38+
De vraag is of de building modeler na software reset, Homey reboot, app update/install of coordinator restart zijn configuratie en geleerde state behoudt, en via welke persistentielaag dat gebeurt.
39+
40+
Daarbij moeten twee soorten data strikt uit elkaar worden gehouden:
41+
42+
- **Configuratie/settings**: Homey device settings uit `driver.settings.compose.json`, gelezen via `device.getSetting()`.
43+
- **Geleerde modelstate**: RLS-engine-state van `BuildingModelLearner`, opgeslagen in device store onder `building_model_state`.
44+
45+
## Analyse
46+
47+
Bij code-inspectie zijn twee concrete risico's zichtbaar voor de geleerde samples/state:
48+
49+
1. `BuildingModelService.collectAndLearn()` persist `building_model_state` alleen elke 10 geaccepteerde samples.
50+
- Bij een restart/update vóór sample 10 is er nog geen state opgeslagen.
51+
- Na sample 10 kan nog steeds maximaal 9 samples, dus maximaal 45 minuten bij 5-minuten interval, verloren gaan.
52+
53+
2. `ServiceCoordinator.destroy()` roept `this.adaptiveControl.destroy()` aan zonder `await`.
54+
- `AdaptiveControlService.destroy()` is async en wacht intern op `this.buildingModel.destroy()`.
55+
- `BuildingModelService.destroy()` doet de finale persist van `building_model_state`.
56+
- Zonder `await` kan app teardown doorgaan terwijl de finale persist nog niet afgerond is.
57+
58+
Voor de settings zelf is in de huidige code geen app-eigen persistencepad nodig of aanwezig: Homey device settings zijn de authoritative source. De app leest deze waarden op bij service-constructie, reset en settings-wijzigingen. Zolang de setting-id's gelijk blijven en het device niet opnieuw gepaired wordt, horen deze settings door Homey bewaard te blijven over reboot en app update.
59+
60+
## Besluit
61+
62+
We behandelen building model persistence als een expliciet lifecycle-contract:
63+
64+
1. **Elke geaccepteerde learning sample wordt direct persistent gemaakt.**
65+
- `learner.addMeasurement()` succesvol afgerond betekent: `building_model_state` moet naar device store.
66+
- UI-capabilities en diagnostics blijven rate-limited, bijvoorbeeld elke 10 samples.
67+
- Rationale: een 5-minuten sample is klein; betrouwbaarheid is belangrijker dan micro-optimalisatie van store writes.
68+
69+
2. **Shutdown moet alle async persistence afwachten.**
70+
- `ServiceCoordinator.destroy()` moet `await this.adaptiveControl.destroy()`.
71+
- `AdaptiveControlService.destroy()` blijft verantwoordelijk voor het awaiten van `BuildingModelService.destroy()`.
72+
- Destroy-volgorde moet geen subservice vernietigen voordat diens persist klaar is.
73+
74+
3. **Restore logging moet aantonen wat er is hersteld.**
75+
- Bij `BuildingModelService.initialize()` loggen:
76+
- store-key aanwezig/afwezig
77+
- sample count
78+
- confidence
79+
- modelparameters op hoofdlijnen
80+
- restore reject met validatiefout indien van toepassing
81+
- Dit maakt het verschil zichtbaar tussen:
82+
- geen state opgeslagen
83+
- state aanwezig maar corrupt/rejected
84+
- state correct hersteld
85+
86+
4. **Settings blijven Homey-managed.**
87+
- `building_model_*` settings blijven Homey settings, niet dupliceren in store.
88+
- Deze ADR wijzigt geen settingsopslag en introduceert geen settings-restore vanuit store.
89+
- `reset_building_model` blijft een expliciete destructive action en mag niet impliciet door restart/update worden getriggerd.
90+
91+
## Openstaande punten
92+
93+
### 1. Persist-frequentie
94+
95+
**Huidig gedrag:** persist alleen bij `sampleCount % 10 === 0` en bij destroy.
96+
**Risico:** alle samples sinds laatste checkpoint kwijt bij harde restart/update.
97+
98+
**Behandeling:**
99+
100+
- Na elke succesvolle `addMeasurement()` direct `await persistState()`.
101+
- `updateModelCapabilities()` en `updateDiagnosticsCapability()` blijven op 10-sample cadence.
102+
- Bij persist-fout: loggen, maar learning niet blokkeren.
103+
104+
**Acceptatiecriterium:**
105+
106+
- Na 1 geaccepteerde sample staat `building_model_state.sampleCount >= 1` in store.
107+
- Na 9 samples en een gesimuleerde restart wordt sampleCount 9 hersteld, niet 0.
108+
109+
### 2. Async destroy-chain
110+
111+
**Huidig gedrag:** `ServiceCoordinator.destroy()` roept `this.adaptiveControl.destroy()` zonder `await`.
112+
**Risico:** finale building-model persist wordt niet gegarandeerd afgerond.
113+
114+
**Behandeling:**
115+
116+
- Wijzig naar `await this.adaptiveControl.destroy()`.
117+
- Houd bestaande expliciete optimizer-state save intact.
118+
- Zorg dat errors in destroy worden gelogd zonder verdere cleanup volledig te blokkeren.
119+
120+
**Acceptatiecriterium:**
121+
122+
- Een test met mock-device-store toont dat `building_model_state` geschreven is voordat `ServiceCoordinator.destroy()` resolved.
123+
124+
### 3. Restore-validatie
125+
126+
**Huidig gedrag:** `BuildingModelLearner.restoreState()` reject corrupte theta/P-state defensief.
127+
**Risico:** correcte reject lijkt voor gebruiker op "alles kwijt" als de reden niet zichtbaar is.
128+
129+
**Behandeling:**
130+
131+
- Restorepad logt expliciet of state:
132+
- afwezig is
133+
- geldig hersteld is
134+
- rejected is, inclusief validatiefout
135+
- Diagnostics krijgen zo nodig een `lastRestoreStatus` of vergelijkbaar veld, als gewone logging onvoldoende blijkt.
136+
137+
**Acceptatiecriterium:**
138+
139+
- Bij corrupte persisted state is in logs/diagnostics zichtbaar waarom het model op defaults start.
140+
141+
### 4. Homey settings versus learned state
142+
143+
**Huidig gedrag:** settings staan in `driver.settings.compose.json`; learned state staat in store.
144+
**Risico:** verwarring tussen twee persistentielagen kan het probleem verkeerd laten behandelen.
145+
146+
**Behandeling:**
147+
148+
- Bij startup restore diagnostics mogen de actuele Homey settingswaarden mee gelogd worden voor context:
149+
- `building_model_enabled`
150+
- `building_model_forgetting_factor`
151+
- `building_profile`
152+
- `enable_dynamic_pint`
153+
- Niet automatisch settings naar store kopiëren.
154+
- Geen settings-migratie of settings-herstel toevoegen zolang setting-id's stabiel blijven en er geen reproduceerbaar Homey settingsverlies is vastgesteld.
155+
156+
**Acceptatiecriterium:**
157+
158+
- Na update leest de app de Homey settings via dezelfde setting-id's.
159+
- `building_model_state` wordt afzonderlijk hersteld uit device store.
160+
- Startup diagnostics maken zichtbaar welke settingswaarden zijn gelezen en welke learned state is hersteld.
161+
162+
### 5. Reset-toggle veiligheid
163+
164+
**Huidig gedrag:** `reset_building_model=true` triggert `BuildingModelService.reset()` en zet daarna de toggle terug naar false via deferred `setSettings()`.
165+
**Risico:** als de deferred reset van de toggle niet lukt, kan een latere settings-cyclus opnieuw resetten.
166+
167+
**Behandeling:**
168+
169+
- Log altijd of de toggle succesvol teruggezet is.
170+
- Overweeg een store-based one-shot guard met timestamp/request-id als herhaalde resets in praktijk voorkomen.
171+
- Geen wijziging tenzij reproduceerbaar, omdat extra guards complexiteit toevoegen.
172+
173+
**Acceptatiecriterium:**
174+
175+
- Een mislukte toggle-reset is zichtbaar in logs.
176+
- Er is geen impliciete reset bij normale app update zonder expliciete user action.
177+
178+
## Voorgestelde implementatievolgorde
179+
180+
1. Maak `BuildingModelService` crash-safe voor samples:
181+
- persist na elke geaccepteerde sample
182+
- behoud 10-sample cadence voor capabilities/diagnostics
183+
184+
2. Maak shutdown await-safe:
185+
- `await this.adaptiveControl.destroy()` in `ServiceCoordinator.destroy()`
186+
187+
3. Verbeter restore-observability:
188+
- log sample count/confidence bij restore
189+
- log afwezig/rejected/geldig expliciet
190+
191+
4. Voeg tests toe:
192+
- unit/mock-test voor persist na sample
193+
- unit/mock-test voor awaited destroy-chain
194+
- simulatie of service-test voor restart na minder dan 10 samples
195+
196+
5. Pas `docs/Dev support/store-persistentie-matrix.md` aan:
197+
- markeer `building_model_state` pas weer correct wanneer de fix en tests aanwezig zijn
198+
- noteer persist-frequentie als "per accepted sample + final destroy"
199+
200+
## Teststrategie
201+
202+
Minimale testdekking voor deze ADR:
203+
204+
1. **Service persistence test**
205+
- Mock `Homey.Device` met `getStoreValue` en `setStoreValue`.
206+
- Injecteer geldige indoor/outdoor/power/COP data.
207+
- Forceer een `collectAndLearn()`-cyclus of exposeer een testbare helper.
208+
- Assert: `setStoreValue('building_model_state', ...)` is aangeroepen na sample 1.
209+
210+
2. **Restart restore test**
211+
- Maak learner/service, voeg 1-9 samples toe, persist store.
212+
- Maak nieuwe service met dezelfde mock-store.
213+
- Assert: restored `sampleCount` is gelijk aan opgeslagen count.
214+
215+
3. **Destroy-chain test**
216+
- Mock `AdaptiveControlService.destroy()` als async promise.
217+
- Assert: `ServiceCoordinator.destroy()` resolved pas na die promise.
218+
219+
4. **Manual update checklist**
220+
- Voor release: app installeren over bestaande versie met actief building model.
221+
- Voor update: noteer `building_model_state.sampleCount` uit restore diagnostics.
222+
- Na update: sample count en settings blijven behouden.
223+
224+
## Consequenties
225+
226+
Positief:
227+
228+
- Geen verlies van vroege learning na update/restart.
229+
- Hooguit 0 samples verlies na nette shutdown; bij harde stroomuitval maximaal de sample die op dat moment nog niet geschreven was.
230+
- Betere diagnose wanneer state ontbreekt of rejected wordt.
231+
232+
Negatief:
233+
234+
- Meer store writes: maximaal een write per 5 minuten per device bij actief leren.
235+
- Iets meer logging bij startup/restore.
236+
237+
Acceptabel, omdat learning-state schaars en waardevol is en de write-frequentie laag blijft.
238+
239+
## Niet doen
240+
241+
- Learned state niet naar Homey settings kopiëren.
242+
- Settings niet dupliceren in store zonder bewijs dat Homey settings zelf niet persistent zijn.
243+
- `reset_building_model` niet automatisch activeren bij corrupt state; corrupt state moet zichtbaar worden en alleen expliciet resetten.
244+
- Geen directe edit aan gegenereerde `app.json`; settings blijven via compose.

0 commit comments

Comments
 (0)