Les cartes markdown utilisaient un bloc YAML replie (content: >), qui remplace les retours a la ligne par des espaces : les tableaux markdown perdaient leur structure et s'affichaient comme une ligne de texte avec des barres verticales. Passage en bloc litteral (content: |) sur les six cartes, et le tableau des profils emet desormais chaque ligne sur la meme ligne que la boucle, sinon Jinja intercale une ligne vide entre chaque rangee et casse le tableau. Ajout d'un repli lisible quand les profils ne sont pas encore publies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
199 lines
8.1 KiB
YAML
199 lines
8.1 KiB
YAML
views:
|
|
# ===================================================================
|
|
- title: Bilan
|
|
path: bilan
|
|
icon: mdi:scale-balance
|
|
cards:
|
|
- type: vertical-stack
|
|
cards:
|
|
- type: custom:mushroom-title-card
|
|
title: Bilan énergétique
|
|
subtitle: Mode ombre — observe et publie, ne pilote rien
|
|
|
|
- type: conditional
|
|
conditions:
|
|
- entity: input_text.evcs_balance_status
|
|
state_not: "ok"
|
|
card:
|
|
type: markdown
|
|
content: |
|
|
## ⚠️ Bilan indisponible
|
|
|
|
{{ states('input_text.evcs_balance_reason') }}
|
|
|
|
Les contrôleurs fonctionnent sur leurs règles historiques.
|
|
|
|
# --- LA comparaison qui décidera du câblage ---------------------
|
|
- type: markdown
|
|
title: Seuil calculé contre seuil fixe
|
|
content: |
|
|
{% set req = states('input_number.evcs_balance_required_soc') | float(0) %}
|
|
{% set fixe = states('input_number.victron_grid_soc_off') | float(0) %}
|
|
{% set soc = states('sensor.victron_battery_soc') | float(0) %}
|
|
{% set ecart = req - fixe %}
|
|
| | |
|
|
|---|---:|
|
|
| SOC batterie **maintenant** | **{{ soc | round(0) }} %** |
|
|
| Seuil **calculé** par le bilan | **{{ req | round(1) }} %** |
|
|
| Seuil **fixe** encore en vigueur | {{ fixe | round(0) }} % |
|
|
| Écart | {{ '+' if ecart >= 0 else '' }}{{ ecart | round(1) }} points |
|
|
|
|
{% if req > fixe %}
|
|
Le seuil fixe est aujourd'hui **trop bas** : il laisserait la batterie
|
|
descendre sous ce qu'il faut pour tenir jusqu'au croisement.
|
|
{% elif req < fixe %}
|
|
Le seuil fixe est aujourd'hui **trop haut** : il fait importer du
|
|
réseau au-delà du nécessaire.
|
|
{% else %}
|
|
Les deux coïncident.
|
|
{% endif %}
|
|
|
|
*C'est l'accumulation de cet écart, jour après jour, qui décidera si
|
|
le bilan prend la main.*
|
|
|
|
# --- Décision immédiate ----------------------------------------
|
|
- type: entities
|
|
title: Décision immédiate
|
|
state_color: true
|
|
entities:
|
|
- entity: input_boolean.evcs_balance_grid_needed
|
|
name: Réseau nécessaire
|
|
- entity: input_text.evcs_balance_crossing_hour
|
|
name: Croisement production / consommation
|
|
- entity: input_number.evcs_balance_energy_to_cover_kwh
|
|
name: Énergie à couvrir d'ici là
|
|
- entity: input_number.evcs_balance_grid_energy_needed_kwh
|
|
name: Énergie réseau strictement nécessaire
|
|
- type: divider
|
|
- entity: input_number.evcs_balance_required_soc
|
|
name: SOC requis (décision)
|
|
- entity: input_number.evcs_balance_required_soc_prudent
|
|
name: SOC requis (planification)
|
|
|
|
# --- La nuit qui vient ------------------------------------------
|
|
- type: entities
|
|
title: Prochaine traversée déficitaire
|
|
entities:
|
|
- entity: input_text.evcs_balance_next_deficit_window
|
|
name: Fenêtre
|
|
- entity: input_number.evcs_balance_next_deficit_kwh
|
|
name: Énergie à fournir
|
|
- entity: input_number.evcs_balance_next_deficit_required_soc
|
|
name: SOC à atteindre avant
|
|
- entity: input_number.evcs_balance_storage_shortfall_kwh
|
|
name: Capacité de stockage manquante
|
|
|
|
- type: conditional
|
|
conditions:
|
|
- entity: input_number.evcs_balance_storage_shortfall_kwh
|
|
state_not: "0.0"
|
|
card:
|
|
type: markdown
|
|
content: |
|
|
### 🔋 Stockage insuffisant pour cette traversée
|
|
|
|
Il manque **{{ states('input_number.evcs_balance_storage_shortfall_kwh') }} kWh**
|
|
de capacité utile : même chargée à 100 %, la batterie actuelle
|
|
({{ states('input_number.evcs_balance_usable_capacity_kwh') }} kWh)
|
|
ne passe pas la fenêtre sans réseau.
|
|
|
|
*Un module US2000C ≈ 2,4 kWh nominal.*
|
|
|
|
# --- Ce qu'on jette ---------------------------------------------
|
|
- type: markdown
|
|
title: Production
|
|
content: |
|
|
{% set bride = is_state('input_boolean.evcs_balance_pv_censored', 'on') %}
|
|
|
|
{% if bride %}
|
|
### 🔻 Production actuellement **bridée**
|
|
|
|
Motif : *{{ states('input_text.evcs_balance_censor_reason') }}*
|
|
|
|
Sans injection réseau, l'onduleur ne produit que ce que le système
|
|
peut absorber. Le soleil est là, il manque un preneur.
|
|
{% else %}
|
|
### ☀️ Production **libre**
|
|
|
|
Rien ne bride l'onduleur en ce moment : la mesure de production
|
|
reflète la ressource réelle.
|
|
{% endif %}
|
|
|
|
Surplus attendu pour le véhicule aujourd'hui :
|
|
**{{ states('input_number.evcs_balance_vehicle_surplus_kwh') }} kWh**
|
|
|
|
- type: history-graph
|
|
title: SOC réel contre seuil calculé
|
|
hours_to_show: 48
|
|
entities:
|
|
- entity: sensor.victron_battery_soc
|
|
name: SOC batterie
|
|
- entity: input_number.evcs_balance_required_soc
|
|
name: Seuil calculé
|
|
- entity: input_number.victron_grid_soc_off
|
|
name: Seuil fixe
|
|
|
|
- type: history-graph
|
|
title: Bridage de la production
|
|
hours_to_show: 48
|
|
entities:
|
|
- entity: input_boolean.evcs_balance_pv_censored
|
|
name: Production bridée
|
|
- entity: switch.edf_general_ok_switch
|
|
name: Réseau EDF
|
|
|
|
# ===================================================================
|
|
- title: Profils & réglages
|
|
path: profils
|
|
icon: mdi:chart-bell-curve
|
|
cards:
|
|
- type: custom:mushroom-title-card
|
|
title: Profils mesurés
|
|
subtitle: Recalculés chaque nuit à 03:30 sur l'historique réel
|
|
|
|
- type: markdown
|
|
title: Profil horaire de consommation (kWh/h, hors véhicule)
|
|
content: |
|
|
{% set p50 = states('input_text.evcs_balance_consumption_p50').split(',') %}
|
|
{% set p80 = states('input_text.evcs_balance_consumption_p80').split(',') %}
|
|
{% set env = states('input_text.evcs_balance_envelope').split(',') %}
|
|
{% set cen = states('input_text.evcs_balance_censorship_rate').split(',') %}
|
|
{% set ok = p50 | length == 24 and p80 | length == 24 and env | length == 24 and cen | length == 24 %}
|
|
{% if not ok %}Profils indisponibles — le recalcul quotidien n'a pas encore publié.
|
|
{% else %}
|
|
| h | conso typique | conso prudente | production max | censure |
|
|
|---:|---:|---:|---:|---:|
|
|
{% for i in range(24) %}| {{ '%02d' | format(i) }} | {{ p50[i] }} | {{ p80[i] }} | {{ env[i] }} | {{ (cen[i] | float(1) * 100) | round(0) }} % |
|
|
{% endfor %}{% endif %}
|
|
|
|
*La colonne « censure » indique la part des jours où la batterie était
|
|
pleine à cette heure : au-delà de 25 %, la production maximale
|
|
observée est minorée et le bilan le signale.*
|
|
|
|
- type: entities
|
|
title: Réglages
|
|
entities:
|
|
- entity: input_number.evcs_balance_usable_capacity_kwh
|
|
name: Capacité batterie utile
|
|
- entity: input_boolean.evcs_balance_enabled
|
|
name: Bilan actif (kill-switch)
|
|
- type: divider
|
|
- entity: input_text.evcs_balance_status
|
|
name: Statut
|
|
- entity: input_text.evcs_balance_last_run
|
|
name: Dernière exécution
|
|
- entity: input_text.evcs_balance_reason
|
|
name: Explication
|
|
|
|
- type: markdown
|
|
content: |
|
|
### À propos
|
|
|
|
Ce bilan remplace des seuils fixes par des grandeurs mesurées. Il
|
|
**n'écrit que dans ses propres entités** `evcs_balance_*` : aucun
|
|
interrupteur, aucune consigne de borne, aucune stratégie. Cette
|
|
garantie est vérifiée par la suite de tests du dépôt, qui échoue si
|
|
une écriture sort de ce périmètre.
|
|
|
|
Détail de la démarche : `docs/CHANTIER_BILAN_ENERGETIQUE.md`.
|