Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
133 lines
8.1 KiB
Smarty
133 lines
8.1 KiB
Smarty
{#- 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 }}
|