From 0d91819577f442830a9cb518dea198b5aef06519 Mon Sep 17 00:00:00 2001 From: Tallagrand Thierry Date: Fri, 12 Jun 2026 02:12:45 +0200 Subject: [PATCH] docs: Add HANDOFF.md for outside-window solar charging block analysis --- HANDOFF.md | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 HANDOFF.md diff --git a/HANDOFF.md b/HANDOFF.md new file mode 100644 index 0000000..15307a6 --- /dev/null +++ b/HANDOFF.md @@ -0,0 +1,198 @@ +# HANDOFF.md — EVCS Outside-Window Solar Charging Block + +## 1. Contexte Projet + +- **Installation** : Victron ESS sans injection réseau. Batterie 17,5 kWh. +- **Workflow actif** : `HA Snapshot EVCS Surplus Controller V2.5` (n8n) +- **Code source** : `/mnt/projects/EVCS/EVCS/decoupesurplus/` (architecture modulaire V2) +- **Fichiers critiques** : + - `WINDOWS/WINDOW_SOURCEV2.js` — Détermine `profile` et `sourceMode` + - `BATTERY/BATTERY_CLOUD_LOCKS.js` — Calcule `cloudDebt`, `cloudToleranceOk` + - `DECISION/DECISION_ENGINEV2.js` — Arbre de décision final + - `HYSTERESIS/COMPUTE.js` — Step-up / step-down + - `modified/EVCS_V2.5_PATCHED.json` — Export n8n de production + +## 2. Architecture Data-Flow + +``` +Schedule Trigger (30s) + → HA Snapshot (template) + → INPUT_PARSE + → WINDOWS_SOURCEV2 ← C'EST ICI QUE LE BLOCAGE SE PRODUIT + → BATTERY_CLOUD_LOCKS + → DECISION_ENGINEV2 + → HA_SERVICE_CALLS_OUTPUT + → Execute HA Service +``` + +## 3. Problème Observé + +### Symptôme +L'après-midi, avec un fort ensoleillement et un SOC élevé (> 85 %), l'EVCS reste en : +- **Profil** : `outside_window` +- **Décision** : `stop_hard` ou `hold` / `blocked` +- **Source** : `Bloqué` +- **Action utilisateur requise** : Forcer manuellement `force_charge_now` + +### Capture d'état typique +``` +Stratégie : auto_solar_plus +Profil : outside_window +Source : Bloqué +SOC : 91 % +Cloud Debt: 1.66 kWh +PV Power : ~800 W (aligné sur charge maison, pas d'injection) +Decision : stop_hard | battery_current_hard_stop +``` + +**Note contextuelle importante** : L'utilisateur a attendu ~45 min sans succès, puis a volontairement passé en `force_charge_now` pour charger sa moto électrique. Ce forçage a fait tirer sur les batteries à cause des nuages, augmentant encore le `cloud_debt`. + +## 4. Root Cause Analysis + +### 4.1. Définition de outside_window +`outside_window` = tout horaire **hors** des 4 fenêtres configurées : +- `night_hc` : 23:00 → 06:00 +- `morning_solar` : 07:30 → 11:00 +- `midday_hc_or_solar` : 12:24 → 14:24 +- `evening_high_soc` : 17:00 → 20:30 + +Donc `outside_window` couvre : **11:00→12:24, 14:24→17:00, 20:30→23:00**. + +### 4.2. Logique du sourceMode en outside_window (WINDOW_SOURCEV2.js, L454-468) + +```javascript +else if (profile === 'outside_window') { + if (strongSolarSignal) { + sourceMode = 'solar_only'; + } else if (isHighBatteryForPotential && potentialAllowed) { + sourceMode = 'solar_potential'; + } else { + sourceMode = 'blocked'; // ← TOMBE ICI + } +} +``` + +Pour sortir de `blocked`, il faut **obligatoirement** l'un des deux : + +#### A. strongSolarSignal (L343-352) +```javascript +const strongSolarSignal = + (parsed.pvPowerW > 0 && parsed.pvPowerW >= effectivePvStartMinW) || + parsed.pvPowerAvg10mW >= params.pvHoldMinW || + (departurePriorityActive && parsed.pvPowerAvg10mW >= params.pvHoldMinW); +``` +- `pvStartMinW` défaut = **1800 W** +- `pvHoldMinW` défaut = **1200 W** + +**Pourquoi c'est faux chez l'utilisateur** : +Comme il n'injecte pas, quand SOC > 85 % et charge maison = 800 W, le MPPT régule les PV à ~800 W. Ni `pvPowerW`, ni `pvPowerAvg10mW` ne dépassent les seuils. + +#### B. isHighBatteryForPotential (L335-339) +```javascript +const isHighBatteryForPotential = + parsed.soc >= 85 && + forecastBufferKwh > 0 && + cloudDebtOkForPotential && // ← BLOQUÉ ICI + batteryOkForPotential; +``` + +**Pourquoi c'est faux chez l'utilisateur** : +```javascript +const cloudDebtOkForPotential = params.cloudDebtPrevKwh <= params.cloudDebtMaxKwh; +// cloudDebtPrevKwh = 1.66 kWh +// cloudDebtMaxKwh = 1.2 kWh (défaut) +// → cloudDebtOkForPotential = FALSE +``` + +**Donc `isHighBatteryForPotential` est FORCÉMENT FALSE**, même avec SOC 91 %. + +### 4.3. Pourquoi le cloud debt est à 1.66 kWh +Le `cloud_debt` s'accumule quand : +- Session EVCS active +- `sourceMode` n'est PAS `grid_hc_allowed` (donc solaire ou batterie) +- `batteryCurrentA < -neutralBand` (batterie qui décharge) + +Sur une journée nuageuse avec intermittences, l'EVCS a démarré/stoppé plusieurs fois. Pendant les passages nuageux, la batterie a complété la puissance manquante → accumulation de dette. Cette dette ne se rembourse que quand `batteryCurrentA > 0` (batterie en charge). Or, si le système bloque l'EVCS, il n'y a pas de passage à `batteryCurrentA > 0` pendant la charge EVCS, donc la dette reste bloquée haute. + +### 4.4. Absence de probe en outside_window +Les probes (`morningProbeEligible`, `middayProbeEligible`) sont **strictement limitées** aux profiles `morning_solar` et `midday_hc_or_solar` (WINDOW_SOURCEV2.js L317-330). Il n'existe **aucun mécanisme de sonde** en `outside_window` pour tester si le PV peut supporter une charge à 6 A. + +### 4.5. Réseau HC midi / nuit +Les toggles `allow_grid_hc_night` et `allow_grid_hc_midday` ne concernent QUE les fenêtres `night_hc` et `midday_hc_or_solar`. Ils sont **totalement ignorés** en `outside_window`. Ce n'est donc PAS une solution. + +### 4.6. Priorité départ +`departurePriorityActive` s'active seulement si : +- `departurePriorityEnabled = ON` +- `minutesUntilDeparture <= 240 min` +- Véhicule branché + +Effet : facilite `strongSolarSignal` en baissant la barre si `pvPowerAvg10mW >= pvHoldMinW`. Mais ne résout pas le blocage `cloudDebt`. + +## 5. Résumé des Verrous + +| Verrou | Condition | État actuel | Impact | +|--------|-----------|-------------|--------| +| Seuil PV instantané | `pvPowerW >= 1800 W` | ~800 W | `strongSolarSignal = false` | +| Seuil PV moyenne | `pvPowerAvg10mW >= 1200 W` | Souvent < 1200 W | `strongSolarSignal = false` | +| Cloud Debt | `cloudDebt <= 1.2 kWh` | 1.66 kWh | `isHighBatteryForPotential = false` | +| Probe absente | Seulement `morning` / `midday` | N/A en afternoon | Aucun test de démarrage | +| Réseau HC | Ignoré hors fenêtre | N/A | Pas de fallback grid | + +## 6. Options de Correction Envisagées + +### Option A — Relâcher `cloudDebtOkForPotential` en `outside_window` +Dans `WINDOW_SOURCEV2.js`, ignorer la condition `cloudDebtOkForPotential` pour le calcul de `isHighBatteryForPotential` quand `profile === 'outside_window'`. + +**Avantage** : Simple, 1 ligne. +**Risque** : Peut entraîner une décharge excessive de la batterie si le PV baisse brutalement. + +### Option B — Ajouter une `afternoon_probe` en `outside_window` (RECOMMANDÉ) +Créer une logique de sonde (probe) active en `outside_window` lorsque `auto_solar_plus` est sélectionné. Démarrage à 6 A pendant 3 min, puis évaluation. + +**Avantage** : Fidèle à la philosophie du système (ne charge que si le PV confirme). +**Risque** : Nécessite modification de `BATTERY_CLOUD_LOCKS.js` + `DECISION_ENGINEV2.js`. + +### Option C — Ajouter une fenêtre `afternoon_solar` +Étendre la logique des fenêtres pour inclure une plage 14:24→17:00 (ou configurable) avec des seuils PV adaptés. + +**Avantage** : Résout définitivement le "trou" de l'après-midi. +**Risque** : Change la sémantique utilisateur des fenêtres. + +### Option D — Abaisser `pvStartMinW` / `pvHoldMinW` dynamiquement +En `outside_window` + `auto_solar_plus`, baisser les seuils si `soc >= 90` et `forecastBufferKwh > 0`. + +**Avantage** : Adaptatif. +**Risque** : Peut causer des démarrages/stops fréquents si le PV est instable. + +## 7. Prochaines Étapes Recommandées + +1. **Décider** quelle Option (A, B, C ou D) correspond au comportement souhaité. +2. **Vérifier** la valeur exacte de `cloud_debt_max_kwh` dans HA (`input_number.victron_cloud_debt_max_kwh` ou équivalent). +3. **Implémenter** le patch dans le fichier cible : + - Si Option A : `WINDOWS/WINDOW_SOURCEV2.js` + - Si Option B : `WINDOWS/WINDOW_SOURCEV2.js` + `BATTERY_CLOUD_LOCKS.js` + `DECISION_ENGINEV2.js` + - Si Option C : `WINDOWS/WINDOW_SOURCEV2.js` + `INPUT_PARSE.js` + - Si Option D : `WINDOWS/WINDOW_SOURCEV2.js` +4. **Tester** en mode "dry-run" (logique uniquement, pas d'appels HA). +5. **Redéployer** via export/import du workflow n8n. + +## 8. Paramètres Clés à Vérifier dans Home Assistant + +| Paramètre HA | Entité typique | Valeur défaut | Valeur actuelle ? | +|--------------|----------------|---------------|-------------------| +| `pv_start_min_w` | `input_number.victron_pv_start_min_w` | 1800 W | ? | +| `pv_hold_min_w` | `input_number.victron_pv_hold_min_w` | 1200 W | ? | +| `cloud_debt_max_kwh` | `input_number.victron_cloud_debt_max_kwh` | 1.2 kWh | ? | +| `battery_neutral_band_a` | `input_number.victron_battery_neutral_band_a` | 3 A | ? | +| `allow_grid_hc_midday` | `input_boolean.victron_allow_grid_hc_midday` | OFF | ON (actif) | +| `allow_grid_hc_night` | `input_boolean.victron_allow_grid_hc_night` | OFF | ON (actif) | + +## 9. Notes de Version + +- Le workflow V2.5 utilise la chaîne modulaire (`decoupesurplus/`). +- Le fichier `modified/EVCS_V2.5_PATCHED.json` est l'export de production. +- Le fichier `modified/WINDOWS_SOURCEV2_patched.js` existe mais ne semble pas utilisé dans le workflow actif (à vérifier). + +--- +*Document créé le : 12/06/2026* +*Prochaine action : Implémenter l'Option B (afternoon_probe), validation des paramètres HA à suivre*