diff --git a/docs/RELEVE_ECS306.md b/docs/RELEVE_ECS306.md new file mode 100644 index 0000000..6c7a07b --- /dev/null +++ b/docs/RELEVE_ECS306.md @@ -0,0 +1,122 @@ +# Relevé banc — ECS-306 et commutations par relais + +Dépôt : `etm-powersync-energy-plugin-etm` · Banc : `192.168.1.75` (`nymea-dev-rpi`) +Installation émulée : `specs/spec_ecs.md` §4.0 (INST-100), cf. INST-104. + +> **Ce document est publié AVANT la mesure.** La section « Prédiction » est +> horodatée du **2026-08-09** et commitée avant tout profil lancé. Une +> reconstruction analytique publiée après coup ne vaut rien ; publiée avant, elle +> est falsifiable. Les résultats viendront s'ajouter en dessous, sans jamais +> réécrire la prédiction — si elle est fausse, elle reste, et c'est le +> renseignement utile. + +--- + +## 1. Dispositif + +Trois charges, un seul budget de surplus, cascade par rang ascendant. + +| Charge | Rang | Adaptateur | Paliers / états | Verrous | +|---|---|---|---|---| +| `chauffe-eau` | 1 | `relay-router` — Relay1/2/3 (500/1000/2000 W) | 0…3500 W, 8 valeurs | `minOnS`/`minOffS` = 60 s (300 s pour le volet 1, cf. §3) | +| PAC SG-Ready | 2 | `sg-ready` — Relay4/5, codé en dur | P3 = 1500 W, P4 = 3000 W | `minStateHoldS` = 300 s | +| `sonde-residu` | 3 | `relay-router` — Relay6, **1 relais, 100 W** | 0 / 100 W | `minOnS`/`minOffS` = 10 s | + +**La sonde est un instrument de mesure, pas une charge.** Aucune résistance n'est +câblée sur Relay6 : le relais claque, rien ne consomme. Ce qu'elle rend +observable est une **décision d'allocation** — le résidu que le waterfall laisse +à la charge suivante — et non une puissance. Son palier à 100 W est choisi très +au-dessous de l'écart attendu (500 W) pour que le basculement soit franc. + +Pilotage du surplus : `banc/cmd/manual {"grandeur":"pv","mode":true,"value":}` +sur le broker `192.168.1.131`, `modele.py:178`. `banc/cmd/pause` fige l'horloge du +modèle et rend le profil reproductible. + +--- + +## 2. Prédiction — 2026-08-09, avant mesure + +### Pourquoi la télémétrie ne discrimine pas + +Les Things sont des relais **GPIO** : leur ThingClass n'expose pas `currentPower`. +`RelayRouter::telemetry()` retombe donc sur le **nominal commandé** +(`relayrouter.cpp:113-114`), et `currentPowerW == palier commandé` en permanence. + +Conséquence : `budget_charge = budget + palier_courant`. Tant que le budget reste +positif, les deux versions choisissent le même palier et laissent le même résidu. +**La divergence n'apparaît qu'en import net**, budget signé négatif. + +### Volet 1 — point de fonctionnement discriminant + +Surplus 3600 W jusqu'à ce que le chauffe-eau atteigne 3500 W et arme `minOn`, +puis chute à **−300 W** maintenue. + +``` +budget_charge = −300 + 3500 = 3200 +``` + +| | Palier retenu | Résidu annoncé | PAC (rang 2) | Sonde (rang 3) | +|---|---|---|---|---| +| **`+etm2`** | 3000 (plus haut ≤ 3200) | **+200 W** | état 2 (200 < P3) | **ALLUMÉE** (100 ≤ 200) | +| **`+etm3`** | 3500 (forcé par `lockMinPowerW`) | **−300 W** | état 2 | **ÉTEINTE** (100 > −300) | + +Sous `+etm2`, le routeur écrête malgré tout à 3500 W (verrou interne) : **500 W +sont consommés de plus que comptés**, et ce sont ces 500 W que la sonde révèle. + +**Prédiction falsifiable : la sonde s'allume sous `+etm2`, reste éteinte sous +`+etm3`. Si elle s'allume sous `+etm3`, le raisonnement est faux.** + +Prédiction secondaire : **la PAC ne changera pas d'état** entre les deux +versions — 200 W comme −300 W sont tous deux sous P3 = 1500 W. Le volet 1 ne +montrera donc rien sur la PAC ; c'est la sonde qui porte la démonstration. Sans +elle, ce relevé aurait conclu « aucun effet observable » à tort. + +### Volet 2 — commutations par relais + +Balayage complet 0 → 3500 W puis retour, plateaux ≥ 90 s (`minOnS` = 60 s). + +Comptage attendu sur un aller simple : + +| Relais | Commutations | Part | +|---|---|---| +| R500 | **7** | bit de poids faible | +| R1000 | **3** | | +| R2000 | **1** | | +| **total** | **11** | | + +La transition **1500 → 2000 W** (`{R500,R1000}` → `{R2000}`) bascule **les trois +relais**, soit **3 des 11** commutations à elle seule. C'est la seule du câblage +dans ce cas. + +**Piège prédit — le cliquet.** `currentPowerW` valant le nominal commandé, le +budget rendu à la charge inclut toujours son propre palier : un profil qui ne +fait que **décroître en surplus positif** ne fera jamais redescendre le palier. +Il faut des plateaux à **surplus négatif** pour provoquer la descente, sinon le +chauffe-eau reste à 3500 W du début à la fin et le relevé est vide. + +--- + +## 3. Protocole + +Deux campagnes **séparées**, jamais fusionnées : si un résultat surprend, il faut +pouvoir dire lequel des deux réglages en est la cause. + +**Volet 1** — `minOnS` du chauffe-eau porté à **300 s** le temps de l'essai, pour +élargir la fenêtre d'observation. Écart de réglage assumé et déclaré ; remis à +60 s après. + +**Volet 2** — `minOnS` à 60 s, plateaux ≥ 90 s, avec plateaux à surplus négatif. + +**Ordre d'exécution** : `+etm3` étant déjà installé, mesurer l'**après** d'abord, +puis descendre en `+etm2`, refaire le même profil, puis remonter en `+etm3`. + +**Vérification obligatoire au retour en `+etm2`** : relire paliers et rangs par +`NymeaEnergy.GetLoadConfig` **avant** de lancer le profil. La configuration a été +écrite par `+etm3` ; si `+etm2` la rejetait — silencieusement ou non — on +mesurerait deux dispositifs différents sans le voir. + +--- + +## 4. Résultats + +*(à compléter après mesure — ne pas modifier les sections ci-dessus)*