{#- Fenetres d'heures creuses (28/09/2026). Le calendrier tarifaire reste dans Home Assistant (helpers victron_evcs_hc_*) ; le bilan ne recoit que deux instants : la fin de la fenetre HC en cours (vide hors fenetre) et le debut de la fenetre HC suivante. Strategie du proprietaire : la batterie doit tenir jusqu'a la prochaine fenetre HC. -#} {%- set ns = namespace(fin='', suivant='', nuit='', fen=[]) -%} {%- for j in [0, 1, 2] -%} {%- for a, b, t in [('victron_evcs_hc_night_start', 'victron_evcs_hc_night_stop', 'nuit'), ('victron_evcs_hc_midday_start', 'victron_evcs_hc_midday_stop', 'midi')] -%} {%- set d = today_at(states('input_datetime.' ~ a)) + timedelta(days=j) -%} {%- set f = today_at(states('input_datetime.' ~ b)) + timedelta(days=j) -%} {%- set f = f + timedelta(days=1) if f <= d else f -%} {%- set ns.fen = ns.fen + [[d, f, t]] -%} {%- endfor -%} {%- endfor -%} {%- for w in ns.fen | sort(attribute='0') -%} {%- if w[0] <= now() < w[1] and ns.fin == '' -%}{%- set ns.fin = w[1] -%}{%- endif -%} {%- endfor -%} {%- set repere = ns.fin if ns.fin != '' else now() -%} {%- for w in ns.fen | sort(attribute='0') -%} {%- if w[0] >= repere and ns.suivant == '' -%}{%- set ns.suivant = w[0] -%}{%- endif -%} {%- if w[0] >= repere and w[2] == 'nuit' and ns.nuit == '' -%}{%- set ns.nuit = w[0] -%}{%- endif -%} {%- endfor -%} {#- Vehicule branche a midi (28/09/2026) — JEEP, VW ou ZERO, selon le selecteur. Pour chacun, HA porte le calendrier (jours et heure de depart apres le dejeuner), la capacite et la puissance de charge MESUREES ; le bilan recoit un instant de depart, vide si le vehicule ne repart pas aujourd'hui. Le niveau saisi n'est retenu que s'il date de ce branchement (tolerance 1 h avant). Capacite ou puissance a 0 = inconnue. -#} {%- set vh = namespace(dep='', valide=false, cap=none, kw=none) -%} {%- set jours = ['lun', 'mar', 'mer', 'jeu', 'ven', 'sam', 'dim'] -%} {%- set cle = {'JEEP': 'jeep', 'VW': 'vw', 'ZERO': 'zero'}.get(states('input_select.victron_evcs_vehicle')) -%} {%- if cle -%} {%- set vh.cap = states('input_number.victron_evcs_capacity_' ~ cle ~ '_kwh') -%} {%- set vh.kw = states('input_number.victron_evcs_charger_kw_' ~ cle) -%} {%- set heure = states('input_datetime.victron_evcs_' ~ cle ~ '_midday_departure') -%} {%- if jours[now().weekday()] in states('input_text.victron_evcs_' ~ cle ~ '_midday_departure_days') | lower and heure not in ['unknown', 'unavailable', ''] -%} {%- set d = today_at(heure) -%} {%- if d > now() -%}{%- set vh.dep = d -%}{%- endif -%} {%- endif -%} {%- endif -%} {%- set branche = states.binary_sensor.victron_evcs_vehicle_connected -%} {%- set niveau = states.input_number.victron_evcs_vehicle_level_pct -%} {#- Depart ponctuel (VW, ZERO : pas de jours fixes) : pour aujourd'hui, a venir, saisi depuis ce branchement. Le plus proche des deux departs l'emporte. -#} {%- set ponctuel = states.input_datetime.victron_evcs_departure_ponctuel -%} {%- if branche is not none and ponctuel is not none and branche.state == 'on' and ponctuel.state not in ['unknown', 'unavailable', ''] -%} {%- set p = as_datetime(ponctuel.attributes.timestamp) | as_local -%} {%- if p.date() == now().date() and p > now() and as_timestamp(ponctuel.last_changed) >= as_timestamp(branche.last_changed) - 3600 -%} {%- set vh.dep = p if vh.dep == '' or p < vh.dep else vh.dep -%} {%- endif -%} {%- endif -%} {%- if branche is not none and niveau is not none and branche.state == 'on' -%} {#- Date de SAISIE ecrite par l'automatisation, pas last_changed : une saisie identique ne change pas l'etat du helper mais compte comme une saisie. -#} {%- set vh.valide = (as_timestamp(states('input_datetime.victron_evcs_vehicle_level_at'), 0)) >= as_timestamp(branche.last_changed) - 3600 -%} {%- endif -%} {{ { "ts": now().isoformat(), "vehicle_connected": is_state("binary_sensor.victron_evcs_vehicle_connected", "on"), "vehicle_departure_ms": (as_timestamp(vh.dep) * 1000) if vh.dep != '' else none, "vehicle_level_pct": states("input_number.victron_evcs_vehicle_level_pct"), "vehicle_level_valid": vh.valide, "vehicle_capacity_kwh": vh.cap, "vehicle_charger_kw": vh.kw, "vehicle_delivered_since_level_kwh": ((states("sensor.evcs_hq2239dnt7p_total_energy") | float(0)) - (states("input_number.victron_evcs_vehicle_level_ref_kwh") | float(0))) if states("sensor.evcs_hq2239dnt7p_total_energy") | is_number else none, "hc_window_end_ms": (as_timestamp(ns.fin) * 1000) if ns.fin != '' else none, "next_hc_start_ms": (as_timestamp(ns.suivant) * 1000) if ns.suivant != '' else none, "next_night_hc_start_ms": (as_timestamp(ns.nuit) * 1000) if ns.nuit != '' else none, "nowMs": as_timestamp(now()) * 1000, "balance_enabled": states("input_boolean.evcs_balance_enabled"), "usable_capacity_kwh": states("input_number.evcs_balance_usable_capacity_kwh"), "modules_en_service": states("input_number.evcs_balance_modules_en_service"), "consumption_p50_csv": states("input_text.evcs_balance_consumption_p50"), "consumption_p80_csv": states("input_text.evcs_balance_consumption_p80"), "envelope_csv": states("input_text.evcs_balance_envelope"), "censorship_rate_csv": states("input_text.evcs_balance_censorship_rate"), "forecast_source": states("input_select.evcs_balance_forecast_source"), "forecast_day0": states("input_text.evcs_balance_vrm_day0") if is_state("input_select.evcs_balance_forecast_source", "vrm") else states("input_text.evcs_balance_forecast_day0"), "forecast_today_csv": states("input_text.evcs_balance_vrm_today") if is_state("input_select.evcs_balance_forecast_source", "vrm") else states("input_text.evcs_balance_forecast_today"), "forecast_tomorrow_csv": states("input_text.evcs_balance_vrm_tomorrow") if is_state("input_select.evcs_balance_forecast_source", "vrm") else states("input_text.evcs_balance_forecast_tomorrow"), "forecast_updated": states("input_text.evcs_balance_vrm_updated") if is_state("input_select.evcs_balance_forecast_source", "vrm") else states("input_text.evcs_balance_forecast_updated"), "grid_soc_off": states("input_number.victron_grid_soc_off"), "manual_hc_floor_percent": states("input_number.evcs_battery_manual_hc_floor"), "pv_power_w": states("sensor.victron_pv_power_system"), "house_ac_power_w": states("sensor.victron_consumption_power_l1"), "vebus_ac_out_l1_power_w": states("sensor.victron_ve_bus_ac_out_l1_power"), "evcs_ac_power_w": states("sensor.victron_evcs_ac_power"), "soc_percent": states("sensor.victron_battery_soc"), "battery_current_a": states("sensor.victron_battery_current"), "battery_voltage_v": states("sensor.victron_battery_voltage"), "vebus_dc_power_w": states("sensor.victron_ve_bus_dc_power_system"), "grid_switch": states("switch.edf_general_ok_switch"), "acin1_available": states("sensor.victron_ac_in1_available"), "grid_power_l1_w": states("sensor.victron_grid_power_l1"), "multiplus_state": states("sensor.airtria_mpii_v1_state"), "multiplus_overload_alarm": states("sensor.airtria_mpii_v1_overload_alarm"), "system_state": states("sensor.gx_device_system_state"), "ess_batterylife_state": states("sensor.gx_device_ess_batterylife_state"), "dc_battery_state": states("sensor.gx_device_dc_battery_state"), "mppt_1_state": states("sensor.airtria_mppt1_state"), "mppt_2_state": states("sensor.mppt_450_200_hq2449yr9pt_state"), "mppt_3_state": states("sensor.v1_state"), "evcs_native_status": states("sensor.evcs_hq2239dnt7p_status"), "forecast_today_remaining_kwh": states("sensor.energy_production_today_remaining"), "forecast_today_kwh": states("sensor.energy_production_today"), "forecast_tomorrow_kwh": states("sensor.energy_production_tomorrow"), "forecast_next_hour_w": states("sensor.power_production_next_hour"), "sun_elevation": state_attr("sun.sun", "elevation"), "storm_alert_level": (states.sensor | selectattr('entity_id', 'search', '_weather_alert') | map(attribute='state') | list | first) | default('indisponible', true), "storm_alert_detail": (states.sensor | selectattr('entity_id', 'search', '_weather_alert') | map(attribute='attributes') | list | first) | default({}, true) } | tojson }}