+etm24 posé sur `.75`, condition du §3.1 rejouée à l'identique : wallbox en Eco, voiture assignée, pluggedIn false. La borne sort du contexte, le journal le dit, et le budget va entier aux deux charges configurées. Sous +etm23 la même condition lui donnait 4 853 W. Une conséquence est notée parce qu'elle n'est pas évidente : « hors arbitrage » ne veut pas dire « non commandée ». Sortie du waterfall, la borne retombe sur le proxy, qui la commande à son courant minimum. L'invariant du lot tient — un seul commandeur — et aucun watt n'est retiré de la cascade. Mais les trois exclusions ne finissent pas au même endroit, et ça se saura le jour où le §10 fera du proxy autre chose qu'un repli. Banc rendu à son état d'origine, voiture de test retirée, wallbox éteinte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
229 lines
12 KiB
Markdown
229 lines
12 KiB
Markdown
# Relevé machine — 3g-2 sur le banc `.75`, 2026-08-27
|
||
|
||
**Paquets** : `1.15.2+etm23` puis `1.15.2+etm24` (correctif du §3.1), construits arm64 dans
|
||
`build-cross-arm64`, posés par
|
||
`etm-powersync-deploy/deploy.sh` (rollback : `/var/lib/etm-deploy/archive/`).
|
||
**Compteur** : Fronius SunSpec. **Bornes** : Terra AC réelle (absente du réseau) + wallbox simulée.
|
||
|
||
> **Méthode.** Ce qui suit distingue ce qui a été **observé sur machine**, ce qui vient d'un
|
||
> **test unitaire**, et ce qui n'est qu'une **lecture de code** (`docs/RELEVE_LOTD.md`).
|
||
> Tout ce qui est numéroté ci-dessous est **machine**, journal ou RPC à l'appui.
|
||
|
||
---
|
||
|
||
## 1. La Terra AC — toujours absente, et c'est physique
|
||
|
||
| Vérification | Résultat |
|
||
|---|---|
|
||
| `ping` depuis le banc `.75`, même segment L2 | `Destination Host Unreachable` |
|
||
| Table ARP du banc pour `.132` | **`INCOMPLETE`** — aucune réponse ARP |
|
||
| TCP 502 depuis le banc | `No route to host` |
|
||
| Balayage complet de `192.168.1.0/24` depuis le banc | rien en `.132` ; aucun autre Modbus TCP inconnu |
|
||
| `Integrations.GetThings` | `Terra AC Charger (TCP)` en **`ThingSetupStatusInProgress`**, en boucle |
|
||
|
||
Une machine qui ne répond pas à l'ARP est hors du réseau. **LM-1204-b garde sa moitié
|
||
matérielle non franchie** — il faut deux bornes RÉELLES, et il n'y en a qu'une.
|
||
|
||
---
|
||
|
||
## 2. Ce qui est FRANCHI
|
||
|
||
### 2.1 Une charge, un commandeur — le critère central du lot
|
||
|
||
**Avant** (`+etm22`, même banc, wallbox en Eco avec voiture assignée) : la borne était arbitrée,
|
||
et `adjustEvChargers()` reprenait la main derrière.
|
||
|
||
**Après** (`+etm23`), chaque cycle porte, dans cet ordre :
|
||
|
||
```
|
||
[Arbitre] "{09e520fd…}" → "Surplus PV 2350 W — Simulated wallbox consigne 2350 W" | activé: true | phases: 1
|
||
Executing action Simulated wallbox to power: ON, Carging current: 10A, Switch phases to: 1, Issuer: Surplus
|
||
---------------- Adjusting chargers ---------------
|
||
"Simulated wallbox" is commanded by the ETM waterfall this cycle. Not re-deciding here.
|
||
```
|
||
|
||
Et dans `planSurplusCharging`, un cycle plus haut :
|
||
`"Simulated wallbox" surplus is planned by the ETM waterfall. Skipping proxy planning.`
|
||
|
||
**Comptage sur la fenêtre d'observation** : 9 lignes `Executing action Simulated wallbox`, **9
|
||
avant** `Adjusting chargers` (donc émises par le dispatch de l'arbitre), **0 après** (donc aucune
|
||
dérivée par le proxy). 6 cycles sur 6 portent la ligne de saut.
|
||
|
||
**Le doublet a disparu, et quelqu'un commande.** C'est le critère du lot, et il est franchi.
|
||
|
||
### 2.2 Le plancher publié est l'exigence réelle
|
||
|
||
Sur la MÊME borne, dans la même journée :
|
||
|
||
| | motif publié |
|
||
|---|---|
|
||
| `+etm22` | `BELOW_MIN_POWER {budgetW: 84, minPowerW: **2070**}` |
|
||
| `+etm23` | `BELOW_MIN_POWER {budgetW: 395, minPowerW: **4140**}` |
|
||
|
||
2 070 W était `6 A × 0,5 × 230 × 3` — le plancher multiplié par la tolérance d'acquisition.
|
||
4 140 W est `6 A × 230 × 3`, ce que la borne exige réellement. Le défaut du relevé 3g-1 §3.4 est
|
||
fermé, et le chiffre le montre.
|
||
|
||
**Et le plancher suit le nombre de phases VISÉ**, cycle à cycle : au cycle suivant, la référence
|
||
de bascule ayant changé, le journal publie
|
||
`BELOW_MIN_POWER {budgetW: 385, minPowerW: **1380**}` — soit `6 A × 230 × 1`. C'est le piège le
|
||
plus silencieux de `DESIGN_3g` §3.3, observé en train de fonctionner.
|
||
|
||
### 2.3 L'entrée `evcharger` auto-provisionnée
|
||
|
||
Au premier cycle après la bascule, une ligne par borne, **à la création seulement** :
|
||
|
||
```
|
||
[EnergyArbitrator] Borne "Simulated wallbox" ajoutée à la configuration des charges
|
||
(rang 1 , domaine ev) — entrée créée automatiquement, modifiable par SetLoadConfig.
|
||
[EnergyArbitrator] Borne "Terra AC Charger (TCP)" ajoutée à la configuration des charges (…)
|
||
```
|
||
|
||
`GetLoadConfig` passe de 2 à 4 entrées. Les deux entrées de borne portent
|
||
`adapter: evcharger`, `mode: dynamic`, `domain: ev`, et **aucune charge utile** — vérifié champ
|
||
par champ (`relays`, `sgReady`, `powerLevels`, `maxPowerW`, `minPowerW`, `minOnS`, `minOffS`
|
||
tous vides ou nuls).
|
||
|
||
**Aller-retour NEUTRE, par la frontière RPC** : `GetLoadConfig` → `SetLoadConfig` verbatim →
|
||
`GetLoadConfig` rend un objet **identique**, et le journal du cycle suivant dit
|
||
`0 créée(s), 0 mise(s) à jour en place, 2 inchangée(s), 0 retirée(s)` — **aucun adaptateur
|
||
reconstruit, aucun verrou réarmé.**
|
||
|
||
**`loads[] ⊆ GetLoadConfig` est rétabli** : les trois charges publiées ont leur entrée. La
|
||
Terra AC est dans `GetLoadConfig` sans être dans `loads[]` — c'est le sens autorisé de
|
||
l'inclusion : sans voiture assignée, elle est **hors arbitrage**, et le journal le dit
|
||
(`[Arbitre] Borne "Terra AC Charger (TCP)" hors waterfall`).
|
||
|
||
### 2.4 La bascule elle-même
|
||
|
||
`nymead` arrêté 10:03:24, démarré 10:03:35, premier cycle d'arbitrage 10:04:00 — **36 s sans
|
||
arbitrage**. L'ECS a repris son palier par relecture des contacts
|
||
(`reprise au démarrage : palier 0 W [correspondance exacte]`, ECS-411).
|
||
|
||
⚠️ **Le cas de transition que je voulais éprouver ne l'a PAS été** : au moment de la bascule,
|
||
**aucune borne n'était sous commande** (surplus négatif, wallbox à l'arrêt). « Une borne
|
||
commandée par un chemin qui n'existe plus » reste donc non observé. Ce qui EST observé et qui
|
||
en couvre la moitié : l'arbitre émet activement des `power: OFF` (4 fois sur la fenêtre), donc
|
||
le mécanisme qui rattraperait une borne laissée allumée est en place et tourne.
|
||
|
||
---
|
||
|
||
## 3. CE QUE LA MACHINE A TROUVÉ, ET QUI N'EST PAS DANS LE LOT
|
||
|
||
### 3.1 GRAVE — une borne SANS VÉHICULE BRANCHÉ absorbe le budget de la cascade
|
||
|
||
Trois cycles consécutifs, wallbox en Eco avec voiture assignée mais **`pluggedIn: false`** :
|
||
|
||
```
|
||
[Arbitre] "chauffe-eau" → "Surplus PV 8353 W — chauffe-eau consigne 3500 W (palier)"
|
||
[Arbitre] "{09e520fd…}" → "Surplus PV 4853 W — Simulated wallbox consigne 4853 W" ← 4 853 W
|
||
[Arbitre] "pac-terrain" → "Surplus PV 1500 W — PAC banc recommandée (état 3, ~1500 W)"
|
||
```
|
||
|
||
Et dans la même charge utile de télémétrie, pour cette borne :
|
||
|
||
```
|
||
allocatedW: 4853 mécanisme: { chargingEnabled: false, pluggedIn: false, currentA: 7, phaseCount: 1 }
|
||
```
|
||
|
||
La borne est commandée `power: ON`, elle ne tire **rien** (`currentPower: 0`), et **4 853 W ont
|
||
été retirés du budget et donnés à personne**. La PAC derrière elle n'a survécu que sur son
|
||
propre recrédit. Les deux cycles voisins donnent 2 350 W puis 5 464 W au même vide.
|
||
|
||
**C'est le défaut du relevé 3g-1 §3.4 qui revient par une autre porte** : là c'était le plancher
|
||
qui mentait, ici c'est le filtre d'entrée.
|
||
|
||
**Cause** : `EnergyArbitrator::evParticipatesInWaterfall()` reprend le filtre d'entrée du proxy —
|
||
voiture assignée, mode non manuel — **mais pas `pluggedIn`**. Le proxy n'en avait pas besoin :
|
||
son allocation n'était pas une cascade, gaspiller ne privait personne. En cascade, si.
|
||
L'asymétrie est visible dans le code même : la boucle EV du scheduler, elle, teste bien
|
||
`if (!ev->available() || !ev->pluggedIn()) continue;` — seul le chemin waterfall ne le fait pas.
|
||
|
||
**Défaut de 3g-1**, révélé par 3g-2 parce que la décision atteint enfin le matériel.
|
||
|
||
**CORRIGÉ** (commit dédié, après ce relevé) : `pluggedIn` rejoint le filtre d'entrée. Une borne
|
||
sans véhicule est **hors arbitrage**, comme une borne sans voiture assignée ou en mode manuel
|
||
(`DESIGN_3g` §4) — absente du contexte, pas servie à 0 : sa consommation est nulle et déjà au
|
||
compteur. Le journal l'annonce comme les deux autres cas.
|
||
|
||
Éprouvé par `testUnpluggedChargerTakesNoBudget`, **vérifié échouant sans le correctif** : la
|
||
borne débranchée disparaît du contexte, la charge suivante reçoit les 3 000 W entiers, et la
|
||
seconde moitié du test rebranche le véhicule pour prouver que c'est bien `pluggedIn` qui décide
|
||
et non une exclusion fortuite.
|
||
|
||
**VÉRIFIÉ SUR MACHINE avec `1.15.2+etm24`**, en rejouant exactement la condition — wallbox en
|
||
Eco, voiture assignée, `pluggedIn: false` :
|
||
|
||
```
|
||
[Arbitre] Borne "Simulated wallbox" hors waterfall (pas de voiture assignée, mode manuel,
|
||
ou aucun véhicule branché).
|
||
```
|
||
|
||
`loads[]` ne contient plus que `chauffe-eau` et `pac-terrain`, et le budget leur va entier.
|
||
Sous `+etm23`, la même condition donnait 4 853 W à la borne.
|
||
|
||
> **Conséquence à connaître : « hors arbitrage » ne veut pas dire « non commandée ».** Sortie du
|
||
> waterfall, la borne retombe sur le PROXY, qui la planifie et la commande —
|
||
> `### Surplus would adjust evcharger "Simulated wallbox" to total 12,35 A (2 841 W)` puis
|
||
> `Executing action … to power: ON, Carging current: 6A, Issuer: Surplus`. C'est le repli prévu
|
||
> (tout ce que le waterfall ne prend pas reste au proxy) et **l'invariant du lot tient : un seul
|
||
> commandeur**. Aucun watt n'est retiré de la cascade, et la borne ne tire rien puisque rien
|
||
> n'est branché — c'est le comportement de l'amont, inchangé.
|
||
>
|
||
> À noter tout de même l'asymétrie avec les deux autres exclusions : « mode manuel » fait sauter
|
||
> la borne dans `adjustEvChargers()`, « pas de voiture » la fait finir à `power OFF`, tandis que
|
||
> « débranchée » la fait commander ON au courant minimum. Sans effet tant que rien n'est
|
||
> branché ; à revoir le jour où le §10 fera du proxy autre chose qu'un repli.
|
||
|
||
### 3.2 Mineur — le rang par défaut retombe à ÉGALITÉ, pas « en tête »
|
||
|
||
Les deux bornes ont reçu **rang 1**, à égalité avec `chauffe-eau` qui l'occupait déjà.
|
||
|
||
La règle implémentée est « le plus petit rang existant moins un, borné à 1 ». Quand une charge
|
||
occupe déjà le rang 1, « moins un » vaut 0, le plancher le ramène à 1, et l'intention — mettre la
|
||
borne **en tête sans bousculer les charges déjà classées** — dégénère en égalité.
|
||
|
||
Sans conséquence sur la reproductibilité : le tri est **total**, l'identifiant départage, et
|
||
l'ordre est stable d'un cycle à l'autre. Mais ce n'est pas ce qui était demandé. Trois issues
|
||
possibles, aucune tranchée : autoriser le rang 0, renuméroter les autres (exclu par « sans
|
||
bousculer »), ou assumer l'égalité et laisser l'app poser les vrais rangs à la mise en service.
|
||
|
||
### 3.3 Pour mémoire — deux écritures de configuration dans le même cycle
|
||
|
||
Deux bornes détectées ⇒ deux `setConfigs()` ⇒ deux `changed()` ⇒ deux `rebuildLoadAdapters()`
|
||
dans le cycle de démarrage. Les deux sont incrémentaux (`2 inchangée(s)`), donc **aucun
|
||
adaptateur n'est détruit** et ECS-412 tient. Sans conséquence, mais à savoir si le nombre de
|
||
bornes grandit.
|
||
|
||
---
|
||
|
||
## 4. CE QUI N'EST PAS PROUVÉ
|
||
|
||
- **`EV_GRID_START` : NON observé.** Guetté six cycles durant, comme demandé — jamais fabriqué.
|
||
Le budget de la borne est passé de 385 W à 2 350 W sans s'arrêter dans la fenêtre
|
||
`[plancher × 0,5 ; plancher[` (690–1 380 W en monophasé). Le motif reste donc éprouvé par le
|
||
seul test de simulation. **À guetter, comme `BELOW_MIN_POWER` l'a été.**
|
||
- **`BATTERY_RESERVE` avec un surplus réel sous le seuil** : toujours pas. Le SoC est à 50 %,
|
||
le seuil à 0,4 — la réserve n'est pas active.
|
||
- **LM-1204-b, moitié matérielle** : deux bornes réelles (§1).
|
||
- **Le cas de transition** « borne commandée par un chemin qui n'existe plus » (§2.4).
|
||
- **La charge réelle d'un véhicule** : aucune voiture n'a été branchée — la wallbox simulée
|
||
n'expose aucune action `pluggedIn`, seulement `connect`/`disconnect` (interface `connectable`,
|
||
état `connected`). C'est d'ailleurs ce qui a rendu §3.1 visible.
|
||
|
||
---
|
||
|
||
## 5. État où le banc a été rendu
|
||
|
||
| | valeur | pourquoi |
|
||
|---|---|---|
|
||
| Paquet | **`1.15.2+etm24`** | posé par `deploy.sh` ; `+etm22` et `+etm23` archivés |
|
||
| `ChargingInfos` | **identiques à l'origine** — les deux bornes en `ChargingModeNormal`, sans voiture, `targetPercentage: 0` | comparées champ par champ au relevé d'avant |
|
||
| Voiture de test | **retirée** (`3G2-CAR-A-SUPPRIMER`) | |
|
||
| Wallbox simulée | **éteinte** (`power: false`) | l'arbitre ne la commande plus, elle est hors arbitrage |
|
||
| `LoadConfig` | **4 entrées** : chauffe-eau, PAC banc, + les 2 bornes auto-provisionnées | les entrées de borne RESTENT — elles seraient recréées au prochain démarrage |
|
||
| `batteryLevelConsideration` | 0,4 · `acquisitionTolerance` 0,5 · `phasePowerLimit` 0 | inchangés |
|
||
|
||
Dernier cycle rendu : surplus 5 634 W, `chauffe-eau` 3 500 W, `pac-terrain` 3 000 W, aucune
|
||
borne dans `loads[]`.
|