From 1302e9a04ee53d64750993d776347c8a370c356a Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Sun, 25 Oct 2026 07:15:36 +0100 Subject: [PATCH] =?UTF-8?q?docs=20:=20heures=20creuses=20et=20batterie=20?= =?UTF-8?q?=E2=80=94=20d=C3=A9cision=20D8,=20la=20consigne=20se=20pose=20p?= =?UTF-8?q?r=C3=A8s=20de=20la=20limite=20de=20phase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §8 : D8 (2026-10-25) — en heures creuses, le plafond de la borne lui rend son courant mesuré, moins 1 A par phase ; la tenue au plancher en surcharge (L4 décide) est confirmée. - §8.1 : écarts ouverts 3 (double écrêtage hors heures creuses, lot à part) et 4 (partage achat/surplus à l'aube, avec la dérogation) ; l'oscillation renvoie à §8.2. - §8.2 : la règle, la marge, la sécurité en dépassement, les hypothèses, les mesures avant/après et les preuves. Co-Authored-By: Claude Opus 5.5 --- docs/DESIGN_HC_BATTERIE.md | 103 +++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/docs/DESIGN_HC_BATTERIE.md b/docs/DESIGN_HC_BATTERIE.md index ae064f4..821d2b2 100644 --- a/docs/DESIGN_HC_BATTERIE.md +++ b/docs/DESIGN_HC_BATTERIE.md @@ -50,8 +50,9 @@ verrous gardent la tête : ils diraient la même chose en heures creuses. **En heures creuses**, le plancher est servi au réseau par la passe éco (`ECO_FLOOR_GRID`), bornée par l'autorisation de soutirage ; le confort ajoute le surplus s'il y en a. *Lot e2 : c'est désormais le plafond, sous `EV_OFF_PEAK_FULL_POWER` — §8, D7.* La borne -déclare un plafond écrêté par `evPhaseAllowanceW()`, `verifyOverloadProtection()` garde le dernier -mot : l'invariant 2 tient sans rien ajouter. +déclare un plafond écrêté par `evPhaseAllowanceW()` — en heures creuses par +`evOffPeakAllowanceW()`, qui lui rend son courant mesuré moins 1 A (§8.2, D8) —, et +`verifyOverloadProtection()` garde le dernier mot : l'invariant 2 tient sans rien ajouter. **L'échéance** : la puissance nécessaire pour tenir une échéance reste celle du proxy amont, qui force la charge à pleine puissance au point de non-retour. Ce point est calculé sur l'échéance, @@ -280,6 +281,7 @@ aucune ne change le code. | D5 | Seuil de « la voiture charge réellement » : 230 W sur la somme des bornes (§3.2) ? | **Accepté.** | | D6 | Plugin SunSpec : une action « limite de décharge » en une séquence (`planBatteryMode(NO_DISCHARGE)`), et `enableDischarging` renommé ou redécrit (§3.1, §7) ? | **Oui aux deux**, dans le dépôt du plugin, à la charge de l'orchestrateur. Le garde ne change pas : il reste compatible avec les deux actions actuelles (`dischargingRate` puis `enableDischarging`). | | D7 | À quelle puissance la borne charge-t-elle en heures creuses (lot e2) ? | **À la pleine puissance permise**, et non plus au plancher. La session finit plus tôt, et la décharge de la batterie n'est bloquée que pendant ce temps-là : ensuite, elle couvre la maison pour le reste de la nuit. Détail en §8.1. | +| D8 | *(2026-10-25)* Près de la limite de phase, la consigne de la borne alterne à chaque cycle (16, 7, 16, 7 A sous 25 A). Corriger avant la vitrine ? | **Oui, maintenant.** En heures creuses, le plafond de la borne lui rend ce qu'elle tire, **mesuré**, moins 1 A par phase. Détail en §8.2. Le même jour : la borne **tenue au plancher** en surcharge (L4 décide de couper) est **confirmée** ; les écarts 3 et 4 de §8.1 sont reportés. | La mesure du minuteur de retour sur un vrai GEN24 (hypothèse AC-10 du plugin, §3.4) reste ouverte : elle relève du plugin et d'un essai sur matériel réel. @@ -295,7 +297,8 @@ pleine le matin, et le surplus solaire part au réseau. réseau en heures creuses est le **plafond de cycle** de la borne (`declared.maxPowerW`) : - il porte le courant maximal de la borne, ses phases, et la limite de phase - (`evPhaseAllowanceW()`) — rien n'est retiré de ces écrêtages ; + (`evPhaseAllowanceW()` ; depuis D8, `evOffPeakAllowanceW()`, §8.2) — rien n'est retiré de ces + écrêtages ; - il ne descend jamais sous le plancher : la limite de phase **rabaisse** la borne, elle ne la coupe pas ; couper reste le geste de `verifyOverloadProtection()` (L4), qui garde le dernier mot ; @@ -321,20 +324,26 @@ la nuit réduit le plafond au cycle suivant ; sous le plancher, la borne est ten L4 coupe au dépassement. Cette exemption ne vaut **qu'en heures creuses** : sans heure creuse, le plancher éco d'une borne reste écrêté par la marge de la maison, comme avant. -**Reste à trancher** (rien n'est changé par ce lot) : +**Surcharge au plancher — confirmé le 2026-10-25.** En heures creuses, quand la limite de phase +ne laisse plus le plancher, la stratégie tient la borne à son plancher (`boundBy: floor`) et L4 +décide de la couper, comme pour la dérogation. On n'est pas revenu au « rien acheté » du lot e1. -- *Le double écrêtage hors heures creuses.* Le plancher éco d'une borne triphasée, sans heure - creuse, est encore comparé à la marge d'une phase. L'étendre à `LM-1500-h` changerait des - décisions sans tarif : c'est un choix à faire à part. -- *L'oscillation près de la limite de phase.* Le plafond d'une borne est la place libre **sans - lui rendre ce qu'elle tire** (`evPhaseAllowanceW()`, choix de sécurité documenté). À pleine - puissance, la borne voit donc sa propre consommation lui réduire le plafond au cycle suivant, - puis le lui rendre au cycle d'après. En simulation, avec un compteur qui voit la borne (maison - à 2 A par phase, borne triphasée 16 A), la consigne alterne à chaque cycle entre 16 et 7 A - sous une limite de 25 A, et entre 16 et 14 A sous 32 A. Au plancher (lot e1), le phénomène ne - se voyait pas. Une piste : rendre à la borne, en heures creuses, son propre courant moins une - marge (la règle de l'échéance chez l'amont, `adjustEvChargers()` : marge − 1 A + courant de la - borne). +**Écarts ouverts** (rien n'est changé ; décision du 2026-10-25 : plus tard, chacun dans son lot) : + +- *Écart 3 — le double écrêtage hors heures creuses.* Sans heure creuse, le plancher éco d'une + borne triphasée est encore comparé à la marge d'**une** phase de la maison (le double + écrêtage que `LM-1500-h` refuse ailleurs). L'étendre changerait des décisions sans tarif : + **lot à part**. +- *Écart 4 — le partage achat/surplus en heures creuses.* À l'aube, le surplus s'ajoute au + niveau éco : la consigne (`estimatedPowerW`) peut dépasser le plafond de cycle, par exemple + 3 680 + 2 000 W. L'adaptateur écrête au courant maximal de la borne, et le partage publié entre + achat et surplus surestime l'achat. Le même cumul existe pour la dérogation. Ce cumul n'est + pas borné par le plafond de phase déjà servi au niveau éco : constaté au lot D8 avec un + compteur qui ne voit pas la borne (le recrédit y fabrique du surplus), plafond 15 A, consigne + 16 A. Avec un vrai surplus, seul L4 rattraperait un dépassement. **À reprendre avec la + dérogation.** +- *L'oscillation près de la limite de phase* était le troisième point de cette liste. Elle est + corrigée : §8.2. **Fin de session.** Le blocage de la décharge se lève sur la puissance **mesurée** des bornes, au seuil de 230 W (D5). Une borne commandée à 16 A dont la voiture ne prend plus rien (pleine, @@ -358,3 +367,65 @@ la maison consommera d'ici le retour du soleil — consommation de base prévue heure de la première production utile (prévision PV). Elle demande une prévision fiable des deux, et un pilotage de `OutWRte` plus fin qu'un tout-ou-rien : c'est un lot à part. +### 8.2 D8 — près de la limite de phase, la consigne se pose (2026-10-25) + +**Le défaut.** Le plafond d'une borne était la place libre au compteur, **sans lui rendre ce +qu'elle tire** (`evPhaseAllowanceW()`). Avec un compteur qui voit la borne, sa propre +consommation lui retirait la place au cycle suivant, puis la lui rendait au cycle d'après. Mesuré +en simulation, maison à 2 A par phase, borne 16 A, mono comme tri : + +| Limite | Avant (consigne cycle par cycle) | Après | +|---|---|---| +| 25 A | 16, 7, 16, 7… (11,5 A en moyenne) | 16 A tenus | +| 32 A | 16, 14, 16, 14… | 16 A tenus | +| 16 A | 14, 6, 8, 6, 8… (7 A en moyenne) | 13 A tenus, 15 A au compteur | + +**La règle.** En heures creuses, et pour la pleine puissance du lot e2 seulement, le plafond est +lu par `EnergyArbitrator::evOffPeakAllowanceW()` : + +> plafond par phase = limite − (tirage de la phase − courant **mesuré** de la borne) − **1 A**, +> arrondi à l'ampère inférieur, × phases. + +C'est la règle de l'échéance chez l'amont (`adjustEvChargers()`). Elle converge en **un** cycle : +le résultat ne dépend plus de ce que la borne tirait, seulement de ce que tire le reste de la +maison. + +- *Mesure, pas consigne.* Le courant rendu est l'état `currentPower` de la borne, sur les phases + où elle le mesure. Une voiture qui prend 10 A d'une borne commandée à 16 n'occupe que 10 A : + lui rendre 16 lui ouvrirait 6 A de trop. Une borne sans mesure, à l'arrêt, ou qui bascule de + phases (mesurées ≠ visées) ne rend rien, et la marge s'applique quand même. +- *La marge : 1 A par phase.* C'est celle de l'amont, pour la même raison : laisser à un appareil + moyen allumé entre deux cycles la place de démarrer avant que L4 ait à couper. Elle couvre aussi + l'écart entre la puissance annoncée par la borne et le courant lu au compteur (tension ≠ 230 V, + ±3 % à 16 A, soit 0,5 A). L'arrondi à l'ampère **inférieur** garantit qu'elle n'est pas mangée + par l'adaptateur, qui arrondit la consigne au plus proche. Plus grande, elle coûterait 230 W + par phase toute la nuit, sans raison mesurée ; plus petite, elle ne couvrirait plus l'écart de + mesure. +- *La sécurité en dépassement tient.* C'était la raison de ne rien rendre. Si une phase tire + `I > limite`, dont `E` pour la borne, la place rendue vaut `limite − (I − E) − 1 < E − 1` : la + consigne baisse d'au moins 1 A par cycle, jusqu'à sortir du dépassement ou jusqu'au plancher, où + la stratégie tient la borne et où L4 décide. Cela suppose que le compteur voie la borne — ce + que L4 suppose déjà. +- *Un compteur qui ne voit pas la borne* ne la mène pas seule à la limite : le tirage de la maison + sans la borne est écrêté à zéro, donc une phase vaut au plus sa limite moins la marge. +- *Où.* Seulement là où `EvAdapter` vise la pleine puissance d'heures creuses (trois modes, heure + creuse en cours). Hors heures creuses et sans tarif, `evPhaseAllowanceW()` reste la règle, et + les décisions sans tarif ne changent pas. En heures creuses, une dérogation sur la borne lit le + même plafond (c'est le même `declared.maxPowerW`). Sans heure creuse, la dérogation garde + l'ancienne règle : la faire passer par la même voie changerait son comportement sans tarif, et + ce n'est pas décidé. + +**Hypothèses.** Les phases de la borne sont celles du compteur (même hypothèse que L4 et que +l'amont). Une borne qui annonce plus que ce que le compteur voit d'elle reçoit au plus 1 A sous la +limite. Un compteur rafraîchi après la borne (borne qui monte, compteur pas encore) peut +surestimer la place d'un cycle, dans la même limite ; L4, lui, lit le compteur en temps réel. + +**Preuves.** `testOffPeakFullPowerSettlesUnderThePhaseLimit` (sept cas, douze cycles : la consigne +se pose dès le premier cycle, la phase la plus chargée reste à 1 A au moins sous la limite ; un +cas à 2,4 A de maison prouve l'arrondi) ; `testOffPeakFullPowerYieldsToThePhaseLimit`, réécrit +avec un compteur qui voit la borne (mesure et non consigne, dépassement, plancher, coupure par +L4) ; `testOffPeakFullPowerStaysUnderTheLimitOnABlindMeter` (écrêtage à zéro) ; +`testOverloadProtectionEcoMode`, hors heures creuses, inchangé. Dans +`testBlockedDischargeShowsAtTheMeterAndL4Decides`, la borne en dépassement finit à son plancher +(L4 la ramène de 16 à 13 A, la stratégie laisse 9 A, L4 la ramène à 6 A) au lieu d'être coupée : +l'assertion attend désormais « plancher ou coupée ».