diff --git a/HANDOFF.md b/HANDOFF.md index b3c3b34..ebb862f 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1670,3 +1670,133 @@ mêler au diagnostic. --- *Document mis à jour le : 30/08/2026 — consigne réseau 4200 W et SOC minimal ESS 40 % identifiés comme propriétaires non lus de la décision réseau ; procédure d'intervention rédigée* + +## 28. Session du 31/08/2026 — La substitution ne se reproduit plus (batterie preneuse). Cas « batterie pleine » encore ouvert + +Première vérification de la correction de la consigne réseau (4200 → 50 W, +§27), sur une nuit complète puis deux campagnes alternées. + +### La nuit 30-31/08 : l'import colle à la consommation +Une seule session réseau, `switch.edf_general_ok_switch` ON à **05:04:10** +(hystérésis, SOC 21 ≤ seuil 20) et OFF à **10:08:04** (SOC 30 ≥ seuil OFF). +Aucun rebond, aucun créneau. + +| heure | import réseau | conso maison | courant batterie | +|---|---:|---:|---:| +| 05:15 | 780 W | 732 W | 0 A | +| 06:30 | 507 W | 477 W | −1 A | +| 07:45 | 781 W | 751 W | +4 A | + +À comparer au test du 27/08 10:47 où, pour 877 W de consommation, l'import +montait en rampe jusqu'à **4113 W** pour gaver la batterie. Le comportement a +disparu. Détail de la fermeture : de 05:04 à 05:13 l'import est resté à +**24-56 W** (la consigne) pendant que la batterie continuait de servir la maison +à −15 A ; à 05:14, SOC atteignant le plancher ESS de 20 %, l'ESS a basculé — +import = charge maison, batterie à 0 A, SOC plat à 20 % jusqu'à 08:00. Manuel. + +### Le matin : réseau présent, production libre +De 08:40 à la coupure de 10:08, contacteur toujours fermé : + +| heure | PV | import | conso | I batterie | +|---|---:|---:|---:|---:| +| 08:45 | 1 303 W | **18 W** | 1 109 W | +2 A | +| 09:25 | 3 425 W | **39 W** | 805 W | +50 A | +| 10:05 | **5 244 W** | **47 W** | 952 W | +83 A | + +`sensor.mppt_450_200_hq2449yr9pt_mppt_operation_mode` est resté `mppt_active` +sur toute la fenêtre : le chargeur déclare lui-même chercher son point de +puissance maximale pendant que le réseau est présent. + +### Campagnes alternées (`tools/test-edf-alterne.mjs`) +Journaux : `docs/mesures/20260831-1043-test-edf-alterne.log` (phases 180 s) et +`20260831-1101-test-edf-alterne.log` (phases 240 s). + +Transitions exploitables, chaque phase fermée contre ses voisines ouvertes : + +| phase | PV fermée | PV voisines ouvertes | écart | trackers bridés | +|---|---:|---:|---:|---:| +| 10:47 ON_1 | 7 168 W | 7 131 W | **+0,5 %** | 2,7/7 (DVCC, I=124 A) | +| 11:13 ON_2 | 7 920 W (max 8 759) | 7 002 W | **+13,1 %** | 4,5/7 (DVCC, I=125 A) | + +Le 27/08, la même manœuvre faisait tomber la PV de 3 885 à 1 045 W en 90 s avec +six trackers sur sept en `voltage_current_limited`. **La substitution ne se +reproduit plus à batterie preneuse.** Le bridage résiduel observé est le bridage +NORMAL : il apparaît quand le courant batterie approche la limite DVCC (125 sur +130 A) et il s'accompagne d'un import réseau nul — critère de discrimination +utilisable : bridage normal ⇒ import nul ; bridage anormal ⇒ l'import remplace +la production. + +### Mécanisme identifié : un transitoire de reprise, qui retombe à la consigne +À chaque fermeture du contacteur, le réseau reprend d'un coup **toute** la charge +de la maison et la totalité du solaire bascule vers la batterie. Bilan vérifié au +watt près (10:48:15 : PV 7222 + grid 2120 − conso 2249 = 7093 W contre 7107 W de +charge batterie mesurée). Puis l'import **décroît jusqu'à la consigne** : + +| campagne | import à la fermeture | après ~2 min 15 | +|---|---:|---:| +| 11:05 ON_1 | 1 985 W | **25 W**, stable | +| 11:13 ON_2 | 2 600 W | **52 W** puis −41 W | + +Coût ≈ 50-60 Wh par fermeture. Avec l'ancienne consigne à 4200 W, cette reprise +n'avait aucune raison de redescendre : elle se stabilisait sur « le réseau +alimente tout, on bride le solaire pour faire de la place ». C'est +vraisemblablement le même mécanisme, dont la correction de consigne a rétabli +l'extinction. Corollaire : chaque fermeture coûte, ce qui plaide pour une +session réseau unique et dimensionnée plutôt que des créneaux répétés. +Note : aucun transitoire à la fermeture de 05:04 (PV nulle) — il n'y a rien à +rediriger quand il n'y a pas de solaire. + +### CE QUI N'EST TOUJOURS PAS TESTÉ — batterie pleine (à faire) +Tout ce qui précède s'est mesuré à SOC 40-54 %, batterie absorbant 60 à 125 A. +Le propriétaire maintient, sur plusieurs mois d'observation, que le cas décisif +est **batterie pleine** : plus de tampon, donc le solaire qui alimentait la +maison n'a plus de destination quand le réseau la reprend. Discrimination +attendue, contacteur fermé, maison ~2 kW, SOC ≥ 90 % : + +| observation | conclusion | +|---|---| +| PV ≈ conso (~2 kW), import ≈ 50 W | corrigé — écrêtage normal, le solaire sert la maison | +| PV ≈ 0-1 kW, import ≈ conso | non corrigé — éviction ; VEConfigure (§27, `docs/PROCEDURE_ESS_PARALLELE.md` étape 1) | + +Le 27/08 à 11:38, SOC 86-88 %, batterie n'acceptant plus que ~1 kW, on avait +PV 1043 W pour une maison à 2258 W et un import de 2287 W : le solaire SOUS la +consommation et le réseau AU-DESSUS. C'est le point le plus proche du cas +décisif dont on dispose, et il est du mauvais côté. Trois minutes de protocole +alterné à SOC ≥ 90 suffiront à trancher. + +### Outillage ajouté +- `tools/test-edf-alterne.mjs` — protocole alterné OFF/ON/OFF/ON/OFF, phases et + pas d'échantillonnage paramétrables. Mesure PV, tension et courant batterie, + conso, import, SOC, limite DVCC, présence physique AC-IN et le mode des 7 + chargeurs solaires. **Désactive l'hystérésis pendant le test et restaure tout + à la fin, sur Ctrl-C et sur erreur.** Journal horodaté dans `docs/mesures/`. +- `tools/analyse-test-alterne.mjs` — résumé par phase et verdict. + +Deux pièges d'instrumentation corrigés en cours de route, à ne pas réintroduire : +1. **Garde météo.** Les phases OUVERTES voient toutes la même ressource : si + elles divergent entre elles (33 % et 42 % sur les deux campagnes du 31/08), + la moyenne ON contre OFF est ininterprétable. L'outil refuse désormais de + conclure dans ce cas et compare chaque phase fermée à ses voisines + immédiates. C'est ce piège qui avait pollué le premier test du 27/08. + Contrôle interne utile : si la PV chute AVANT l'apparition de l'import, ce + sont des nuages (cas de la phase ON_2 du 31/08 10:53, chute 6995 → 3607 W + avec l'import encore à zéro). +2. **Biais du parseur.** La lecture des modes MPPT était ancrée sur `MPPT `, ce + qui faisait tomber en silence toute ligne dont le PREMIER tracker était bridé + — précisément les échantillons à mesurer — et biaisait le résultat vers + « aucun bridage ». Le bloc de modes est le dernier champ : l'ancrer sur + `edf on|off`, jamais sur le mot `MPPT`. + +### Signal indépendant : la jauge de SOC s'effondre en bas d'échelle +Entre 04:00 et 04:20, le SOC est passé de **30 à 22 %** alors que la batterie ne +débitait que ~11 A (≈ 550 W), tension stable à 49 V. Huit points sur un parc de +~15 kWh représentent 1,2 kWh, soit plus de deux heures à ce débit — pas vingt +minutes. La jauge ne mesure plus, elle réestime. Comportement classique d'un +parc vieillissant près du genou de décharge, cohérent avec le module en panne +connu (7 modules actifs sur 8, cf. MANUEL §0). +Conséquence : tous les seuils des deux workflows (20, 30, 22, 35) sont exprimés +dans une grandeur non linéaire en bas d'échelle. À verser au chantier du bilan +énergétique ; ne pas « corriger » par un seuil de plus. + +--- +*Document mis à jour le : 31/08/2026 (~11:30) — substitution non reproduite à batterie preneuse (nuit + 2 campagnes alternées) ; transitoire de fermeture caractérisé et retombant à la consigne ; cas batterie pleine à tester* diff --git a/docs/mesures/20260831-1043-test-edf-alterne.log b/docs/mesures/20260831-1043-test-edf-alterne.log new file mode 100644 index 0000000..dd89b5e --- /dev/null +++ b/docs/mesures/20260831-1043-test-edf-alterne.log @@ -0,0 +1,72 @@ +TEST ALTERNE EDF <-> MPPT — 31/08/2026 10:43:54 +phases 180s, echantillon 15s, sequence OFF_1 / ON_1 / OFF_2 / ON_2 / FIN_OFF +etat initial : edf off | latch off | hysteresis on +consigne reseau 50 W | SOC min ESS 20 % | limite active 20.0 % +MPPT ordre: mppt1 rs_1 rs_2 rs_3 rs_4 rs_g v1 (MPPT=cherche le max, lim_=se retient) + +10:43:56 | OFF_1 | PV 7353 | U 50.13 | I 97.3 | conso 2270 | grid 0 | SOC 39 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:44:11 | OFF_1 | PV 6985 | U 50.15 | I 95.8 | conso 2258 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:44:26 | OFF_1 | PV 6710 | U 50.16 | I 91.3 | conso 2276 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:44:41 | OFF_1 | PV 6216 | U 50.12 | I 75.5 | conso 2309 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:44:56 | OFF_1 | PV 6749 | U 50.10 | I 70.7 | conso 2246 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:45:11 | OFF_1 | PV 6683 | U 50.17 | I 91.3 | conso 2263 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:45:26 | OFF_1 | PV 5462 | U 50.10 | I 67.8 | conso 2252 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:45:42 | OFF_1 | PV 5423 | U 50.08 | I 64.4 | conso 2270 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:45:57 | OFF_1 | PV 6697 | U 50.10 | I 74.8 | conso 2268 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:46:12 | OFF_1 | PV 6911 | U 50.12 | I 78.3 | conso 2264 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:46:27 | OFF_1 | PV 7168 | U 50.18 | I 97.2 | conso 2246 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:46:42 | OFF_1 | PV 7498 | U 50.19 | I 96.0 | conso 2272 | grid 0 | SOC 40 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF ON +10:47:00 | ON_1 | PV 7278 | U 50.21 | I 98.9 | conso 2252 | grid 0 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:47:15 | ON_1 | PV 7169 | U 50.23 | I 99.0 | conso 2244 | grid 0 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:47:30 | ON_1 | PV 7447 | U 50.22 | I 95.3 | conso 2286 | grid 0 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:47:45 | ON_1 | PV 7327 | U 50.22 | I 94.5 | conso 2300 | grid 0 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:48:00 | ON_1 | PV 7221 | U 50.22 | I 95.4 | conso 2252 | grid 0 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:48:15 | ON_1 | PV 7222 | U 50.37 | I 141.1 | conso 2249 | grid 2120 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +10:48:30 | ON_1 | PV 6884 | U 50.36 | I 129.1 | conso 2245 | grid 1914 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +10:48:45 | ON_1 | PV 7087 | U 50.37 | I 126.8 | conso 2252 | grid 1727 | SOC 41 | DVCC 130A/51.5V | acin 1 | edf on | volt MPPT MPPT MPPT MPPT volt volt +10:49:00 | ON_1 | PV 7331 | U 50.37 | I 126.0 | conso 2309 | grid 1556 | SOC 42 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +10:49:15 | ON_1 | PV 7458 | U 50.37 | I 124.4 | conso 2228 | grid 1248 | SOC 42 | DVCC 130A/51.5V | acin 1 | edf on | volt MPPT MPPT MPPT MPPT MPPT MPPT +10:49:30 | ON_1 | PV 7520 | U 50.37 | I 122.8 | conso 2293 | grid 1117 | SOC 42 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:49:45 | ON_1 | PV 6730 | U 50.35 | I 115.5 | conso 2271 | grid 886 | SOC 42 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF OFF +10:50:04 | OFF_2 | PV 7329 | U 50.32 | I 108.6 | conso 2254 | grid 0 | SOC 42 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:50:19 | OFF_2 | PV 6540 | U 50.28 | I 99.0 | conso 2397 | grid 0 | SOC 42 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:50:34 | OFF_2 | PV 7382 | U 50.25 | I 93.0 | conso 2338 | grid 0 | SOC 42 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:50:49 | OFF_2 | PV 7356 | U 50.28 | I 99.0 | conso 2240 | grid 0 | SOC 42 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:51:04 | OFF_2 | PV 7639 | U 50.28 | I 99.8 | conso 2243 | grid 0 | SOC 42 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:51:19 | OFF_2 | PV 7381 | U 50.28 | I 101.0 | conso 2240 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:51:34 | OFF_2 | PV 7508 | U 50.27 | I 98.2 | conso 2257 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:51:49 | OFF_2 | PV 7700 | U 50.27 | I 100.2 | conso 2331 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:52:04 | OFF_2 | PV 7879 | U 50.28 | I 101.6 | conso 2305 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:52:19 | OFF_2 | PV 7570 | U 50.29 | I 103.3 | conso 2328 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:52:34 | OFF_2 | PV 7853 | U 50.29 | I 103.3 | conso 2311 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:52:49 | OFF_2 | PV 7899 | U 50.30 | I 106.8 | conso 2309 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF ON +10:53:07 | ON_2 | PV 6995 | U 50.30 | I 103.0 | conso 2329 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:53:22 | ON_2 | PV 5384 | U 50.22 | I 80.6 | conso 2822 | grid 0 | SOC 43 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:53:37 | ON_2 | PV 4032 | U 50.01 | I 23.6 | conso 2793 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:53:52 | ON_2 | PV 3607 | U 49.91 | I 6.9 | conso 2825 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:54:07 | ON_2 | PV 3686 | U 49.87 | I 11.4 | conso 2804 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:54:22 | ON_2 | PV 3707 | U 50.03 | I 70.3 | conso 2874 | grid 2717 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:54:37 | ON_2 | PV 3794 | U 50.06 | I 63.8 | conso 2926 | grid 2598 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:54:52 | ON_2 | PV 3037 | U 50.05 | I 57.4 | conso 2719 | grid 2221 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:55:07 | ON_2 | PV 2968 | U 50.01 | I 43.8 | conso 2731 | grid 1956 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:55:22 | ON_2 | PV 3078 | U 49.98 | I 39.8 | conso 2739 | grid 1760 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:55:37 | ON_2 | PV 3603 | U 49.98 | I 43.8 | conso 2767 | grid 1555 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:55:52 | ON_2 | PV 4702 | U 50.00 | I 50.1 | conso 2741 | grid 1343 | SOC 44 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF OFF +10:56:11 | FIN_OFF| PV 4788 | U 50.07 | I 65.7 | conso 2664 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:56:26 | FIN_OFF| PV 5765 | U 50.02 | I 51.7 | conso 2682 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:56:41 | FIN_OFF| PV 5249 | U 50.00 | I 44.5 | conso 2634 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:56:56 | FIN_OFF| PV 4821 | U 49.96 | I 36.0 | conso 2664 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:57:11 | FIN_OFF| PV 6658 | U 49.98 | I 45.1 | conso 2642 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:57:26 | FIN_OFF| PV 7882 | U 50.15 | I 93.1 | conso 2644 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +10:57:41 | FIN_OFF| PV 5740 | U 50.26 | I 114.8 | conso 2360 | grid 0 | SOC 44 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:57:56 | FIN_OFF| PV 5774 | U 50.12 | I 61.2 | conso 2327 | grid 0 | SOC 45 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:58:11 | FIN_OFF| PV 4755 | U 50.10 | I 61.2 | conso 2336 | grid 0 | SOC 45 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:58:26 | FIN_OFF| PV 4824 | U 50.04 | I 48.1 | conso 2350 | grid 0 | SOC 45 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:58:41 | FIN_OFF| PV 5987 | U 50.05 | I 55.6 | conso 2345 | grid 0 | SOC 45 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +10:58:56 | FIN_OFF| PV 6074 | U 50.09 | I 67.5 | conso 2381 | grid 0 | SOC 45 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> RESTAURATION (fin de campagne) +>>> etat restaure : edf off | latch off | hysteresis on diff --git a/docs/mesures/20260831-1101-test-edf-alterne.log b/docs/mesures/20260831-1101-test-edf-alterne.log new file mode 100644 index 0000000..6b526d3 --- /dev/null +++ b/docs/mesures/20260831-1101-test-edf-alterne.log @@ -0,0 +1,92 @@ +TEST ALTERNE EDF <-> MPPT — 31/08/2026 11:01:00 +phases 240s, echantillon 15s, sequence OFF_1 / ON_1 / OFF_2 / ON_2 / FIN_OFF +etat initial : edf off | latch off | hysteresis on +consigne reseau 50 W | SOC min ESS 20 % | limite active 20.0 % +MPPT ordre: mppt1 rs_1 rs_2 rs_3 rs_4 rs_g v1 (MPPT=cherche le max, lim_=se retient) + +11:01:02 | OFF_1 | PV 5200 | U 50.09 | I 48.2 | conso 2275 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:01:17 | OFF_1 | PV 6109 | U 50.11 | I 60.3 | conso 2279 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:01:32 | OFF_1 | PV 5632 | U 50.19 | I 84.3 | conso 1983 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:01:47 | OFF_1 | PV 8639 | U 50.35 | I 131.3 | conso 2108 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | volt volt volt volt MPPT volt volt +11:02:02 | OFF_1 | PV 8510 | U 50.38 | I 126.4 | conso 2372 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:02:18 | OFF_1 | PV 8540 | U 50.33 | I 100.9 | conso 2452 | grid 0 | SOC 46 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:02:33 | OFF_1 | PV 7535 | U 50.30 | I 89.8 | conso 2424 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:02:48 | OFF_1 | PV 6464 | U 50.30 | I 97.3 | conso 2393 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:03:03 | OFF_1 | PV 7018 | U 50.22 | I 74.3 | conso 2400 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:03:18 | OFF_1 | PV 7233 | U 50.28 | I 93.0 | conso 2381 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:03:33 | OFF_1 | PV 8269 | U 50.32 | I 104.7 | conso 2405 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:03:48 | OFF_1 | PV 6161 | U 50.29 | I 84.4 | conso 2395 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:04:03 | OFF_1 | PV 5965 | U 50.20 | I 58.6 | conso 2404 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:04:18 | OFF_1 | PV 6338 | U 50.22 | I 77.2 | conso 2397 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:04:33 | OFF_1 | PV 6878 | U 50.22 | I 75.6 | conso 2409 | grid 0 | SOC 47 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:04:48 | OFF_1 | PV 6276 | U 50.20 | I 66.7 | conso 2394 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF ON +11:05:06 | ON_1 | PV 5262 | U 50.16 | I 61.4 | conso 2452 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:05:21 | ON_1 | PV 5674 | U 50.13 | I 57.5 | conso 2458 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:05:36 | ON_1 | PV 5740 | U 50.10 | I 54.3 | conso 2410 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:05:51 | ON_1 | PV 6539 | U 50.18 | I 78.4 | conso 2083 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:06:06 | ON_1 | PV 7018 | U 50.23 | I 80.1 | conso 2107 | grid 0 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:06:21 | ON_1 | PV 5203 | U 50.35 | I 114.4 | conso 2113 | grid 1985 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:06:36 | ON_1 | PV 5126 | U 50.31 | I 93.4 | conso 2107 | grid 1811 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:06:52 | ON_1 | PV 4853 | U 50.29 | I 90.0 | conso 2131 | grid 1603 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:07:07 | ON_1 | PV 4935 | U 50.26 | I 78.6 | conso 2184 | grid 1418 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:07:22 | ON_1 | PV 5147 | U 50.23 | I 74.6 | conso 2140 | grid 1135 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:07:37 | ON_1 | PV 5535 | U 50.26 | I 84.6 | conso 2120 | grid 939 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:07:52 | ON_1 | PV 4455 | U 50.21 | I 62.1 | conso 2079 | grid 659 | SOC 48 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:08:07 | ON_1 | PV 4105 | U 50.14 | I 50.5 | conso 2086 | grid 445 | SOC 49 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:08:22 | ON_1 | PV 4116 | U 50.08 | I 42.0 | conso 2160 | grid 307 | SOC 49 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:08:37 | ON_1 | PV 5153 | U 50.09 | I 50.3 | conso 2070 | grid 25 | SOC 49 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:08:52 | ON_1 | PV 4488 | U 50.09 | I 48.3 | conso 2067 | grid 25 | SOC 49 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF OFF +11:09:10 | OFF_2 | PV 4483 | U 50.06 | I 38.3 | conso 2314 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:09:25 | OFF_2 | PV 4953 | U 50.05 | I 41.6 | conso 2305 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:09:40 | OFF_2 | PV 6915 | U 50.10 | I 58.7 | conso 2304 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:09:55 | OFF_2 | PV 6850 | U 50.19 | I 76.7 | conso 2310 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:10:10 | OFF_2 | PV 6174 | U 50.22 | I 76.9 | conso 2309 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:10:25 | OFF_2 | PV 5937 | U 50.16 | I 59.6 | conso 2374 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:10:40 | OFF_2 | PV 6519 | U 50.17 | I 64.4 | conso 2319 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:10:55 | OFF_2 | PV 5987 | U 50.22 | I 74.4 | conso 2340 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:11:10 | OFF_2 | PV 4922 | U 50.15 | I 51.5 | conso 2381 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:11:25 | OFF_2 | PV 5392 | U 50.10 | I 43.9 | conso 2361 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:11:40 | OFF_2 | PV 5504 | U 50.16 | I 62.3 | conso 2347 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:11:55 | OFF_2 | PV 6235 | U 50.17 | I 67.1 | conso 2324 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:12:11 | OFF_2 | PV 7208 | U 50.26 | I 84.7 | conso 2330 | grid 0 | SOC 49 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:12:26 | OFF_2 | PV 5227 | U 50.24 | I 69.9 | conso 2350 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:12:41 | OFF_2 | PV 4526 | U 50.14 | I 44.0 | conso 2371 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:12:56 | OFF_2 | PV 3986 | U 50.11 | I 40.1 | conso 4229 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF ON +11:13:14 | ON_2 | PV 4963 | U 50.05 | I 38.8 | conso 2398 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:13:29 | ON_2 | PV 5666 | U 50.07 | I 41.0 | conso 2369 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:13:44 | ON_2 | PV 5415 | U 50.14 | I 59.1 | conso 2374 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:13:59 | ON_2 | PV 6240 | U 50.14 | I 62.6 | conso 2380 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:14:14 | ON_2 | PV 7346 | U 50.24 | I 87.1 | conso 2635 | grid 0 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:14:29 | ON_2 | PV 7398 | U 50.47 | I 142.9 | conso 2730 | grid 2600 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:14:44 | ON_2 | PV 6944 | U 50.48 | I 129.5 | conso 2495 | grid 2190 | SOC 50 | DVCC 130A/51.5V | acin 1 | edf on | volt MPPT MPPT MPPT MPPT MPPT volt +11:14:59 | ON_2 | PV 7122 | U 50.50 | I 127.0 | conso 2498 | grid 1949 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:15:14 | ON_2 | PV 7312 | U 50.52 | I 126.2 | conso 2540 | grid 1806 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:15:29 | ON_2 | PV 7540 | U 50.53 | I 126.8 | conso 2482 | grid 1536 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:15:44 | ON_2 | PV 7966 | U 50.54 | I 123.9 | conso 2515 | grid 1237 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:15:59 | ON_2 | PV 8017 | U 50.54 | I 121.3 | conso 2503 | grid 1094 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt MPPT +11:16:14 | ON_2 | PV 8456 | U 50.56 | I 123.5 | conso 2499 | grid 828 | SOC 51 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:16:29 | ON_2 | PV 8592 | U 50.57 | I 125.9 | conso 2116 | grid 277 | SOC 52 | DVCC 130A/51.5V | acin 1 | edf on | volt volt volt volt MPPT volt volt +11:16:44 | ON_2 | PV 8488 | U 50.59 | I 126.8 | conso 2089 | grid 52 | SOC 52 | DVCC 130A/51.5V | acin 1 | edf on | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:16:59 | ON_2 | PV 8759 | U 50.57 | I 121.0 | conso 2092 | grid -41 | SOC 52 | DVCC 130A/51.5V | acin 1 | edf on | volt MPPT MPPT MPPT MPPT MPPT MPPT +>>> EDF OFF +11:17:17 | FIN_OFF| PV 8921 | U 50.58 | I 127.5 | conso 2058 | grid 0 | SOC 52 | DVCC 130A/51.5V | acin 0 | edf off | volt volt volt volt MPPT volt volt +11:17:32 | FIN_OFF| PV 8483 | U 50.58 | I 126.6 | conso 2054 | grid 0 | SOC 52 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:17:47 | FIN_OFF| PV 8296 | U 50.57 | I 121.9 | conso 2024 | grid 0 | SOC 52 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:18:02 | FIN_OFF| PV 7904 | U 50.57 | I 122.9 | conso 2024 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:18:17 | FIN_OFF| PV 8785 | U 50.59 | I 128.9 | conso 2025 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | volt volt volt volt MPPT volt volt +11:18:32 | FIN_OFF| PV 8128 | U 50.60 | I 125.2 | conso 2028 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:18:48 | FIN_OFF| PV 8287 | U 50.61 | I 127.3 | conso 2018 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:19:03 | FIN_OFF| PV 6198 | U 50.50 | I 90.7 | conso 2021 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:19:18 | FIN_OFF| PV 8660 | U 50.47 | I 89.1 | conso 2012 | grid 0 | SOC 53 | DVCC 130A/51.5V | acin 0 | edf off | volt volt volt volt MPPT volt MPPT +11:19:33 | FIN_OFF| PV 8310 | U 50.58 | I 120.2 | conso 2019 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:19:48 | FIN_OFF| PV 8015 | U 50.59 | I 118.9 | conso 2317 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT MPPT MPPT MPPT MPPT +11:20:03 | FIN_OFF| PV 8740 | U 50.55 | I 111.1 | conso 2364 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | MPPT MPPT MPPT volt volt volt MPPT +11:20:18 | FIN_OFF| PV 9047 | U 50.61 | I 121.6 | conso 2392 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:20:33 | FIN_OFF| PV 9009 | U 50.64 | I 124.3 | conso 2343 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT MPPT +11:20:48 | FIN_OFF| PV 9155 | U 50.64 | I 122.4 | conso 2459 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | volt MPPT MPPT MPPT MPPT MPPT volt +11:21:03 | FIN_OFF| PV 9115 | U 50.66 | I 127.1 | conso 2343 | grid 0 | SOC 54 | DVCC 130A/51.5V | acin 0 | edf off | MPPT volt volt volt MPPT volt volt +>>> RESTAURATION (fin de campagne) +>>> etat restaure : edf off | latch off | hysteresis on diff --git a/tools/analyse-test-alterne.mjs b/tools/analyse-test-alterne.mjs new file mode 100644 index 0000000..b181259 --- /dev/null +++ b/tools/analyse-test-alterne.mjs @@ -0,0 +1,119 @@ +#!/usr/bin/env node +// Resume par phase d'un journal produit par tools/test-edf-alterne.mjs. +// Usage: node tools/analyse-test-alterne.mjs docs/mesures/.log [secondesIgnorees] +// +// Les N premieres secondes de chaque phase sont ignorees par defaut (90 s) : +// la bascule du contacteur met ~30 a 90 s a s'etablir, et inclure le transitoire +// ecraserait l'ecart qu'on cherche a mesurer. + +import fs from 'node:fs'; + +const file = process.argv[2]; +const SKIP = Number(process.argv[3] ?? 90); +const lines = fs.readFileSync(file, 'utf8').split('\n'); + +const rows = []; +for (const l of lines) { + const m = l.match( + // Le bloc des modes MPPT est le DERNIER champ : on l'ancre sur "edf on|off", + // jamais sur le mot MPPT. Ancrer sur "MPPT " faisait tomber en silence toute + // ligne dont le PREMIER tracker etait bride -- c'est-a-dire precisement les + // echantillons a mesurer -- et biaisait le resultat vers "aucun bridage". + /^(\d{2}:\d{2}:\d{2}) \| (\w+)\s*\| PV\s+(-?\d+) \| U\s+([\d.]+) \| I\s+(-?[\d.]+) \| conso\s+(-?\d+) \| grid\s+(-?\d+) \| SOC\s+(\d+).*\| edf (?:on|off) \| (.*)$/ + ); + if (!m) continue; + const [, t, phase, pv, u, i, conso, grid, soc, modes] = m; + rows.push({ + t, phase, + pv: +pv, u: +u, i: +i, conso: +conso, grid: +grid, soc: +soc, + lim: modes.trim().split(/\s+/).filter((m) => m !== 'MPPT').length, + sec: (+t.slice(0, 2)) * 3600 + (+t.slice(3, 5)) * 60 + (+t.slice(6, 8)), + }); +} + +const order = []; +const byPhase = new Map(); +for (const r of rows) { + if (!byPhase.has(r.phase)) { byPhase.set(r.phase, []); order.push(r.phase); } + byPhase.get(r.phase).push(r); +} + +const avg = (a, k) => (a.length ? a.reduce((s, x) => s + x[k], 0) / a.length : NaN); +const n = (x, d = 0) => (Number.isFinite(x) ? x.toFixed(d) : '—'); + +console.log(`Journal : ${file} (${rows.length} echantillons, ${SKIP}s de transitoire ignorees par phase)\n`); +console.log('phase n | PV moy | PV max | conso | grid | I bat | SOC | trackers brides'); +console.log('---------------------------------------------------------------------------------'); +const summary = []; +for (const p of order) { + const all = byPhase.get(p); + const t0 = all[0].sec; + const a = all.filter((r) => r.sec - t0 >= SKIP); + const use = a.length ? a : all; + const s = { + phase: p, n: use.length, + pv: avg(use, 'pv'), pvmax: Math.max(...use.map((r) => r.pv)), + conso: avg(use, 'conso'), grid: avg(use, 'grid'), i: avg(use, 'i'), + soc: avg(use, 'soc'), lim: avg(use, 'lim'), + }; + summary.push(s); + console.log( + `${p.padEnd(8)}${String(s.n).padStart(3)} |${n(s.pv).padStart(9)} |${n(s.pvmax).padStart(8)} |` + + `${n(s.conso).padStart(8)} |${n(s.grid).padStart(7)} |${n(s.i, 1).padStart(7)} |${n(s.soc, 1).padStart(5)} |` + + `${n(s.lim, 1).padStart(9)} / 7` + ); +} + +const off = summary.filter((s) => !s.phase.startsWith('ON')); +const on = summary.filter((s) => s.phase.startsWith('ON')); + +// --- garde meteo ------------------------------------------------------------- +// Les phases OUVERTES sont toutes censees voir la meme ressource solaire. Si +// elles ne s'accordent pas entre elles, c'est le ciel qui a change pendant la +// campagne : la moyenne ON contre moyenne OFF devient ininterpretable, et il ne +// faut surtout pas la presenter comme un resultat (piege rencontre le 27/08 au +// premier test, et de nouveau le 31/08). +const pvOffs = off.map((s) => s.pv); +const spread = Math.max(...pvOffs) - Math.min(...pvOffs); +const spreadPct = (spread / (pvOffs.reduce((a, b) => a + b, 0) / pvOffs.length)) * 100; + +console.log('\n--- STABILITE DE LA RESSOURCE ---'); +console.log(`PV moyenne des phases OUVERTES : ${off.map((s) => `${s.phase} ${n(s.pv)} W`).join(' | ')}`); +console.log(`Ecart entre phases ouvertes : ${n(spread)} W (${n(spreadPct, 1)} % de la moyenne)`); +const meteoStable = spreadPct < 15; +console.log(meteoStable + ? '=> ressource stable : la comparaison globale ON/OFF est exploitable.' + : '=> RESSOURCE INSTABLE (nuages) : la comparaison globale ON/OFF n est PAS exploitable.\n Se fier uniquement aux transitions ci-dessous, phase par phase.'); + +// --- comparaison locale : chaque ON contre ses voisines OFF ------------------- +console.log('\n--- TRANSITIONS (chaque phase fermee contre ses voisines ouvertes) ---'); +for (const s of on) { + const idx = order.indexOf(s.phase); + const voisins = summary.filter((x) => Math.abs(order.indexOf(x.phase) - idx) === 1 && !x.phase.startsWith('ON')); + if (!voisins.length) continue; + const ref = voisins.reduce((a, x) => a + x.pv, 0) / voisins.length; + const d = s.pv - ref; + const pct = (d / ref) * 100; + console.log( + `${s.phase} : PV ${n(s.pv)} W contre ${n(ref)} W chez ${voisins.map((v) => v.phase).join('+')}` + + ` => ${d >= 0 ? '+' : ''}${n(d)} W (${pct >= 0 ? '+' : ''}${n(pct, 1)} %)` + + ` | import ${n(s.grid)} W | trackers brides ${n(s.lim, 1)}/7` + ); +} + +console.log('\n--- VERDICT ---'); +if (!meteoStable) { + console.log('Campagne partiellement inexploitable (ressource instable).'); + console.log('Verifier a la main, sur le journal brut, si la chute de PV precede ou suit'); + console.log('l apparition de l import reseau : si elle la PRECEDE, ce sont des nuages.'); +} else { + const pvOff = pvOffs.reduce((a, b) => a + b, 0) / pvOffs.length; + const pvOn = on.reduce((a, s) => a + s.pv, 0) / on.length; + const gOn = on.reduce((a, s) => a + s.grid, 0) / on.length; + const pct = ((pvOn - pvOff) / pvOff) * 100; + console.log(`PV ouverte ${n(pvOff)} W | PV fermee ${n(pvOn)} W | ecart ${pct >= 0 ? '+' : ''}${n(pct, 1)} %`); + console.log(Math.abs(pct) < 10 + ? '=> PAS DE SUBSTITUTION : la production ne depend pas de la presence du reseau.' + : '=> SUBSTITUTION : la production chute quand le reseau est la.'); + console.log(`Import moyen en phase fermee : ${n(gOn)} W (consigne ESS ~50 W attendue si le solaire couvre tout).`); +} diff --git a/tools/test-edf-alterne.mjs b/tools/test-edf-alterne.mjs new file mode 100644 index 0000000..519b86e --- /dev/null +++ b/tools/test-edf-alterne.mjs @@ -0,0 +1,157 @@ +#!/usr/bin/env node +// Campagne de test EDF <-> MPPT, protocole ALTERNE. +// +// Usage: node tools/test-edf-alterne.mjs [phaseSec] [sampleSec] +// node tools/test-edf-alterne.mjs 180 15 (defaut) +// +// Protocole : OFF / ON / OFF / ON / OFF, phases de duree egale, echantillon +// regulier. L'alternance est ce qui rend la mesure interpretable : une derive +// meteo monotone ne peut pas produire un signal qui suit le contacteur quatre +// fois de suite. +// +// Ce que le script mesure a chaque echantillon : PV totale, tension et courant +// batterie, consommation maison, import reseau, SOC, limite DVCC, presence +// physique AC-IN, et le mode de fonctionnement des 7 chargeurs solaires +// (mppt_active = cherche son point de puissance maximale ; sinon il se retient). +// +// SECURITE : l'hysteresis reseau est desactivee pendant le test puis restauree, +// ainsi que le latch et l'etat du contacteur. La restauration est faite aussi +// sur Ctrl-C et sur erreur. + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const HA = process.env.HA_URL || 'http://10.10.10.17:8123'; + +function loadToken() { + if (process.env.HA_TOKEN) return process.env.HA_TOKEN; + const m = fs.readFileSync(path.join(ROOT, '.env'), 'utf8').match(/^\s*HA_TOKEN\s*=\s*(.+?)\s*$/m); + if (!m) { console.error('HA_TOKEN absent de .env'); process.exit(1); } + return m[1].replace(/^["']|["']$/g, ''); +} +const TOKEN = loadToken(); +const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }; + +const get = async (id) => { + const r = await fetch(`${HA}/api/states/${id}`, { headers: H }); + if (!r.ok) return null; + return (await r.json()).state; +}; +const call = async (svc, data) => { + const [d, s] = svc.split('.'); + const r = await fetch(`${HA}/api/services/${d}/${s}`, { method: 'POST', headers: H, body: JSON.stringify(data) }); + if (!r.ok) throw new Error(`${svc} -> HTTP ${r.status} ${await r.text()}`); +}; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +// --- entites ----------------------------------------------------------------- +const MPPT = [ + ['mppt1', 'sensor.airtria_mppt1_mppt_operation_mode'], + ['rs_1', 'sensor.mppt_450_200_hq2449yr9pt_pv_tracker_solar_1_operation_mode'], + ['rs_2', 'sensor.mppt_450_200_hq2449yr9pt_pv_tracker_solar_2_operation_mode'], + ['rs_3', 'sensor.mppt_450_200_hq2449yr9pt_pv_tracker_solar_3_operation_mode'], + ['rs_4', 'sensor.mppt_450_200_hq2449yr9pt_pv_tracker_solar_4_operation_mode'], + ['rs_g', 'sensor.mppt_450_200_hq2449yr9pt_mppt_operation_mode'], + ['v1', 'sensor.v1_mppt_operation_mode'], +]; +const M = { + pv: 'sensor.victron_pv_power_system', + u: 'sensor.victron_battery_voltage', + i: 'sensor.victron_battery_current', + conso: 'sensor.victron_consumption_power_l1', + grid: 'sensor.victron_grid_power_l1', + soc: 'sensor.victron_battery_soc', + dvcc_a: 'sensor.victron_max_charge_current_setting', + dvcc_v: 'sensor.victron_max_charge_voltage_setting', + acin: 'sensor.victron_ac_in1_available', + edf: 'switch.edf_general_ok_switch', + mode: 'input_text.victron_charge_mode', +}; +const HYST = 'input_boolean.victron_grid_hysteresis_enabled'; +const LATCH = 'input_boolean.victron_grid_hysteresis_latch'; + +const PHASE_SEC = Number(process.argv[2] || 180); +const SAMPLE_SEC = Number(process.argv[3] || 15); +const PHASES = ['OFF_1', 'ON_1', 'OFF_2', 'ON_2', 'FIN_OFF']; + +const stamp = () => new Date().toLocaleTimeString('fr-FR', { timeZone: 'Europe/Paris' }); +const out = []; +const say = (l) => { console.log(l); out.push(l); }; + +// --- restauration ------------------------------------------------------------ +let initial = null; +let restored = false; +async function restore(why) { + if (restored || !initial) return; + restored = true; + say(`>>> RESTAURATION (${why})`); + try { + await call('switch.turn_off', { entity_id: M.edf }); + await call(`input_boolean.turn_${initial.latch}`, { entity_id: LATCH }); + await call(`input_boolean.turn_${initial.hyst}`, { entity_id: HYST }); + say(`>>> etat restaure : edf off | latch ${initial.latch} | hysteresis ${initial.hyst}`); + } catch (e) { + say(`!!! ECHEC RESTAURATION : ${e.message} — VERIFIER A LA MAIN ${M.edf}, ${LATCH}, ${HYST}`); + } +} +process.on('SIGINT', async () => { await restore('Ctrl-C'); process.exit(130); }); + +// --- deroule ----------------------------------------------------------------- +initial = { + hyst: (await get(HYST)) === 'on' ? 'on' : 'off', + latch: (await get(LATCH)) === 'on' ? 'on' : 'off', + edf: await get(M.edf), +}; + +say(`TEST ALTERNE EDF <-> MPPT — ${new Date().toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })}`); +say(`phases ${PHASE_SEC}s, echantillon ${SAMPLE_SEC}s, sequence ${PHASES.join(' / ')}`); +say(`etat initial : edf ${initial.edf} | latch ${initial.latch} | hysteresis ${initial.hyst}`); +say(`consigne reseau ${await get('number.gx_device_ac_power_setpoint')} W | SOC min ESS ${await get('number.gx_device_ess_min_soc_limit')} % | limite active ${await get('sensor.gx_device_active_soc_limit')} %`); +say(`MPPT ordre: ${MPPT.map((m) => m[0]).join(' ')} (MPPT=cherche le max, lim_=se retient)`); +say(''); + +try { + await call('input_boolean.turn_off', { entity_id: HYST }); + await call('switch.turn_off', { entity_id: M.edf }); + await sleep(2000); + + for (const phase of PHASES) { + const want = phase.startsWith('ON') ? 'on' : 'off'; + if ((await get(M.edf)) !== want) { + say(`>>> EDF ${want.toUpperCase()}`); + await call(`switch.turn_${want}`, { entity_id: M.edf }); + await sleep(3000); + } + const t0 = Date.now(); + while (Date.now() - t0 < PHASE_SEC * 1000) { + const v = {}; + await Promise.all(Object.entries(M).map(async ([k, id]) => { v[k] = await get(id); })); + const modes = await Promise.all(MPPT.map(async ([, id]) => { + const s = await get(id); + return s === 'mppt_active' ? 'MPPT' : (s || 'n/a').slice(0, 4).padEnd(4); + })); + const n = (x, d = 0) => (Number.isFinite(Number(x)) ? Number(x).toFixed(d) : String(x)); + say( + `${stamp()} | ${phase.padEnd(7)}| PV ${n(v.pv).padStart(5)} | U ${n(v.u, 2).padStart(5)}` + + ` | I ${n(v.i, 1).padStart(6)} | conso ${n(v.conso).padStart(5)} | grid ${n(v.grid).padStart(5)}` + + ` | SOC ${n(v.soc)} | DVCC ${n(v.dvcc_a)}A/${n(v.dvcc_v, 1)}V | acin ${v.acin} | edf ${v.edf}` + + ` | ${modes.join(' ')}` + ); + await sleep(SAMPLE_SEC * 1000); + } + } +} catch (e) { + say(`!!! ERREUR : ${e.message}`); +} finally { + await restore('fin de campagne'); +} + +// Le nom porte la date ET l'heure : deux campagnes le meme jour ne doivent pas +// s'ecraser l'une l'autre (piege rencontre le 31/08). +const now = new Date(); +const hhmm = now.toLocaleTimeString('fr-FR', { timeZone: 'Europe/Paris', hour: '2-digit', minute: '2-digit' }).replace(':', ''); +const dest = path.join(ROOT, 'docs/mesures', `${now.toISOString().slice(0, 10).replace(/-/g, '')}-${hhmm}-test-edf-alterne.log`); +fs.writeFileSync(dest, out.join('\n') + '\n'); +console.log(`\nJournal : ${dest}`);