Chauffe-eau : reprise de 16 h a 20 h apres coupure en pleine chauffe, mesure sur 10 min ; bilan HC de midi

This commit is contained in:
Tallagrand Thierry
2026-10-07 14:40:21 +02:00
parent b34b68408c
commit 16d1f8ee2b
8 changed files with 101 additions and 15 deletions

View File

@@ -282,6 +282,7 @@ const {
} = normalized;
let offJourFaible = false;
let jourFaibleState = 'none';
let coupeEnChauffe = null; // horodatage a ecrire si la coupure tombe en pleine chauffe
if (advisorEnabled && ecsNuit) {
const energieConnue = Number.isFinite(ecs24hKwh);
const eauFroide = energieConnue && ecs24hKwh < ECS_EAU_FROIDE_KWH;
@@ -292,8 +293,11 @@ if (advisorEnabled && ecsNuit) {
? pvPowerW >= houseAcPowerW
: pvPowerW - houseAcPowerW >= autoPowerW);
const heure = Number.isFinite(now.hour) ? now.hour : -1;
// 07/10 : coupe en PLEINE CHAUFFE a la fin des HC de midi (BOOST encore a 2,3 kW
// a 14:24) -> l'eau n'est pas a 65 °C : il reprend aussi de 16 h a 20 h.
const coupeEnChauffeAujourdhui = (input.coupe_en_chauffe || '').startsWith(now.date || '?');
const securiteSoir = heure >= ECS_SOIR_DEBUT_H && heure < ECS_SOIR_FIN_H
&& !(Number.isFinite(ecsJourKwh) && ecsJourKwh >= ECS_EAU_FROIDE_KWH);
&& (!(Number.isFinite(ecsJourKwh) && ecsJourKwh >= ECS_EAU_FROIDE_KWH) || coupeEnChauffeAujourdhui);
const veutChauffer = !energieConnue || heuresCreusesEdf || eauFroide || solaireCouvre || securiteSoir;
offJourFaible = true;
jourFaibleState = !energieConnue ? 'jour_faible_energie_illisible'
@@ -305,6 +309,10 @@ if (advisorEnabled && ecsNuit) {
if (veutChauffer !== waterHeaterSwitchOn) {
powerSwitchAction = veutChauffer ? 'turn_on' : 'turn_off';
powerSwitchDesiredOn = veutChauffer;
// Coupure alors qu'il chauffait (puissance mesuree au-dessus de l'arret).
if (!veutChauffer && Math.max(observedPowerW, normalized.observedPowerPrevW ?? 0) > 150) {
coupeEnChauffe = `${now.date} ${String(now.hour).padStart(2, '0')}:${String(now.minute).padStart(2, '0')}`;
}
} else {
powerSwitchAction = 'none';
powerSwitchDesiredOn = waterHeaterSwitchOn;
@@ -406,7 +414,8 @@ return [{
powerSwitchDesiredOn,
offJourFaible,
jourFaibleState,
alerteChauffeEau
alerteChauffeEau,
coupeEnChauffe
}
}
}];

View File

@@ -34,6 +34,7 @@
"ecs_jour_kwh": states("sensor.evcs_chauffe_eau_jour_kwh"),
"off_jour_faible_prev": states("input_boolean.victron_water_heater_off_jour_faible"),
"alerte_prev": states("input_text.evcs_alerte_chauffe_eau"),
"coupe_en_chauffe": states("input_text.victron_water_heater_coupe_en_chauffe"),
"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"),

View File

@@ -141,8 +141,11 @@ const cfg = {
mobileNotifyDomain: 'notify',
mobileNotifyService: 'mobile_app_iphone_16_de_tt',
batteryUsableCapacityKwh: 17.5,
sampleWindowMinMin: 2,
sampleWindowMinMax: 15,
// 07/10/2026 : le compteur Tuya ne remonte que toutes les ~10 min ; mesure sur
// 5 min = une fois 2,3 kW, une fois 0 W (regime qui clignote). On mesure donc
// sur >= 9,5 min : la reference n'est avancee que quand l'echantillon sert.
sampleWindowMinMin: 9.5,
sampleWindowMinMax: 25,
energyByDemandKwh: {
low: { green: 0.9, auto: 1.4, boost: 2.0 },
normal: { green: 1.4, auto: 2.2, boost: 3.1 },
@@ -196,6 +199,7 @@ const ecsNuit = low(input.ecs_nuit) === 'on';
const hcSessionCommitted = low(input.hc_session_committed) === 'on';
const ecs24hKwh = num(input.ecs_24h_kwh, NaN);
const ecsJourKwh = num(input.ecs_jour_kwh, NaN);
const observedPowerPrevW = Math.max(0, num(input.observed_power_helper_w, 0));
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.
@@ -251,6 +255,7 @@ return [{
hcSessionCommitted,
ecs24hKwh,
ecsJourKwh,
observedPowerPrevW,
offJourFaiblePrev,
forecastSource,
hcWindows

View File

@@ -197,7 +197,8 @@ let {
powerSwitchAction,
powerSwitchDesiredOn,
offJourFaible = false,
alerteChauffeEau = ''
alerteChauffeEau = '',
coupeEnChauffe = null
} = finalDecision;
reason = Array.isArray(reason) ? [...reason] : [];
@@ -524,7 +525,10 @@ helper_budget_margin: {
datetime: mismatchSinceAtEffective
}
},
// La reference n'avance que si l'echantillon a servi, ou s'il est perime
// (trop vieux ou illisible) : sinon on laisse s'accumuler jusqu'a 9,5 min.
helper_energy_prev_kwh: {
execute: !!sampleIsUsable || !(Number.isFinite(sampleDurationMin) && sampleDurationMin < 9.5),
domain: 'input_number',
service: 'set_value',
data: {
@@ -533,6 +537,7 @@ helper_budget_margin: {
}
},
helper_energy_prev_at: {
execute: !!sampleIsUsable || !(Number.isFinite(sampleDurationMin) && sampleDurationMin < 9.5),
domain: 'input_datetime',
service: 'set_datetime',
data: {
@@ -564,6 +569,16 @@ helper_budget_margin: {
datetime: forcedOffAtSafe
}
},
// Coupure en pleine chauffe (07/10/2026) : autorise la reprise de 16 h a 20 h.
helper_coupe_en_chauffe: {
execute: !!coupeEnChauffe,
domain: 'input_text',
service: 'set_value',
data: {
entity_id: 'input_text.victron_water_heater_coupe_en_chauffe',
value: coupeEnChauffe || ''
}
},
// Alerte « passe en BOOST » (07/10/2026), lue par le concierge OpenClaw.
helper_alerte_chauffe_eau: {
domain: 'input_text',