P7: charge HC nuit automatique si véhicule branché + toggle 'Réseau HC nuit' ON

- Root cause 1: battery_assist_night ne démarrait jamais (floor décharge 0A
  impossible la nuit) -> idle_wait_conditions jusqu'à dérive du SOC au trigger.
- Root cause 2: allow_grid_hc_night parsé mais jamais utilisé.
- Fix: nightGridHcPreferred dans WINDOWS_SOURCEV2 + BATTERY_CLOUD_LOCKS ->
  grid_hc_allowed dès l'ouverture de la fenêtre HC (EDF ON auto, ACM hold 2A).
- Toggle OFF = comportement historique. Dry-run 7 scénarios validés.
- Outils: n8n-pull/n8n-push (push REST direct, backup auto, node --check).
- Déployé en production le 07/08/2026 15:45, exécutions vérifiées success.
This commit is contained in:
Tallagrand Thierry
2026-08-07 15:46:49 +02:00
parent 1debfe3c0e
commit 9592ac94ea
4 changed files with 350 additions and 2 deletions

View File

@@ -0,0 +1,114 @@
#!/usr/bin/env node
// Patch 07/08/2026 : charge HC nuit automatique quand un véhicule est branché
// et que le toggle "Réseau HC nuit" (input_boolean.victron_evcs_allow_grid_hc_night) est ON.
// Modifie WINDOWS_SOURCEV2 et BATTERY_CLOUD_LOCKS dans le JSON local du workflow.
import fs from 'fs';
const FILE = 'workflows/evcs-surplus-controller-v2.6.json';
const wf = JSON.parse(fs.readFileSync(FILE, 'utf8'));
function patchNode(nodeName, replacements) {
const node = wf.nodes.find(n => n.name === nodeName);
if (!node) throw new Error(`Node introuvable: ${nodeName}`);
let code = node.parameters.jsCode;
for (const [i, { from, to }] of replacements.entries()) {
if (!code.includes(from)) {
throw new Error(`${nodeName}: pattern #${i + 1} introuvable:\n---\n${from}\n---`);
}
if (code.split(from).length !== 2) {
throw new Error(`${nodeName}: pattern #${i + 1} non unique`);
}
code = code.replace(from, to);
}
node.parameters.jsCode = code;
console.log(`OK: ${nodeName} patché (${replacements.length} remplacement(s))`);
}
const HEADER = `// FIX 07/08/2026 : fenêtre HC nuit + véhicule branché + toggle "Réseau HC nuit" ON
// => préférence réseau HC directe (la VW hybride charge sans intervention manuelle).
// Toggle OFF => comportement historique (battery_assist_night puis takeover à la cible).
const nightGridHcPreferred =
nightSessionActive &&
params.allowGridHcNight;
`;
// ---------- WINDOWS_SOURCEV2 ----------
patchNode('WINDOWS_SOURCEV2', [
{
from: `const batteryAssistAllowed =
nightSessionActive &&
parsed.soc > batteryHardFloorPct &&
parsed.soc > gridTakeoverTriggerPct &&
!nightTakeoverLatched &&
!batteryRecoveryUrgent;`,
to: HEADER + `const batteryAssistAllowed =
nightSessionActive &&
!nightGridHcPreferred &&
parsed.soc > batteryHardFloorPct &&
parsed.soc > gridTakeoverTriggerPct &&
!nightTakeoverLatched &&
!batteryRecoveryUrgent;`
},
{
from: `const nightGridTakeoverNeeded =
nightSessionActive &&
(
batteryBelowHardFloor ||
batteryAtOrBelowGridTakeoverTrigger ||
batteryRecoveryUrgent ||
nightTakeoverLatched
);`,
to: `const nightGridTakeoverNeeded =
nightSessionActive &&
(
nightGridHcPreferred ||
batteryBelowHardFloor ||
batteryAtOrBelowGridTakeoverTrigger ||
batteryRecoveryUrgent ||
nightTakeoverLatched
);`
}
]);
// ---------- BATTERY_CLOUD_LOCKS ----------
patchNode('BATTERY_CLOUD_LOCKS', [
{
from: `const batteryAssistAllowed =
nightSessionActive &&
!batteryBelowHardFloor &&
!batteryRecoveryUrgent &&
!nightTakeoverLatched &&
parsed.soc > gridTakeoverTriggerPct;`,
to: HEADER + `const batteryAssistAllowed =
nightSessionActive &&
!nightGridHcPreferred &&
!batteryBelowHardFloor &&
!batteryRecoveryUrgent &&
!nightTakeoverLatched &&
parsed.soc > gridTakeoverTriggerPct;`
},
{
from: `const nightGridTakeoverNeeded =
nightSessionActive &&
(
batteryBelowHardFloor ||
batteryAtOrBelowGridTakeoverTrigger ||
batteryRecoveryUrgent ||
nightTakeoverLatched
);`,
to: `const nightGridTakeoverNeeded =
nightSessionActive &&
(
nightGridHcPreferred ||
batteryBelowHardFloor ||
batteryAtOrBelowGridTakeoverTrigger ||
batteryRecoveryUrgent ||
nightTakeoverLatched
);`
}
]);
fs.writeFileSync(FILE, JSON.stringify(wf, null, 2) + '\n');
console.log(`Écrit: ${FILE}`);