Files
EVCS/src/energy-balance/PREPARE_BALANCE.js
Tallagrand Thierry be1b12969e Vehicule branche a midi : JEEP, VW et moto ZERO (calendrier, capacite et puissance par vehicule)
ZERO ajoutee au selecteur avec son heure de depart (P9). Le bilan lit la
capacite et la puissance de charge mesurees du vehicule selectionne ; 0 =
inconnue (regle muette / pas de borne). Bilan 64/64, golden 123/123.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-28 14:05:04 +02:00

80 lines
3.6 KiB
JavaScript

// 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,
modules_en_service: snapshot.modules_en_service,
// 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,
// Vigilance Météo-France, lue sans connaître la commune (l'entité
// s'appelle sensor.<commune>_weather_alert). Absente tant que
// l'intégration n'est pas installée : le bilan publie alors
// 'indisponible' et ne change rien.
storm_alert_level: snapshot.storm_alert_level,
storm_alert_detail: snapshot.storm_alert_detail,
// Fenetres HC (28/09, « tenir jusqu'a la prochaine HC ») : horodatages
// calcules par le gabarit depuis les helpers victron_evcs_hc_*. Sans cette
// recopie, BALANCE.js ne les voit pas et la regle reste muette.
// Plancher de charge HC manuelle (18/09) : oublie ici jusqu'au 28/09, le
// bouton n'avait donc jamais atteint le bilan.
manual_hc_floor_percent: snapshot.manual_hc_floor_percent,
// Vehicule branche a midi (28/09, JEEP/VW/ZERO) : depart du jour et besoin saisi.
vehicle_connected: snapshot.vehicle_connected,
vehicle_departure_ms: snapshot.vehicle_departure_ms,
vehicle_level_pct: snapshot.vehicle_level_pct,
vehicle_level_valid: snapshot.vehicle_level_valid,
vehicle_capacity_kwh: snapshot.vehicle_capacity_kwh,
vehicle_charger_kw: snapshot.vehicle_charger_kw,
vehicle_delivered_since_level_kwh: snapshot.vehicle_delivered_since_level_kwh,
hc_window_end_ms: snapshot.hc_window_end_ms,
next_hc_start_ms: snapshot.next_hc_start_ms,
next_night_hc_start_ms: snapshot.next_night_hc_start_ms,
// Repris pour l'écriture des helpers, sans influencer le calcul.
resourceUsable: resource.usable,
shapeConfidence: resource.source ? resource.source.shapeConfidence : null,
},
}];