Bonjour à tous,
je possède aujourd’hui une installation Photovoltaïque et je voulais voir si il était rentable d’y ajouter une batterie, pour cela j’ai (avec l’aide de chatgpt) un package et une carte.
Je voulais vous les présenter afin de recueillir vos avis et critiques.
Merci par avance.
Simulation de batteries virtuelles (3 packs) — ROI, rentabilité & projections
But du package
Ce package Home Assistant permet de simuler trois batteries virtuelles indépendantes (Pack A/B/C) sur la base de tes mesures réelles (Linky + production solaire). L’objectif est de :
-
Visualiser les flux instantanés (réseau, solaire, maison, batterie) dans Power Flow Card Plus.
-
Évaluer la rentabilité : coûts d’achats en HC, gains lors des décharges en HP, net €, ROI et délai d’amortissement.
-
Comparer des profils matériels différents (capacité, puissances, rendements, coût d’investissement) et projeter la rentabilité selon 3 horizons (30/180/360 jours).
Chaque pack est une simulation séparée : aucun cumul entre A, B, C. Un sélecteur (
input_select) permet d’afficher à la demande le pack à suivre dans la carte Lovelace.
Méthodologie (règles de pilotage)
Les décisions de charge/décharge sont prises à partir de capteurs réels :
-
Sources
-
Tarif temps réel :
sensor.tarif_actuel_edf_ttc -
Import réseau :
sensor.garage_sonde_linky_sinsts -
Export réseau :
sensor.garage_sonde_linky_sinsti -
Production PV :
sensor.envoy_..._production_d_electricite_actuelle -
HC/HP :
binary_sensor.rte_tempo_heures_creuses
-
-
Règles
-
Charge solaire (surplus PV) : si export réseau > 0 et SOC < 100 %, la batterie se charge jusqu’à sa puissance max de charge. Coût = 0 €.
-
Charge réseau en HC : si HC = ON et SOC < SOC_cible, la batterie se charge depuis le réseau (jusqu’à Pmax). Coût = énergie × tarif HC.
-
Décharge en HP : si HC = OFF, qu’il y a un import réseau et que SOC > SOC_min, la batterie alimente la maison (jusqu’à Pmax). Gain = énergie × tarif HP.
-
Aucun échange entre packs et pas de priorité croisée : chaque pack suit ses propres règles, sa capacité, ses rendements et ses seuils.
-
Les rendements sont appliqués à la charge/décharge (charge efficace, énergie interne déchargée) pour une simulation plus réaliste.
Explication des calculs
1) Normalisation des flux (capteurs “sim_”)
-
sim_grid_import_w= max(Import mesuré, 0) -
sim_grid_export_w= max(Export mesuré, 0) -
sim_pv_power_w= production PV (conversion auto kW→W si nécessaire) -
sim_home_demand_w≈ Import + PV – Export (approximation cohérente de la demande maison) -
sim_tarif_eur_kwh= tarif instantané en €/kWh -
sim_hc_on= état HC/HP
2) Puissances batterie (par pack)
-
Charge PV :
charge_pv_w = min(surplus_export, Pmax_charge)si SOC<100 % -
Charge réseau :
charge_grid_w = Pmax_chargesi HC=ON et SOC<SOC_cible -
Décharge :
discharge_w = min(import_maison, Pmax_decharge)si HC=OFF et SOC>SOC_min
Rendements :
charge_effective_w = (charge_pv_w + charge_grid_w) × η_charge
discharge_internal_w = discharge_w / η_decharge(énergie réellement soutirée du pack)
3) Conversion W → kWh et €/h → €
Réalisée par la plateforme integration (méthode trapézoïdale) :
-
Énergies cumulées :
kWh_charge_pv,kWh_charge_grid,kWh_charge_effective,kWh_discharge_home,kWh_discharge_internal -
Coût instantané :
cost_rate = charge_grid_w/1000 × tarif→ intégré en € -
Gain instantané :
gain_rate = discharge_w/1000 × tarif→ intégré en €
4) État d’énergie & SOC
-
Énergie stockée :
E = E_init + kWh_charge_effective – kWh_discharge_internal, bornée à[0 ; capacité] -
SOC =
100 × E / capacité
5) Coût, gain et net
-
Coût (réseau uniquement) = ∫
cost_rate(€/h) -
Gain (décharge) = ∫
gain_rate(€/h) -
Net = Gain – Coût (en continu).
-
Utility meters journaliers et mensuels calculent :
-
net_day,net_month,chg_day,dis_day,chg_month,dis_month(par pack) -
last_perioddes UM journaliers = valeur d’hier, utile pour des moyennes “jours complets”.
-
6) ROI & Délai d’amortissement
-
ROI par pack =
gain_net_cumulé / coût_investissement(0–1). -
Payback simple (jours) =
coût_investissement / (net_mois / nb_jours_écoulés) -
Payback 30j =
coût_investissement / moyenne_30j(€ / jour)- Moyenne 30j via
statisticssur la valeur d’hier (UMlast_period) → moyenne de jours complets, plus stable.
- Moyenne 30j via
-
Date d’amortissement =
aujourd’hui + payback_jours.
7) Projections (ce sont des estimations, pas des garanties)
-
Projection mensuelle =
moyenne_30j × nb_jours_du_mois -
Projection annuelle =
moyenne_30j × 365 -
Confiance = min(
count_statistics / 30, 1) × 100 % -
Horizons supplémentaires : moyennes 180 j et 360 j pour lisser la saisonnalité et estimer des paybacks 180/360 j.
Intégrations Home Assistant utilisées
-
template-
Règles de décision, calculs des puissances, rendements, SOC, ROI, paybacks, proxys “pack sélectionné”, projections et indicateurs de confiance.
-
Une seule clé
template:dans le package pour éviter les erreursduplicate key.
-
-
integration- Convertit les puissances (W) en énergies (kWh) et les €/h en € (méthode trapézoïdale, précise sur mesures régulières).
-
utility_meter-
Découpe les cumuls en jour et mois pour le net (€, charge/décharge kWh).
-
Fournit
last_period= valeur d’hier, exploitable pour des moyennes de jours complets.
-
-
statistics-
Calcule des moyennes glissantes du gain net quotidien sur 30 / 180 / 360 jours (entrée = “net d’hier”).
-
Sert de base aux paybacks lissés et aux projections.
-
-
Cartes Lovelace
-
Power Flow Card Plus (HACS) : visualisation des flux instantanés (réseau/solaire/maison/batterie).
-
Gauge/Tile/Markdown : SOC, ROI, net jour/mois, charge/décharge, paybacks, projections, confiance.
-
Sélecteur :
input_selectpour choisir le pack affiché (les proxyssim_selected_*pilotent la carte).
-
-
(Optionnel) Recorder / InfluxDB
- Possibilité d’inclure tous les capteurs “sim_” pour l’historique court terme (Recorder) et le long terme (InfluxDB) → dashboards Grafana/HA.
Paramètres éditables (par pack)
-
Capacité (kWh), Pmax charge/décharge (kW), rendements (%), SOC cible, SOC min, SOC initial, coût d’investissement (€).
-
Valeurs par défaut : inspirées de matériels typiques (ex. Tesla Powerwall 3, BYD HVM 16.6, Pylontech Force H2), à ajuster selon tes besoins.
Points forts & limites
Points forts
-
S’appuie exclusivement sur tes mesures réelles.
-
Rendements et limites physiques pris en compte.
-
Vision économique complète : net €, ROI, amortissement et projections multi-horizons.
-
Un sélecteur unique pour piloter l’affichage, sans mélange des packs.
Limites / transparence
-
Le calcul
home_demandest une approximation (Import + PV – Export). -
Les projections (30/180/360 j) sont indicatives et varient avec la météo, l’usage et les tarifs.
-
La carte PFCP peut afficher des transitoires (quelques secondes) lors des bascules charge/décharge.
Comment l’utiliser
-
Copier le package dans
packages/pkg_energie_simu_batteries.yaml. -
Vérifier les noms d’entités (Linky, Envoy, tarif, binaire HC).
-
Adapter si besoin les paramètres des packs (capacité, puissances, rendements, coût).
-
Ajouter la carte Lovelace fournie.
-
(Optionnel) Ajouter les capteurs “sim_” au Recorder / InfluxDB pour l’historique & Grafana.
###############################################################################
# PACKAGE : Simulation 3 batteries virtuelles (A/B/C)
# - Flux réels (Linky + Envoy) → charge/décharge + coûts/gains
# - Utility meters jour/mois
# - ROI, délai d’amortissement (simple & 30j) + PROJECTIONS 30/180/360 jours
# - Proxys "pack sélectionné" pour la carte
# - Une seule clé 'template:' (pas de duplicate)
###############################################################################
homeassistant:
customize: {}
# -----------------------------------------------------------------------------
# Sélection & activation
# -----------------------------------------------------------------------------
input_select:
sim_pack_selected:
name: "Pack affiche"
options:
- Pack A (Powerwall3)
- Pack B (BYD HVM 16.6)
- Pack C (Pylontech F-H2 14.2)
initial: "Pack A (Powerwall3)"
input_boolean:
sim_pack_a_enabled: { name: "Pack A active", initial: true }
sim_pack_b_enabled: { name: "Pack B active", initial: true }
sim_pack_c_enabled: { name: "Pack C active", initial: true }
# -----------------------------------------------------------------------------
# Paramètres (défauts réalistes)
# -----------------------------------------------------------------------------
input_number:
# A — Tesla PW3 ~13.5 kWh / ~11.5 kW
sim_pack_a_capacity_kwh: {name: "A Capacite (kWh)", min: 1, max: 30, step: 0.1, mode: box, unit_of_measurement: kWh, initial: 13.5}
sim_pack_a_p_charge_kw: {name: "A Pmax charge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 11.5}
sim_pack_a_p_discharge_kw: {name: "A Pmax decharge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 11.5}
sim_pack_a_eta_charge_pct: {name: "A Rendement charge (%)", min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 97}
sim_pack_a_eta_discharge_pct: {name: "A Rendement decharge (%)",min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 97}
sim_pack_a_soc_target_pct: {name: "A SOC cible reseau (%)", min: 10, max: 100, step: 1, unit_of_measurement: "%", initial: 80}
sim_pack_a_soc_min_pct: {name: "A SOC mini decharge (%)", min: 0, max: 30, step: 1, unit_of_measurement: "%", initial: 5}
sim_pack_a_soc_initial_pct: {name: "A SOC initial (%)", min: 0, max: 100, step: 1, unit_of_measurement: "%", initial: 50}
sim_pack_a_invest_cost_eur: {name: "A Cout investissement (€)",min: 0, max: 30000, step: 100, unit_of_measurement: "€", initial: 15000}
# B — BYD HVM 16.56 / ~6 kW
sim_pack_b_capacity_kwh: {name: "B Capacite (kWh)", min: 1, max: 30, step: 0.1, mode: box, unit_of_measurement: kWh, initial: 16.56}
sim_pack_b_p_charge_kw: {name: "B Pmax charge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 6}
sim_pack_b_p_discharge_kw: {name: "B Pmax decharge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 6}
sim_pack_b_eta_charge_pct: {name: "B Rendement charge (%)", min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 96}
sim_pack_b_eta_discharge_pct: {name: "B Rendement decharge (%)",min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 96}
sim_pack_b_soc_target_pct: {name: "B SOC cible reseau (%)", min: 10, max: 100, step: 1, unit_of_measurement: "%", initial: 80}
sim_pack_b_soc_min_pct: {name: "B SOC mini decharge (%)", min: 0, max: 30, step: 1, unit_of_measurement: "%", initial: 5}
sim_pack_b_soc_initial_pct: {name: "B SOC initial (%)", min: 0, max: 100, step: 1, unit_of_measurement: "%", initial: 50}
sim_pack_b_invest_cost_eur: {name: "B Cout investissement (€)",min: 0, max: 30000, step: 100, unit_of_measurement: "€", initial: 10000}
# C — Pylontech Force H2 ~14.2 kWh / ~5 kW
sim_pack_c_capacity_kwh: {name: "C Capacite (kWh)", min: 1, max: 30, step: 0.1, mode: box, unit_of_measurement: kWh, initial: 14.2}
sim_pack_c_p_charge_kw: {name: "C Pmax charge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 5}
sim_pack_c_p_discharge_kw: {name: "C Pmax decharge (kW)", min: 0.1,max: 20, step: 0.1, mode: box, unit_of_measurement: kW, initial: 5}
sim_pack_c_eta_charge_pct: {name: "C Rendement charge (%)", min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 95}
sim_pack_c_eta_discharge_pct: {name: "C Rendement decharge (%)",min: 80, max: 100, step: 0.5, unit_of_measurement: "%", initial: 95}
sim_pack_c_soc_target_pct: {name: "C SOC cible reseau (%)", min: 10, max: 100, step: 1, unit_of_measurement: "%", initial: 80}
sim_pack_c_soc_min_pct: {name: "C SOC mini decharge (%)", min: 0, max: 30, step: 1, unit_of_measurement: "%", initial: 5}
sim_pack_c_soc_initial_pct: {name: "C SOC initial (%)", min: 0, max: 100, step: 1, unit_of_measurement: "%", initial: 50}
sim_pack_c_invest_cost_eur: {name: "C Cout investissement (€)",min: 0, max: 30000, step: 100, unit_of_measurement: "€", initial: 6500}
# -----------------------------------------------------------------------------
# TEMPLATES (UNIQUE clé "template:")
# -----------------------------------------------------------------------------
template:
# === Globaux (tick 10s + boot + changements) ===============================
- trigger:
- trigger: homeassistant
event: start
- trigger: time_pattern
seconds: "/10"
- trigger: state
entity_id:
- sensor.garage_sonde_linky_sinsts
- sensor.garage_sonde_linky_sinsti
- sensor.envoy_122237107679_production_d_electricite_actuelle
- sensor.tarif_actuel_edf_ttc
- binary_sensor.rte_tempo_heures_creuses
sensor:
- name: sim_grid_import_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: "{{ [ states('sensor.garage_sonde_linky_sinsts')|float(0), 0 ]|max }}"
- name: sim_grid_export_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: "{{ [ states('sensor.garage_sonde_linky_sinsti')|float(0), 0 ]|max }}"
- name: sim_pv_power_w
unit_of_measurement: W
device_class: power
state_class: measurement
# Conversion auto si la source est en kW
state: >
{% set src = 'sensor.envoy_122237107679_production_d_electricite_actuelle' %}
{% set v = states(src)|float(0) %}
{% set u = (state_attr(src,'unit_of_measurement') or 'W')|string|lower %}
{% set f = 1000 if u == 'kw' else 1 %}
{{ [ (v * f), 0 ]|max }}
- name: sim_home_demand_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set imp = states('sensor.sim_grid_import_w')|float(0) %}
{% set exp = states('sensor.sim_grid_export_w')|float(0) %}
{% set pv = states('sensor.sim_pv_power_w')|float(0) %}
{{ [ imp + pv - exp, 0 ]|max }}
- name: sim_tarif_eur_kwh
unit_of_measurement: "€/kWh"
state_class: measurement
state: "{{ states('sensor.tarif_actuel_edf_ttc')|float(0) }}"
- name: sim_hc_on
state: "{{ is_state('binary_sensor.rte_tempo_heures_creuses','on') }}"
# === PACK A =================================================================
- sensor:
- name: sim_pack_a_charge_pv_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_a_enabled','on') %}
{% set exportw = states('sensor.sim_grid_export_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_a_p_charge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_a_soc_pct')|float(0) %}
{% if exportw>0 and soc<100 %} {{ [exportw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_a_charge_grid_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_a_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set soc = states('sensor.sim_pack_a_soc_pct')|float(0) %}
{% set target = states('input_number.sim_pack_a_soc_target_pct')|float(0) %}
{% set pmax = states('input_number.sim_pack_a_p_charge_kw')|float(0)*1000 %}
{% if hc and soc<target %} {{ pmax }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_a_discharge_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_a_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set importw = states('sensor.sim_grid_import_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_a_p_discharge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_a_soc_pct')|float(0) %}
{% set socmin = states('input_number.sim_pack_a_soc_min_pct')|float(0) %}
{% if (not hc) and importw>0 and soc>socmin %} {{ [importw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_a_charge_effective_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_a_eta_charge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_a_charge_pv_w')|float(0) + states('sensor.sim_pack_a_charge_grid_w')|float(0) %}
{{ (p*eta)|round(3) }}
- name: sim_pack_a_discharge_internal_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_a_eta_discharge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_a_discharge_w')|float(0) %}
{% if eta>0 %} {{ (p/eta)|round(3) }} {% else %} 0 {% endif %}
# === PACK B =================================================================
- sensor:
- name: sim_pack_b_charge_pv_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_b_enabled','on') %}
{% set exportw = states('sensor.sim_grid_export_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_b_p_charge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_b_soc_pct')|float(0) %}
{% if exportw>0 and soc<100 %} {{ [exportw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_b_charge_grid_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_b_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set soc = states('sensor.sim_pack_b_soc_pct')|float(0) %}
{% set target = states('input_number.sim_pack_b_soc_target_pct')|float(0) %}
{% set pmax = states('input_number.sim_pack_b_p_charge_kw')|float(0)*1000 %}
{% if hc and soc<target %} {{ pmax }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_b_discharge_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_b_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set importw = states('sensor.sim_grid_import_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_b_p_discharge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_b_soc_pct')|float(0) %}
{% set socmin = states('input_number.sim_pack_b_soc_min_pct')|float(0) %}
{% if (not hc) and importw>0 and soc>socmin %} {{ [importw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_b_charge_effective_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_b_eta_charge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_b_charge_pv_w')|float(0) + states('sensor.sim_pack_b_charge_grid_w')|float(0) %}
{{ (p*eta)|round(3) }}
- name: sim_pack_b_discharge_internal_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_b_eta_discharge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_b_discharge_w')|float(0) %}
{% if eta>0 %} {{ (p/eta)|round(3) }} {% else %} 0 {% endif %}
# === PACK C =================================================================
- sensor:
- name: sim_pack_c_charge_pv_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_c_enabled','on') %}
{% set exportw = states('sensor.sim_grid_export_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_c_p_charge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_c_soc_pct')|float(0) %}
{% if exportw>0 and soc<100 %} {{ [exportw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_c_charge_grid_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_c_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set soc = states('sensor.sim_pack_c_soc_pct')|float(0) %}
{% set target = states('input_number.sim_pack_c_soc_target_pct')|float(0) %}
{% set pmax = states('input_number.sim_pack_c_p_charge_kw')|float(0)*1000 %}
{% if hc and soc<target %} {{ pmax }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_c_discharge_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% if is_state('input_boolean.sim_pack_c_enabled','on') %}
{% set hc = is_state('sensor.sim_hc_on','True') %}
{% set importw = states('sensor.sim_grid_import_w')|float(0) %}
{% set pmax = states('input_number.sim_pack_c_p_discharge_kw')|float(0)*1000 %}
{% set soc = states('sensor.sim_pack_c_soc_pct')|float(0) %}
{% set socmin = states('input_number.sim_pack_c_soc_min_pct')|float(0) %}
{% if (not hc) and importw>0 and soc>socmin %} {{ [importw, pmax]|min }} {% else %} 0 {% endif %}
{% else %} 0 {% endif %}
- name: sim_pack_c_charge_effective_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_c_eta_charge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_c_charge_pv_w')|float(0) + states('sensor.sim_pack_c_charge_grid_w')|float(0) %}
{{ (p*eta)|round(3) }}
- name: sim_pack_c_discharge_internal_w
unit_of_measurement: W
device_class: power
state_class: measurement
state: >
{% set eta = states('input_number.sim_pack_c_eta_discharge_pct')|float(0)/100 %}
{% set p = states('sensor.sim_pack_c_discharge_w')|float(0) %}
{% if eta>0 %} {{ (p/eta)|round(3) }} {% else %} 0 {% endif %}
# === KPI + proxys (cumulés + sélection) ====================================
- sensor:
# €/h instantané
- name: sim_pack_a_cost_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_a_charge_grid_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
- name: sim_pack_a_gain_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_a_discharge_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
- name: sim_pack_b_cost_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_b_charge_grid_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
- name: sim_pack_b_gain_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_b_discharge_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
- name: sim_pack_c_cost_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_c_charge_grid_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
- name: sim_pack_c_gain_rate_eurph
unit_of_measurement: "€/h"
state_class: measurement
state: "{{ (states('sensor.sim_pack_c_discharge_w')|float(0)/1000) * states('sensor.sim_tarif_eur_kwh')|float(0) }}"
# Energie stockée / SOC / Gains / ROI (cumulé)
- name: sim_pack_a_energy_stored_kwh
unit_of_measurement: kWh
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_a_capacity_kwh')|float(0) %}
{% set e0 = cap * (states('input_number.sim_pack_a_soc_initial_pct')|float(0)/100) %}
{% set ch = states('sensor.sim_pack_a_kwh_charge_effective')|float(0) %}
{% set de = states('sensor.sim_pack_a_kwh_discharge_internal')|float(0) %}
{{ [[e0 + ch - de,0]|max, cap]|min | round(3) }}
- name: sim_pack_a_soc_pct
unit_of_measurement: "%"
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_a_capacity_kwh')|float(0) %}
{% set e = states('sensor.sim_pack_a_energy_stored_kwh')|float(0) %}
{% if cap>0 %} {{ (100*e/cap)|round(1) }} {% else %} 0 {% endif %}
- name: sim_pack_a_gain_net_eur
unit_of_measurement: "€"
state: "{{ (states('sensor.sim_pack_a_gain_eur')|float(0) - states('sensor.sim_pack_a_cost_eur')|float(0)) | round(2) }}"
- name: sim_pack_a_roi
state: >
{% set invest = states('input_number.sim_pack_a_invest_cost_eur')|float(0) %}
{% set gain = states('sensor.sim_pack_a_gain_net_eur')|float(0) %}
{% if invest>0 %} {{ (gain/invest)|round(4) }} {% else %} 0 {% endif %}
- name: sim_pack_b_energy_stored_kwh
unit_of_measurement: kWh
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_b_capacity_kwh')|float(0) %}
{% set e0 = cap * (states('input_number.sim_pack_b_soc_initial_pct')|float(0)/100) %}
{% set ch = states('sensor.sim_pack_b_kwh_charge_effective')|float(0) %}
{% set de = states('sensor.sim_pack_b_kwh_discharge_internal')|float(0) %}
{{ [[e0 + ch - de,0]|max, cap]|min | round(3) }}
- name: sim_pack_b_soc_pct
unit_of_measurement: "%"
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_b_capacity_kwh')|float(0) %}
{% set e = states('sensor.sim_pack_b_energy_stored_kwh')|float(0) %}
{% if cap>0 %} {{ (100*e/cap)|round(1) }} {% else %} 0 {% endif %}
- name: sim_pack_b_gain_net_eur
unit_of_measurement: "€"
state: "{{ (states('sensor.sim_pack_b_gain_eur')|float(0) - states('sensor.sim_pack_b_cost_eur')|float(0)) | round(2) }}"
- name: sim_pack_b_roi
state: >
{% set invest = states('input_number.sim_pack_b_invest_cost_eur')|float(0) %}
{% set gain = states('sensor.sim_pack_b_gain_net_eur')|float(0) %}
{% if invest>0 %} {{ (gain/invest)|round(4) }} {% else %} 0 {% endif %}
- name: sim_pack_c_energy_stored_kwh
unit_of_measurement: kWh
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_c_capacity_kwh')|float(0) %}
{% set e0 = cap * (states('input_number.sim_pack_c_soc_initial_pct')|float(0)/100) %}
{% set ch = states('sensor.sim_pack_c_kwh_charge_effective')|float(0) %}
{% set de = states('sensor.sim_pack_c_kwh_discharge_internal')|float(0) %}
{{ [[e0 + ch - de,0]|max, cap]|min | round(3) }}
- name: sim_pack_c_soc_pct
unit_of_measurement: "%"
state_class: measurement
state: >
{% set cap = states('input_number.sim_pack_c_capacity_kwh')|float(0) %}
{% set e = states('sensor.sim_pack_c_energy_stored_kwh')|float(0) %}
{% if cap>0 %} {{ (100*e/cap)|round(1) }} {% else %} 0 {% endif %}
- name: sim_pack_c_gain_net_eur
unit_of_measurement: "€"
state: "{{ (states('sensor.sim_pack_c_gain_eur')|float(0) - states('sensor.sim_pack_c_cost_eur')|float(0)) | round(2) }}"
- name: sim_pack_c_roi
state: >
{% set invest = states('input_number.sim_pack_c_invest_cost_eur')|float(0) %}
{% set gain = states('sensor.sim_pack_c_gain_net_eur')|float(0) %}
{% if invest>0 %} {{ (gain/invest)|round(4) }} {% else %} 0 {% endif %}
# ------- Proxys (pack sélectionné) — cumulés
- name: sim_selected_soc_pct
unit_of_measurement: "%"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% if 'Pack A' in s %} {{ states('sensor.sim_pack_a_soc_pct') }}
{% elif 'Pack B' in s %} {{ states('sensor.sim_pack_b_soc_pct') }}
{% else %} {{ states('sensor.sim_pack_c_soc_pct') }} {% endif %}
- name: sim_selected_charge_w
unit_of_measurement: W
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% if 'Pack A' in s %} {{ (states('sensor.sim_pack_a_charge_pv_w')|float(0) + states('sensor.sim_pack_a_charge_grid_w')|float(0))|round(3) }}
{% elif 'Pack B' in s %} {{ (states('sensor.sim_pack_b_charge_pv_w')|float(0) + states('sensor.sim_pack_b_charge_grid_w')|float(0))|round(3) }}
{% else %} {{ (states('sensor.sim_pack_c_charge_pv_w')|float(0) + states('sensor.sim_pack_c_charge_grid_w')|float(0))|round(3) }} {% endif %}
- name: sim_selected_discharge_w
unit_of_measurement: W
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% if 'Pack A' in s %} {{ states('sensor.sim_pack_a_discharge_w')|float(0) }}
{% elif 'Pack B' in s %} {{ states('sensor.sim_pack_b_discharge_w')|float(0) }}
{% else %} {{ states('sensor.sim_pack_c_discharge_w')|float(0) }} {% endif %}
- name: sim_selected_gain_net_eur
unit_of_measurement: "€"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% if 'Pack A' in s %} {{ states('sensor.sim_pack_a_gain_net_eur')|float(0) }}
{% elif 'Pack B' in s %} {{ states('sensor.sim_pack_b_gain_net_eur')|float(0) }}
{% else %} {{ states('sensor.sim_pack_c_gain_net_eur')|float(0) }} {% endif %}
- name: sim_selected_roi
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% if 'Pack A' in s %} {{ states('sensor.sim_pack_a_roi')|float(0) }}
{% elif 'Pack B' in s %} {{ states('sensor.sim_pack_b_roi')|float(0) }}
{% else %} {{ states('sensor.sim_pack_c_roi')|float(0) }} {% endif %}
- name: sim_selected_roi_pct
unit_of_measurement: "%"
state: "{{ (states('sensor.sim_selected_roi')|float(0) * 100) | round(1) }}"
# === PROXYS jour/mois + Payback simple (mois courant) ======================
- sensor:
- name: sim_selected_net_day_eur
unit_of_measurement: "€"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_net_day') if 'Pack A' in s else
states('sensor.sim_pack_b_net_day') if 'Pack B' in s else
states('sensor.sim_pack_c_net_day') ) %}
{{ (v|float(0))|round(2) }}
- name: sim_selected_net_month_eur
unit_of_measurement: "€"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_net_month') if 'Pack A' in s else
states('sensor.sim_pack_b_net_month') if 'Pack B' in s else
states('sensor.sim_pack_c_net_month') ) %}
{{ (v|float(0))|round(2) }}
- name: sim_selected_chg_day_kwh
unit_of_measurement: kWh
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_chg_day') if 'Pack A' in s else
states('sensor.sim_pack_b_chg_day') if 'Pack B' in s else
states('sensor.sim_pack_c_chg_day') ) %}
{{ (v|float(0))|round(3) }}
- name: sim_selected_dis_day_kwh
unit_of_measurement: kWh
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_dis_day') if 'Pack A' in s else
states('sensor.sim_pack_b_dis_day') if 'Pack B' in s else
states('sensor.sim_pack_c_dis_day') ) %}
{{ (v|float(0))|round(3) }}
- name: sim_selected_chg_month_kwh
unit_of_measurement: kWh
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_chg_month') if 'Pack A' in s else
states('sensor.sim_pack_b_chg_month') if 'Pack B' in s else
states('sensor.sim_pack_c_chg_month') ) %}
{{ (v|float(0))|round(3) }}
- name: sim_selected_dis_month_kwh
unit_of_measurement: kWh
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_dis_month') if 'Pack A' in s else
states('sensor.sim_pack_b_dis_month') if 'Pack B' in s else
states('sensor.sim_pack_c_dis_month') ) %}
{{ (v|float(0))|round(3) }}
# --- Moyenne journalière simple basée sur le mois courant
- name: sim_pack_a_avg_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set net_m = states('sensor.sim_pack_a_net_month')|float(0) %}
{% set d = now().day|int(1) %}
{{ (net_m / d)|round(2) }}
- name: sim_pack_b_avg_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set net_m = states('sensor.sim_pack_b_net_month')|float(0) %}
{% set d = now().day|int(1) %}
{{ (net_m / d)|round(2) }}
- name: sim_pack_c_avg_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set net_m = states('sensor.sim_pack_c_net_month')|float(0) %}
{% set d = now().day|int(1) %}
{{ (net_m / d)|round(2) }}
# --- Payback simple (jours & date)
- name: sim_pack_a_payback_days
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_a_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_a_avg_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_b_payback_days
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_b_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_b_avg_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_c_payback_days
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_c_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_c_avg_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_a_payback_date
state: >
{% set days = states('sensor.sim_pack_a_payback_days')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
- name: sim_pack_b_payback_date
state: >
{% set days = states('sensor.sim_pack_b_payback_days')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
- name: sim_pack_c_payback_date
state: >
{% set days = states('sensor.sim_pack_c_payback_days')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
- name: sim_selected_payback_days
unit_of_measurement: "jours"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_payback_days') if 'Pack A' in s else
states('sensor.sim_pack_b_payback_days') if 'Pack B' in s else
states('sensor.sim_pack_c_payback_days') ) %}
{{ v|float(0)|round(0) }}
- name: sim_selected_payback_date
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_payback_date') if 'Pack A' in s else
states('sensor.sim_pack_b_payback_date') if 'Pack B' in s else
states('sensor.sim_pack_c_payback_date') ) %}
{{ v if v not in ['unknown','unavailable','None'] else 0 }}
# === PAYBACK 30 jours + PROJECTIONS & LONG TERME ===========================
- sensor:
# Gain net d'hier (utilise last_period des utility_meter jour)
- name: sim_pack_a_net_yesterday_eur
unit_of_measurement: "€"
state: "{{ state_attr('sensor.sim_pack_a_net_day','last_period')|float(0)|round(2) }}"
- name: sim_pack_b_net_yesterday_eur
unit_of_measurement: "€"
state: "{{ state_attr('sensor.sim_pack_b_net_day','last_period')|float(0)|round(2) }}"
- name: sim_pack_c_net_yesterday_eur
unit_of_measurement: "€"
state: "{{ state_attr('sensor.sim_pack_c_net_day','last_period')|float(0)|round(2) }}"
# Moyenne 30j (miroirs lisibles des statistics)
- name: sim_pack_a_avg30d_net_day_eur
unit_of_measurement: "€/j"
state: "{{ states('sensor.sim_pack_a_avg30d_net_day_eur_stat')|float(0)|round(2) }}"
- name: sim_pack_b_avg30d_net_day_eur
unit_of_measurement: "€/j"
state: "{{ states('sensor.sim_pack_b_avg30d_net_day_eur_stat')|float(0)|round(2) }}"
- name: sim_pack_c_avg30d_net_day_eur
unit_of_measurement: "€/j"
state: "{{ states('sensor.sim_pack_c_avg30d_net_day_eur_stat')|float(0)|round(2) }}"
# Payback 30j + date
- name: sim_pack_a_payback_days_30d
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_a_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_a_avg30d_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_b_payback_days_30d
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_b_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_b_avg30d_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_c_payback_days_30d
unit_of_measurement: "jours"
state: >
{% set invest = states('input_number.sim_pack_c_invest_cost_eur')|float(0) %}
{% set avg = states('sensor.sim_pack_c_avg30d_net_day_eur')|float(0) %}
{% if avg > 0 %} {{ (invest / avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_pack_a_payback_date_30d
state: >
{% set days = states('sensor.sim_pack_a_payback_days_30d')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
- name: sim_pack_b_payback_date_30d
state: >
{% set days = states('sensor.sim_pack_b_payback_days_30d')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
- name: sim_pack_c_payback_date_30d
state: >
{% set days = states('sensor.sim_pack_c_payback_days_30d')|float(0) %}
{% if days > 0 %} {{ (now().timestamp() + days*86400) | timestamp_custom('%Y-%m-%d', true) }} {% else %} 0 {% endif %}
# Proxys sélection 30j
- name: sim_selected_avg30d_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_avg30d_net_day_eur') if 'Pack A' in s else
states('sensor.sim_pack_b_avg30d_net_day_eur') if 'Pack B' in s else
states('sensor.sim_pack_c_avg30d_net_day_eur') ) %}
{{ v|float(0)|round(2) }}
- name: sim_selected_payback_days_30d
unit_of_measurement: "jours"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_payback_days_30d') if 'Pack A' in s else
states('sensor.sim_pack_b_payback_days_30d') if 'Pack B' in s else
states('sensor.sim_pack_c_payback_days_30d') ) %}
{{ v|float(0)|round(0) }}
- name: sim_selected_payback_date_30d
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_payback_date_30d') if 'Pack A' in s else
states('sensor.sim_pack_b_payback_date_30d') if 'Pack B' in s else
states('sensor.sim_pack_c_payback_date_30d') ) %}
{{ v if v not in ['unknown','unavailable','None'] else 0 }}
# ===== PROJECTIONS (basées sur la moyenne 30 j) =====
- name: sim_selected_projection_month_eur
unit_of_measurement: "€"
state: >
{% set avg = states('sensor.sim_selected_avg30d_net_day_eur')|float(0) %}
{% set days_in_month = ((now().replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1)).day %}
{{ (avg * days_in_month)|round(2) }}
- name: sim_selected_projection_year_eur
unit_of_measurement: "€"
state: >
{% set avg = states('sensor.sim_selected_avg30d_net_day_eur')|float(0) %}
{{ (avg * 365)|round(0) }}
- name: sim_selected_projection_confidence_pct
unit_of_measurement: "%"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set stat_ent =
('sensor.sim_pack_a_avg30d_net_day_eur_stat' if 'Pack A' in s else
'sensor.sim_pack_b_avg30d_net_day_eur_stat' if 'Pack B' in s else
'sensor.sim_pack_c_avg30d_net_day_eur_stat') %}
{% set cnt = state_attr(stat_ent, 'count')|int(0) %}
{% set pct = ( (cnt / 30) if cnt>0 else 0 ) * 100 %}
{{ [pct, 100]|min|round(0) }}
- name: sim_selected_projection_label
state: >
Projection basée sur moyenne 30 j (confiance {{ states('sensor.sim_selected_projection_confidence_pct')|float(0)|round(0) }}%)
# ===== LONG TERME : 180j & 360j (moyennes & payback) =====
- name: sim_selected_avg180d_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_avg180d_net_day_eur_stat') if 'Pack A' in s else
states('sensor.sim_pack_b_avg180d_net_day_eur_stat') if 'Pack B' in s else
states('sensor.sim_pack_c_avg180d_net_day_eur_stat') ) %}
{{ v|float(0)|round(2) }}
- name: sim_selected_payback_days_180d
unit_of_measurement: "jours"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set avg =
( states('sensor.sim_pack_a_avg180d_net_day_eur_stat') if 'Pack A' in s else
states('sensor.sim_pack_b_avg180d_net_day_eur_stat') if 'Pack B' in s else
states('sensor.sim_pack_c_avg180d_net_day_eur_stat') )|float(0) %}
{% set invest =
( states('input_number.sim_pack_a_invest_cost_eur') if 'Pack A' in s else
states('input_number.sim_pack_b_invest_cost_eur') if 'Pack B' in s else
states('input_number.sim_pack_c_invest_cost_eur') )|float(0) %}
{% if avg>0 %} {{ (invest/avg)|round(0) }} {% else %} 0 {% endif %}
- name: sim_selected_avg360d_net_day_eur
unit_of_measurement: "€/j"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set v =
( states('sensor.sim_pack_a_avg360d_net_day_eur_stat') if 'Pack A' in s else
states('sensor.sim_pack_b_avg360d_net_day_eur_stat') if 'Pack B' in s else
states('sensor.sim_pack_c_avg360d_net_day_eur_stat') ) %}
{{ v|float(0)|round(2) }}
- name: sim_selected_payback_days_360d
unit_of_measurement: "jours"
state: >
{% set s = states('input_select.sim_pack_selected') %}
{% set avg =
( states('sensor.sim_pack_a_avg360d_net_day_eur_stat') if 'Pack A' in s else
states('sensor.sim_pack_b_avg360d_net_day_eur_stat') if 'Pack B' in s else
states('sensor.sim_pack_c_avg360d_net_day_eur_stat') )|float(0) %}
{% set invest =
( states('input_number.sim_pack_a_invest_cost_eur') if 'Pack A' in s else
states('input_number.sim_pack_b_invest_cost_eur') if 'Pack B' in s else
states('input_number.sim_pack_c_invest_cost_eur') )|float(0) %}
{% if avg>0 %} {{ (invest/avg)|round(0) }} {% else %} 0 {% endif %}
# -----------------------------------------------------------------------------
# INTEGRATIONS (W→kWh et €/h→€) + STATISTICS 30/180/360 j
# -----------------------------------------------------------------------------
sensor:
# A (énergies)
- platform: integration
name: sim_pack_a_kwh_charge_pv
source: sensor.sim_pack_a_charge_pv_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_a_kwh_charge_grid
source: sensor.sim_pack_a_charge_grid_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_a_kwh_charge_effective
source: sensor.sim_pack_a_charge_effective_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_a_kwh_discharge_home
source: sensor.sim_pack_a_discharge_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_a_kwh_discharge_internal
source: sensor.sim_pack_a_discharge_internal_w
unit_prefix: k
round: 4
method: trapezoidal
# B (énergies)
- platform: integration
name: sim_pack_b_kwh_charge_pv
source: sensor.sim_pack_b_charge_pv_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_b_kwh_charge_grid
source: sensor.sim_pack_b_charge_grid_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_b_kwh_charge_effective
source: sensor.sim_pack_b_charge_effective_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_b_kwh_discharge_home
source: sensor.sim_pack_b_discharge_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_b_kwh_discharge_internal
source: sensor.sim_pack_b_discharge_internal_w
unit_prefix: k
round: 4
method: trapezoidal
# C (énergies)
- platform: integration
name: sim_pack_c_kwh_charge_pv
source: sensor.sim_pack_c_charge_pv_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_c_kwh_charge_grid
source: sensor.sim_pack_c_charge_grid_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_c_kwh_charge_effective
source: sensor.sim_pack_c_charge_effective_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_c_kwh_discharge_home
source: sensor.sim_pack_c_discharge_w
unit_prefix: k
round: 4
method: trapezoidal
- platform: integration
name: sim_pack_c_kwh_discharge_internal
source: sensor.sim_pack_c_discharge_internal_w
unit_prefix: k
round: 4
method: trapezoidal
# € cumulés
- platform: integration
name: sim_pack_a_cost_eur
source: sensor.sim_pack_a_cost_rate_eurph
method: trapezoidal
unit_time: h
round: 2
- platform: integration
name: sim_pack_a_gain_eur
source: sensor.sim_pack_a_gain_rate_eurph
method: trapezoidal
unit_time: h
round: 2
- platform: integration
name: sim_pack_b_cost_eur
source: sensor.sim_pack_b_cost_rate_eurph
method: trapezoidal
unit_time: h
round: 2
- platform: integration
name: sim_pack_b_gain_eur
source: sensor.sim_pack_b_gain_rate_eurph
method: trapezoidal
unit_time: h
round: 2
- platform: integration
name: sim_pack_c_cost_eur
source: sensor.sim_pack_c_cost_rate_eurph
method: trapezoidal
unit_time: h
round: 2
- platform: integration
name: sim_pack_c_gain_eur
source: sensor.sim_pack_c_gain_rate_eurph
method: trapezoidal
unit_time: h
round: 2
# ======= Moyenne glissante 30/180/360 jours du gain net quotidien (par pack)
- platform: statistics
name: sim_pack_a_avg30d_net_day_eur_stat
entity_id: sensor.sim_pack_a_net_yesterday_eur
state_characteristic: mean
max_age: { days: 30 }
sampling_size: 60
- platform: statistics
name: sim_pack_b_avg30d_net_day_eur_stat
entity_id: sensor.sim_pack_b_net_yesterday_eur
state_characteristic: mean
max_age: { days: 30 }
sampling_size: 60
- platform: statistics
name: sim_pack_c_avg30d_net_day_eur_stat
entity_id: sensor.sim_pack_c_net_yesterday_eur
state_characteristic: mean
max_age: { days: 30 }
sampling_size: 60
- platform: statistics
name: sim_pack_a_avg180d_net_day_eur_stat
entity_id: sensor.sim_pack_a_net_yesterday_eur
state_characteristic: mean
max_age: { days: 180 }
sampling_size: 400
- platform: statistics
name: sim_pack_b_avg180d_net_day_eur_stat
entity_id: sensor.sim_pack_b_net_yesterday_eur
state_characteristic: mean
max_age: { days: 180 }
sampling_size: 400
- platform: statistics
name: sim_pack_c_avg180d_net_day_eur_stat
entity_id: sensor.sim_pack_c_net_yesterday_eur
state_characteristic: mean
max_age: { days: 180 }
sampling_size: 400
- platform: statistics
name: sim_pack_a_avg360d_net_day_eur_stat
entity_id: sensor.sim_pack_a_net_yesterday_eur
state_characteristic: mean
max_age: { days: 360 }
sampling_size: 800
- platform: statistics
name: sim_pack_b_avg360d_net_day_eur_stat
entity_id: sensor.sim_pack_b_net_yesterday_eur
state_characteristic: mean
max_age: { days: 360 }
sampling_size: 800
- platform: statistics
name: sim_pack_c_avg360d_net_day_eur_stat
entity_id: sensor.sim_pack_c_net_yesterday_eur
state_characteristic: mean
max_age: { days: 360 }
sampling_size: 800
# -----------------------------------------------------------------------------
# UTILITY METERS (jour / mois) par pack
# -----------------------------------------------------------------------------
utility_meter:
# ---- Pack A
sim_pack_a_cost_day: { source: sensor.sim_pack_a_cost_eur, cycle: daily }
sim_pack_a_cost_month: { source: sensor.sim_pack_a_cost_eur, cycle: monthly }
sim_pack_a_gain_day: { source: sensor.sim_pack_a_gain_eur, cycle: daily }
sim_pack_a_gain_month: { source: sensor.sim_pack_a_gain_eur, cycle: monthly }
sim_pack_a_net_day: { source: sensor.sim_pack_a_gain_net_eur, cycle: daily }
sim_pack_a_net_month: { source: sensor.sim_pack_a_gain_net_eur, cycle: monthly }
sim_pack_a_chg_day: { source: sensor.sim_pack_a_kwh_charge_effective, cycle: daily }
sim_pack_a_dis_day: { source: sensor.sim_pack_a_kwh_discharge_internal, cycle: daily }
sim_pack_a_chg_month: { source: sensor.sim_pack_a_kwh_charge_effective, cycle: monthly }
sim_pack_a_dis_month: { source: sensor.sim_pack_a_kwh_discharge_internal, cycle: monthly }
# ---- Pack B
sim_pack_b_cost_day: { source: sensor.sim_pack_b_cost_eur, cycle: daily }
sim_pack_b_cost_month: { source: sensor.sim_pack_b_cost_eur, cycle: monthly }
sim_pack_b_gain_day: { source: sensor.sim_pack_b_gain_eur, cycle: daily }
sim_pack_b_gain_month: { source: sensor.sim_pack_b_gain_eur, cycle: monthly }
sim_pack_b_net_day: { source: sensor.sim_pack_b_gain_net_eur, cycle: daily }
sim_pack_b_net_month: { source: sensor.sim_pack_b_gain_net_eur, cycle: monthly }
sim_pack_b_chg_day: { source: sensor.sim_pack_b_kwh_charge_effective, cycle: daily }
sim_pack_b_dis_day: { source: sensor.sim_pack_b_kwh_discharge_internal, cycle: daily }
sim_pack_b_chg_month: { source: sensor.sim_pack_b_kwh_charge_effective, cycle: monthly }
sim_pack_b_dis_month: { source: sensor.sim_pack_b_kwh_discharge_internal, cycle: monthly }
# ---- Pack C
sim_pack_c_cost_day: { source: sensor.sim_pack_c_cost_eur, cycle: daily }
sim_pack_c_cost_month: { source: sensor.sim_pack_c_cost_eur, cycle: monthly }
sim_pack_c_gain_day: { source: sensor.sim_pack_c_gain_eur, cycle: daily }
sim_pack_c_gain_month: { source: sensor.sim_pack_c_gain_eur, cycle: monthly }
sim_pack_c_net_day: { source: sensor.sim_pack_c_gain_net_eur, cycle: daily }
sim_pack_c_net_month: { source: sensor.sim_pack_c_gain_net_eur, cycle: monthly }
sim_pack_c_chg_day: { source: sensor.sim_pack_c_kwh_charge_effective, cycle: daily }
sim_pack_c_dis_day: { source: sensor.sim_pack_c_kwh_discharge_internal, cycle: daily }
sim_pack_c_chg_month: { source: sensor.sim_pack_c_kwh_charge_effective, cycle: monthly }
sim_pack_c_dis_month: { source: sensor.sim_pack_c_kwh_discharge_internal, cycle: monthly }
et carte :
type: vertical-stack
cards:
- type: entities
title: Simulation batteries — sélection & activation
entities:
- entity: input_select.sim_pack_selected
name: Pack affiché
- entity: input_boolean.sim_pack_a_enabled
name: Pack A actif
- entity: input_boolean.sim_pack_b_enabled
name: Pack B actif
- entity: input_boolean.sim_pack_c_enabled
name: Pack C actif
- type: custom:power-flow-card-plus
title: Consommation instantanée
entities:
grid:
entity:
consumption: sensor.sim_grid_import_w
production: sensor.sim_grid_export_w
display_state: one_way
solar:
entity: sensor.sim_pv_power_w
battery:
entity:
consumption: sensor.sim_selected_charge_w
production: sensor.sim_selected_discharge_w
state_of_charge: sensor.sim_selected_soc_pct
display_state: one_way
home:
entity: sensor.sim_home_demand_w
clickable_entities: true
use_new_flow_rate_model: true
w_decimals: 0
kw_decimals: 2
watt_threshold: 0
- type: markdown
content: |
## {{ states('input_select.sim_pack_selected') }}
- type: grid
columns: 2
square: false
cards:
- type: gauge
name: SOC
entity: sensor.sim_selected_soc_pct
min: 0
max: 100
needle: true
- type: gauge
name: ROI
entity: sensor.sim_selected_roi_pct
min: 0
max: 100
needle: true
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_net_day_eur
name: Gain net (jour)
icon: mdi:cash-plus
state_content:
- state
- type: tile
entity: sensor.sim_selected_net_month_eur
name: Gain net (mois)
icon: mdi:calendar-month
state_content:
- state
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_chg_day_kwh
name: Charge (jour)
icon: mdi:battery-arrow-up
state_content:
- state
- type: tile
entity: sensor.sim_selected_dis_day_kwh
name: Décharge (jour)
icon: mdi:battery-arrow-down
state_content:
- state
- type: tile
entity: sensor.sim_selected_chg_month_kwh
name: Charge (mois)
icon: mdi:battery-arrow-up
state_content:
- state
- type: tile
entity: sensor.sim_selected_dis_month_kwh
name: Décharge (mois)
icon: mdi:battery-arrow-down
state_content:
- state
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_payback_days
name: Délai de renta (jours)
icon: mdi:calendar-clock
state_content:
- state
- type: tile
entity: sensor.sim_selected_payback_date
name: Date d’amortissement
icon: mdi:calendar-check
state_content:
- state
- type: markdown
content: >
### 📈 Projection (basée sur moyenne 30 j) *{{
states('sensor.sim_selected_projection_label') }} — ce n'est pas une
garantie.*
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_avg30d_net_day_eur
name: Gain net moyen (30 j)
icon: mdi:chart-line
- type: tile
entity: sensor.sim_selected_payback_days_30d
name: Délai de renta (30 j)
icon: mdi:calendar-clock
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_projection_month_eur
name: Projection mois (€/mois)
icon: mdi:calendar-month-outline
- type: tile
entity: sensor.sim_selected_projection_year_eur
name: Projection année (€/an)
icon: mdi:calendar-range
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_payback_date_30d
name: Date d’amortissement (projection 30 j)
icon: mdi:calendar-check
- type: tile
entity: sensor.sim_selected_projection_confidence_pct
name: Confiance projection
icon: mdi:shield-check
- type: markdown
content: |
### 🔮 Projection long terme (moyennes 180 j & 360 j)
- type: grid
columns: 2
square: false
cards:
- type: tile
entity: sensor.sim_selected_avg180d_net_day_eur
name: Gain net moyen (180 j)
icon: mdi:chart-line
- type: tile
entity: sensor.sim_selected_payback_days_180d
name: Délai de renta (180 j)
icon: mdi:calendar-clock
- type: tile
entity: sensor.sim_selected_avg360d_net_day_eur
name: Gain net moyen (360 j)
icon: mdi:chart-line
- type: tile
entity: sensor.sim_selected_payback_days_360d
name: Délai de renta (360 j)
icon: mdi:calendar-clock
- type: entities
title: Debug PFCP (doivent exister)
show_header_toggle: false
entities:
- entity: sensor.sim_grid_import_w
name: Réseau → Maison (import)
- entity: sensor.sim_grid_export_w
name: Maison → Réseau (export)
- entity: sensor.sim_pv_power_w
name: Solaire (puissance instantanée)
- entity: sensor.sim_home_demand_w
name: Demande Maison (W mesuré)
- entity: sensor.sim_selected_soc_pct
name: SOC batterie (pack sélectionné)
- entity: sensor.sim_selected_charge_w
name: Flux vers batterie (charge)
- entity: sensor.sim_selected_discharge_w
name: Flux depuis batterie (décharge)
- entity: sensor.sim_tarif_eur_kwh
name: Tarif EDF instantané (€/kWh)




