Bilan : reprise du chauffe-eau du soir comptee les jours faibles, prevision de l'apres-midi recalee sur la matinee
This commit is contained in:
@@ -184,13 +184,61 @@ function nightScaled(profile, slot) {
|
||||
return (profile[h] ?? 0) * (1 + (nightFactor - 1) * nightShare(slot.startMs));
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// JOUR FAIBLE : CE QUE LA JOURNEE DIT DEJA (07/10/2026, proprietaire)
|
||||
// =====================================================================
|
||||
// Le 07/10 la HC de midi visait 44 % (« arriver a 01:24 au-dessus de 22 % »),
|
||||
// et EDF a quand meme ete ferme en HEURES PLEINES a 18:03 (~8 kWh HP). Deux
|
||||
// erreurs du calcul, corrigees ici :
|
||||
// 1. La reprise du chauffe-eau de 16 h a 20 h (douche de 20 h, 2,1 kWh mesures
|
||||
// le 07/10) n'etait pas comptee : les jours faibles (decision du bilan),
|
||||
// `ecs_reprise_soir_kwh` est ajoute a la consommation de 16 h a 20 h du jour.
|
||||
// 2. La prevision de l'apres-midi n'etait pas recalee sur la matinee : VRM
|
||||
// annoncait ~9 kWh de 14 h a 19 h, il en est venu ~5, et la matinee le
|
||||
// disait deja (3,1 kWh produits a 12:36 pour ~5 prevus). Quand le reel du
|
||||
// jour est EN RETARD sur la prevision des heures ecoulees (au moins 2 kWh
|
||||
// prevus, production complete), les heures restantes du jour sont
|
||||
// multipliees par le meme rapport, borne a [0,4 ; 1]. Jamais a la hausse :
|
||||
// une matinee meilleure que prevu ne promet rien pour l'apres-midi.
|
||||
const ECS_SOIR_H0 = 16;
|
||||
const ECS_SOIR_H1 = 20;
|
||||
const nowMsSlots = num(input.nowMs, Date.now());
|
||||
const jourParis = (ms) => new Date(ms).toLocaleDateString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const aujourdhuiParis = jourParis(nowMsSlots);
|
||||
function slotIsToday(slot) {
|
||||
return Number.isFinite(num(slot.startMs, NaN)) && jourParis(num(slot.startMs, 0)) === aujourdhuiParis;
|
||||
}
|
||||
const ecsNuitAujourdhui = typeof input.ecs_nuit_jour === 'string'
|
||||
&& input.ecs_nuit_jour.startsWith(aujourdhuiParis + '|on');
|
||||
const ecsRepriseSoirKwh = ecsNuitAujourdhui ? Math.max(0, num(input.ecs_reprise_soir_kwh, 0)) : 0;
|
||||
let prodRecal = { factor: 1, active: false };
|
||||
{
|
||||
const prevu = typeof input.forecast_today_csv === 'string' ? input.forecast_today_csv.split(',').map(Number) : [];
|
||||
const reel = num(input.production_jour_kwh, NaN);
|
||||
if (prevu.length === 24 && prevu.every(Number.isFinite) && Number.isFinite(reel)
|
||||
&& input.production_jour_statut === 'complet') {
|
||||
const p = new Intl.DateTimeFormat('fr-FR', { timeZone: 'Europe/Paris', hour: '2-digit', minute: '2-digit', hour12: false })
|
||||
.format(new Date(nowMsSlots)).split(':').map(Number);
|
||||
let ecoule = 0;
|
||||
for (let h = 0; h < 24; h++) ecoule += h < p[0] ? prevu[h] : (h === p[0] ? prevu[h] * p[1] / 60 : 0);
|
||||
if (ecoule >= 2) {
|
||||
const r = reel / ecoule;
|
||||
prodRecal = { factor: round2(Math.max(0.4, Math.min(1, r))), active: r < 1, ratio: round2(r),
|
||||
realKwh: round2(reel), expectedSoFarKwh: round2(ecoule) };
|
||||
}
|
||||
}
|
||||
}
|
||||
const prodRecalFactor = prodRecal.factor;
|
||||
|
||||
function buildSlots(consumption, prudent = false) {
|
||||
return horizon.slice(0, CFG.SEARCH_HOURS).map(slot => {
|
||||
const hour = num(slot.hour, 0);
|
||||
const productionKwh = Math.max(0, num(slot.expectedKwh, 0));
|
||||
const consumptionKwh = prudent
|
||||
const aujourdhui = slotIsToday(slot);
|
||||
const productionKwh = Math.max(0, num(slot.expectedKwh, 0)) * (aujourdhui ? prodRecalFactor : 1);
|
||||
const consumptionKwh = (prudent
|
||||
? Math.max(consumption[hour] ?? 0, nightScaled(consumptionP50, slot))
|
||||
: nightScaled(consumption, slot);
|
||||
: nightScaled(consumption, slot))
|
||||
+ (aujourdhui && hour >= ECS_SOIR_H0 && hour < ECS_SOIR_H1 ? ecsRepriseSoirKwh / (ECS_SOIR_H1 - ECS_SOIR_H0) : 0);
|
||||
return {
|
||||
startMs: slot.startMs,
|
||||
hour,
|
||||
@@ -800,6 +848,9 @@ return [{
|
||||
|
||||
// Chauffe-eau en HC de nuit les jours faibles (07/10).
|
||||
ecsNight,
|
||||
// Reprise du soir et prevision du jour recalee sur la matinee (07/10).
|
||||
ecsReprise: { active: ecsRepriseSoirKwh > 0, kwh: round2(ecsRepriseSoirKwh) },
|
||||
prodRecal,
|
||||
|
||||
// Nuit prevue par la soiree (28/09) : facteur applique au profil.
|
||||
nightModel: {
|
||||
|
||||
@@ -82,6 +82,9 @@
|
||||
"night_hc_start_ms": (as_timestamp(ns.nd) * 1000) if ns.nd != '' else none,
|
||||
"night_hc_end_ms": (as_timestamp(ns.nf) * 1000) if ns.nf != '' else none,
|
||||
"ecs_nuit_jour": states("input_text.evcs_balance_ecs_nuit_jour"),
|
||||
"ecs_reprise_soir_kwh": states("input_number.evcs_chauffe_eau_reprise_soir_kwh"),
|
||||
"production_jour_kwh": states("sensor.evcs_production_jour_kwh"),
|
||||
"production_jour_statut": state_attr("sensor.evcs_production_jour_kwh", "statut"),
|
||||
"nowMs": as_timestamp(now()) * 1000,
|
||||
|
||||
"balance_enabled": states("input_boolean.evcs_balance_enabled"),
|
||||
|
||||
@@ -83,6 +83,12 @@ return [{
|
||||
night_hc_end_ms: snapshot.night_hc_end_ms,
|
||||
// Decision du jour pour le chauffe-eau (07/10) : « AAAA-MM-JJ|on|raison ».
|
||||
ecs_nuit_jour: snapshot.ecs_nuit_jour,
|
||||
// 07/10 : reprise du chauffe-eau le soir (jour faible) et production reelle
|
||||
// du jour pour recaler la prevision de l'apres-midi.
|
||||
ecs_reprise_soir_kwh: snapshot.ecs_reprise_soir_kwh,
|
||||
production_jour_kwh: snapshot.production_jour_kwh,
|
||||
production_jour_statut: snapshot.production_jour_statut,
|
||||
forecast_today_csv: snapshot.forecast_today_csv,
|
||||
|
||||
// Repris pour l'écriture des helpers, sans influencer le calcul.
|
||||
resourceUsable: resource.usable,
|
||||
|
||||
Reference in New Issue
Block a user