Chantier etape 5 : bilan energetique publie en mode ombre
Workflow n8n "EVCS Energy Balance V1" (id QoSfPeyGq35orF1K), actif, cycle de 5 min : snapshot HA -> CENSORSHIP et RESOURCE_ESTIMATE en parallele -> PREPARE_BALANCE -> BALANCE -> BUILD_HA_CALLS -> appels de service HA. MODE OMBRE garanti structurellement : BUILD_HA_CALLS n'ecrit que vers des entites evcs_balance_* plus une trace logbook. La suite de tests echoue si une ecriture sort de ce perimetre — verifie par mutation, l'injection d'un turn_on sur switch.edf_general_ok_switch fait rougir la suite. Kill-switch input_boolean.evcs_balance_enabled : a OFF, aucune ecriture du tout. Package HA evcs_energy_balance.yaml : 18 helpers. Profils de consommation, enveloppe de production et taux de censure amorces avec les valeurs calculees sur 28 jours reels ; capacite utile posee a 15 kWh (7 modules actifs). Outillage : gen-energy-balance-workflow.mjs, enregistrement dans lib-node-map.mjs, suite cablee dans n8n-push.mjs (bloquante). Suite a 24 scenarios. Premiere execution reelle : le bilan s'est declare indisponible faute d'entrees, exactement comme prevu, au lieu d'inventer des valeurs. Le format du snapshot (corps JSON dans `data`) et la lecture des profils CSV ont ete corriges ensuite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
53
src/energy-balance/PREPARE_BALANCE.js
Normal file
53
src/energy-balance/PREPARE_BALANCE.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// EVCS Energy Balance — PREPARE_BALANCE
|
||||
// =====================================================================
|
||||
// Colle de câblage n8n, et rien d'autre. Les nœuds de calcul (CENSORSHIP,
|
||||
// RESOURCE_ESTIMATE, BALANCE) sont volontairement écrits pour ne lire que
|
||||
// `$input`, afin de rester testables hors de n8n. Ce nœud rassemble donc ce
|
||||
// que BALANCE attend, en puisant dans les nœuds précédents.
|
||||
//
|
||||
// Il fait aussi la seule conversion nécessaire : les profils horaires vivent
|
||||
// dans des helpers `input_text` sous forme de CSV compact (24 valeurs, moins
|
||||
// de 255 caractères), il faut les redonner sous forme de tableaux.
|
||||
// =====================================================================
|
||||
|
||||
function parseCsv24(raw) {
|
||||
if (typeof raw !== 'string') return null;
|
||||
const parts = raw.split(',').map(v => Number.parseFloat(v.trim()));
|
||||
if (parts.length !== 24 || parts.some(v => !Number.isFinite(v))) return null;
|
||||
return parts;
|
||||
}
|
||||
|
||||
// Le nœud HTTP de n8n renvoie le corps du template dans `data`, sous forme de
|
||||
// chaîne. Hors n8n (tests), l'objet arrive déjà décodé — on accepte les deux.
|
||||
function unwrapSnapshot(raw) {
|
||||
if (raw && typeof raw.data === 'string') {
|
||||
try { return JSON.parse(raw.data); } catch { return raw; }
|
||||
}
|
||||
return (raw && raw.data) || raw;
|
||||
}
|
||||
|
||||
const snapshot = unwrapSnapshot($('HA Snapshot Balance').first().json);
|
||||
const resource = $input.first().json;
|
||||
|
||||
return [{
|
||||
json: {
|
||||
nowMs: Number.parseFloat(snapshot.nowMs),
|
||||
|
||||
consumption_p50: parseCsv24(snapshot.consumption_p50_csv),
|
||||
consumption_p80: parseCsv24(snapshot.consumption_p80_csv),
|
||||
|
||||
horizon: resource.horizon || [],
|
||||
|
||||
soc_percent: snapshot.soc_percent,
|
||||
usable_capacity_kwh: snapshot.usable_capacity_kwh,
|
||||
// Plancher dur : même valeur de repli que INPUT_PARSE.js
|
||||
// (evcs_night_battery_hard_floor_pct n'est aujourd'hui exposé par AUCUN
|
||||
// helper — la valeur « 22 % » documentée partout est en réalité un défaut
|
||||
// de code, cf. backlog du chantier).
|
||||
soc_floor_percent: 22,
|
||||
|
||||
// Repris pour l'écriture des helpers, sans influencer le calcul.
|
||||
resourceUsable: resource.usable,
|
||||
shapeConfidence: resource.source ? resource.source.shapeConfidence : null,
|
||||
},
|
||||
}];
|
||||
Reference in New Issue
Block a user