Jour faible : session HC midi et nuit engagee pour le chauffe-eau ; alerte « passe en BOOST » si pompe a chaleur en HC ; HANDOFF
This commit is contained in:
@@ -175,6 +175,7 @@
|
||||
"balance_status": states("input_text.evcs_balance_status"),
|
||||
"balance_last_run": states("input_text.evcs_balance_last_run"),
|
||||
"balance_vehicle_grid_needed": states("input_boolean.evcs_balance_vehicle_grid_needed"),
|
||||
"balance_ecs_nuit": states("input_boolean.evcs_balance_ecs_nuit"),
|
||||
"allow_grid_hc_midday": states("input_boolean.victron_evcs_allow_grid_hc_midday"),
|
||||
"probe_enabled": states("input_boolean.victron_evcs_probe_enabled"),
|
||||
|
||||
|
||||
@@ -501,6 +501,9 @@ const params = {
|
||||
// Voiture branchee en HC avec un depart avant la prochaine HC (28/09) : le
|
||||
// bilan juge que le solaire ne lui donnera pas son besoin avant le depart.
|
||||
balanceVehicleGridNeeded: low(input.balance_vehicle_grid_needed || 'off') === 'on',
|
||||
// Jour faible (07/10/2026) : decision quotidienne du bilan, l'eau chaude se
|
||||
// fait en HC sur EDF -> la session reseau HC (nuit ET midi) s'engage.
|
||||
balanceEcsNuit: low(input.balance_ecs_nuit || 'off') === 'on',
|
||||
// P12 — charge nuit sur batterie. Le plancher est le SOC requis PRUDENT (p80)
|
||||
// et non le p50 : la marge est mesuree, pas inventee. On descend la voiture
|
||||
// jusqu'a ce que la batterie n'ait plus que ce qu'il lui faut pour tenir
|
||||
|
||||
@@ -763,7 +763,8 @@ const nightGridSessionCommittedPrev =
|
||||
(input.night_grid_session_committed_prev ?? 'off').toString().trim().toLowerCase() === 'on';
|
||||
|
||||
const nightGridSessionUncovered =
|
||||
balanceMorningTargetApplied && batteryBelowMorningTarget;
|
||||
balanceMorningTargetApplied &&
|
||||
(batteryBelowMorningTarget || params.balanceEcsNuit);
|
||||
|
||||
// ⚠️ SANS VEHICULE AUSSI (12/09/2026).
|
||||
// Nuit du 11-12/09, voiture rendue la veille : le bilan a reclame entre 92 %
|
||||
@@ -814,12 +815,23 @@ const middayVehicleGridNeeded =
|
||||
params.balanceVehicleGridNeeded &&
|
||||
parsed.evcsVehicleConnected;
|
||||
|
||||
// ET LE CHAUFFE-EAU (07/10/2026, proprietaire) : un jour faible, l'eau chaude
|
||||
// se fait en heures creuses sur EDF, a PLEINE consommation toute la fenetre
|
||||
// (douches de 06:00 et 20:00 a 65 °C ; le 06/10 le ballon avait pris 5,4 kWh
|
||||
// de solaire de 10 h a 15 h, l'energie qui manquait a la batterie). Le bilan
|
||||
// decide une fois par jour (input_boolean.evcs_balance_ecs_nuit) ; le workflow
|
||||
// ECS n'alimente le ballon que si la session est engagee ET le contacteur
|
||||
// ferme. Memes gardes de fraicheur et de statut que la cible.
|
||||
const hcEcsGridNeeded =
|
||||
balanceMorningTargetApplied && params.balanceEcsNuit;
|
||||
|
||||
const middayGridSessionUncovered =
|
||||
balanceMorningTargetApplied &&
|
||||
(
|
||||
(Number.isFinite(params.balanceRequiredSocPct) &&
|
||||
parsed.soc < params.balanceRequiredSocPct) ||
|
||||
middayVehicleGridNeeded
|
||||
middayVehicleGridNeeded ||
|
||||
hcEcsGridNeeded
|
||||
);
|
||||
|
||||
const gridSessionInHcWindow =
|
||||
|
||||
@@ -329,6 +329,36 @@ if (advisorEnabled && ecsNuit) {
|
||||
reason.push('Jour normal : chauffe-eau remis sous tension (il chauffe au solaire)');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// ALERTE « PASSE EN BOOST » (07/10/2026, proprietaire)
|
||||
// =====================================================
|
||||
// En heures creuses sur EDF, le ballon doit consommer AU MAXIMUM toute la
|
||||
// fenetre : en AUTO il reste sur la pompe a chaleur (lent, 55 °C) et la douche
|
||||
// ne sera pas a 65 °C (20 h apres la HC de midi, 06 h apres celle de nuit).
|
||||
// Si, 15 min apres le debut de la fenetre, session engagee, contacteur ferme et
|
||||
// ballon sous tension, il ne tire que la puissance de la pompe a chaleur
|
||||
// (regime hp_low), on le SIGNALE : input_text.evcs_alerte_chauffe_eau (JSON,
|
||||
// `since` = debut de la fenetre -> un seul message par fenetre, envoye par le
|
||||
// concierge OpenClaw). 0 W = thermostat satisfait : pas d'alerte.
|
||||
const ALERTE_DELAI_MIN = 15;
|
||||
const minNow = Number.isFinite(now.minNow) ? now.minNow : null;
|
||||
const fenetreHc = (normalized.hcWindows || []).find((w) => minNow !== null && (
|
||||
w.debut <= w.fin ? (minNow >= w.debut && minNow < w.fin) : (minNow >= w.debut || minNow < w.fin)));
|
||||
const depuisDebutMin = fenetreHc ? ((minNow - fenetreHc.debut + 1440) % 1440) : null;
|
||||
const alerteBoost = !!fenetreHc && depuisDebutMin >= ALERTE_DELAI_MIN
|
||||
&& hcSessionCommitted && gridIsOn && waterHeaterSwitchOn && observedRegime === 'hp_low';
|
||||
let alerteChauffeEau = '';
|
||||
if (alerteBoost) {
|
||||
const h = String(Math.floor(fenetreHc.debut / 60)).padStart(2, '0') + ':' + String(fenetreHc.debut % 60).padStart(2, '0');
|
||||
const jourFenetre = (fenetreHc.debut > fenetreHc.fin && minNow < fenetreHc.fin)
|
||||
? new Date(nowMs - 86400000).toLocaleDateString('sv-SE', { timeZone: 'Europe/Paris' }) : now.date;
|
||||
alerteChauffeEau = JSON.stringify({
|
||||
active: true, since: `${jourFenetre} ${h}`, fenetre: fenetreHc.nom,
|
||||
puissance_w: Math.round(observedPowerW),
|
||||
message: `🚿 Heures creuses EDF : le chauffe-eau ne tire que ${Math.round(observedPowerW)} W (pompe a chaleur). Passe-le en BOOST pour avoir 65 °C a ${fenetreHc.douche}.`,
|
||||
});
|
||||
}
|
||||
|
||||
return [{
|
||||
json: {
|
||||
...root,
|
||||
@@ -366,7 +396,8 @@ return [{
|
||||
powerSwitchAction,
|
||||
powerSwitchDesiredOn,
|
||||
offJourFaible,
|
||||
jourFaibleState
|
||||
jourFaibleState,
|
||||
alerteChauffeEau
|
||||
}
|
||||
}
|
||||
}];
|
||||
@@ -33,6 +33,10 @@
|
||||
"ecs_24h_kwh": states("sensor.evcs_chauffe_eau_24h_kwh"),
|
||||
"ecs_jour_kwh": states("sensor.evcs_chauffe_eau_jour_kwh"),
|
||||
"off_jour_faible_prev": states("input_boolean.victron_water_heater_off_jour_faible"),
|
||||
"hc_midday_start": states("input_datetime.victron_evcs_hc_midday_start"),
|
||||
"hc_midday_stop": states("input_datetime.victron_evcs_hc_midday_stop"),
|
||||
"hc_night_start": states("input_datetime.victron_evcs_hc_night_start"),
|
||||
"hc_night_stop": states("input_datetime.victron_evcs_hc_night_stop"),
|
||||
|
||||
"advisor_enabled": states("input_boolean.victron_water_heater_advisor_enabled"),
|
||||
"notifications_enabled": states("input_boolean.victron_water_heater_notifications"),
|
||||
|
||||
@@ -198,6 +198,12 @@ const ecs24hKwh = num(input.ecs_24h_kwh, NaN);
|
||||
const ecsJourKwh = num(input.ecs_jour_kwh, NaN);
|
||||
const offJourFaiblePrev = low(input.off_jour_faible_prev) === 'on';
|
||||
const forecastSource = cleanStateText(input.forecast_source) || 'forecast_solar';
|
||||
// Fenetres HC (« HH:MM:SS » des input_datetime du controleur), en minutes du jour.
|
||||
const hhmm = (v) => { const m = cleanStateText(v).match(/^(\d{1,2}):(\d{2})/); return m ? Number(m[1]) * 60 + Number(m[2]) : null; };
|
||||
const hcWindows = [
|
||||
{ nom: 'midi', debut: hhmm(input.hc_midday_start), fin: hhmm(input.hc_midday_stop), douche: '20 h' },
|
||||
{ nom: 'nuit', debut: hhmm(input.hc_night_start), fin: hhmm(input.hc_night_stop), douche: '06 h' },
|
||||
].filter((w) => w.debut !== null && w.fin !== null);
|
||||
|
||||
return [{
|
||||
json: {
|
||||
@@ -246,7 +252,8 @@ return [{
|
||||
ecs24hKwh,
|
||||
ecsJourKwh,
|
||||
offJourFaiblePrev,
|
||||
forecastSource
|
||||
forecastSource,
|
||||
hcWindows
|
||||
}
|
||||
}
|
||||
}];
|
||||
@@ -196,7 +196,8 @@ let {
|
||||
protectionState,
|
||||
powerSwitchAction,
|
||||
powerSwitchDesiredOn,
|
||||
offJourFaible = false
|
||||
offJourFaible = false,
|
||||
alerteChauffeEau = ''
|
||||
} = finalDecision;
|
||||
|
||||
reason = Array.isArray(reason) ? [...reason] : [];
|
||||
@@ -563,6 +564,15 @@ helper_budget_margin: {
|
||||
datetime: forcedOffAtSafe
|
||||
}
|
||||
},
|
||||
// Alerte « passe en BOOST » (07/10/2026), lue par le concierge OpenClaw.
|
||||
helper_alerte_chauffe_eau: {
|
||||
domain: 'input_text',
|
||||
service: 'set_value',
|
||||
data: {
|
||||
entity_id: 'input_text.evcs_alerte_chauffe_eau',
|
||||
value: alerteChauffeEau
|
||||
}
|
||||
},
|
||||
// Jour faible (07/10/2026) : la coupure appartient a la regle « eau chaude en HC de nuit ».
|
||||
helper_off_jour_faible: {
|
||||
domain: 'input_boolean',
|
||||
|
||||
Reference in New Issue
Block a user