Grafana vehicules : resume en tableau, couleurs fixes ; HANDOFF concierge vehicule non confirme

This commit is contained in:
Tallagrand Thierry
2026-10-03 23:57:18 +02:00
parent eabd55f0cb
commit 9b283292bc
3 changed files with 227 additions and 63 deletions

View File

@@ -1492,6 +1492,31 @@ du 03-04/10 = test du budget.
vehicule_sur=false`). Session close : le service ne la reecrit pas. La session de
13:10 (JEEP, 4,6 kWh, a confirmer) est bien la JEEP.
- JEEP rebranchee a 20:14, concierge 20:20 : la nuit du 03-04/10 reste le test du budget.
- **Suite (03/10 ~23:55, accord du proprietaire)** :
- Grafana « Sur la periode » : panneau `stat` (chiffres empiles, illisible) remplace par
un TABLEAU pleine largeur, une colonne par vehicule (VW, JEEP, ZERO, Invite, Non
etiquete, Sessions, A confirmer), couleurs fixes partagees avec l'histogramme
(`COULEURS_VEHICULES` : VW bleu, JEEP vert, ZERO violet, Invite jaune, Non etiquete
orange) — l'histogramme prenait la palette par defaut (JEEP en jaune). Verifie par
l'API : 7 jours = JEEP 62,5 / ZERO 4,7.
- `session_charge` 13:10 (JEEP) passee a **confirmee** en base.
- **Releve SPARK des reponses reelles du 03/10** : ZERO 48 % (17:11) et JEEP 54 %
(20:22) conformes. Mais a 14:13 « JEEP » a ete ANNULE par OpenClaw (« Skipped due to
queued user message », le « 53% » suivant etait deja en file) : seul le niveau a ete
note, le branchement de 13:06 est reste sans etiquette. Et « C'etait 53% a 13h10 » ->
l'agent a repondu « Noté : 53 % à 13:10 » (heure inventee, le script n'en enregistre
pas).
- **`concierge-live.js` (fait par moi, SPARK prevenu avant/apres)** : (1) un niveau
seul alors que le branchement en cours n'a pas d'etiquette concierge (ou historique
illisible) -> la ligne finit par « ⚠️ Véhicule non confirmé pour ce branchement :
lequel est-ce ? » ; le vehicule du selecteur n'est JAMAIS publie ; (2) la ligne du
niveau porte l'heure de saisie : « 🔋 Niveau noté : 53 % (saisi à 14:15). ».
7 cas verifies en simulation (niveau seul etiquete / non etiquete / base muette,
vehicule + niveau, 150 % refuse, voiture debranchee, vehicule seul). Sauvegarde
`concierge-live.js.bak-nonconfirme-20261003-235613`.
- Horodatage « [Sat 2026-10-03 14:14 GMT+2 » dans un WhatsApp : ecrit par le MODELE
(il a recopie l'enveloppe des messages entrants apres l'appel annule), pas par le
gateway. Une occurrence : SPARK surveille, pas de regle de fiche.
---
*Document mis a jour le : 03/10/2026 (soir) — Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*
*Document mis a jour le : 03/10/2026 (~23:55) — concierge : vehicule non confirme demande, heure de saisie ; Grafana vehicules en tableau ; Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*

View File

@@ -60,9 +60,9 @@
},
"panels": [
{
"type": "stat",
"type": "table",
"title": "Sur la periode",
"description": "« Etiquette douteuse » compte les sessions ou le selecteur a change en cours de route, ou n'etait pas renseigne. C'est la mesure honnete de l'incertitude : elle ne peut pas etre levee autrement qu'en positionnant le selecteur au branchement.",
"description": "kWh charges par vehicule sur la plage choisie (compteur de la borne). « Invite » = tout vehicule hors foyer (Megane de service, amis). « A confirmer » compte les sessions dont l'etiquette vient du selecteur sans confirmation : la seule mesure honnete de l'incertitude.",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "evcs-pg"
@@ -77,30 +77,24 @@
"format": "table",
"rawQuery": true,
"editorMode": "code",
"rawSql": "SELECT round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'VW'), 0)::numeric, 1) AS \"VW\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'JEEP'), 0)::numeric, 1) AS \"JEEP\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'ZERO'), 0)::numeric, 1) AS \"ZERO\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule NOT IN ('VW', 'JEEP', 'ZERO')), 0)::numeric, 1) AS \"Invite\",\n count(*) AS \"Sessions\",\n count(*) FILTER (WHERE NOT vehicule_sur OR vehicule IS NULL) AS \"A confirmer\"\nFROM session_charge WHERE $__timeFilter(debut)"
"rawSql": "SELECT round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'VW'), 0)::numeric, 1) AS \"VW\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'JEEP'), 0)::numeric, 1) AS \"JEEP\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'ZERO'), 0)::numeric, 1) AS \"ZERO\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule NOT IN ('VW', 'JEEP', 'ZERO')), 0)::numeric, 1) AS \"Invite\",\n round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule IS NULL), 0)::numeric, 1) AS \"Non etiquete\",\n count(*) AS \"Sessions\",\n count(*) FILTER (WHERE NOT vehicule_sur OR vehicule IS NULL) AS \"A confirmer\"\nFROM session_charge WHERE $__timeFilter(debut)"
}
],
"gridPos": {
"x": 0,
"y": 0,
"w": 24,
"h": 5
"h": 4
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "text",
"value": null
}
]
},
"mappings": []
"custom": {
"align": "left",
"cellOptions": {
"type": "auto"
},
"filterable": true
}
},
"overrides": [
{
@@ -113,6 +107,16 @@
"id": "unit",
"value": "kwatth"
},
{
"id": "decimals",
"value": 1
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "color",
"value": {
@@ -132,6 +136,16 @@
"id": "unit",
"value": "kwatth"
},
{
"id": "decimals",
"value": 1
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "color",
"value": {
@@ -151,6 +165,16 @@
"id": "unit",
"value": "kwatth"
},
{
"id": "decimals",
"value": 1
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "color",
"value": {
@@ -170,6 +194,16 @@
"id": "unit",
"value": "kwatth"
},
{
"id": "decimals",
"value": 1
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "color",
"value": {
@@ -182,9 +216,44 @@
{
"matcher": {
"id": "byName",
"options": "Etiquette douteuse"
"options": "Non etiquete"
},
"properties": [
{
"id": "unit",
"value": "kwatth"
},
{
"id": "decimals",
"value": 1
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "orange"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "A confirmer"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "thresholds",
"value": {
@@ -200,31 +269,23 @@
}
]
}
},
{
"id": "color",
"value": {
"mode": "thresholds"
}
}
]
}
]
},
"options": {
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "horizontal",
"textMode": "auto",
"colorMode": "value",
"graphMode": "none",
"justifyMode": "center",
"percentChangeColorMode": "standard",
"noValue": "—",
"text": {
"valueSize": 34,
"titleSize": 12
},
"wideLayout": true
"showHeader": true,
"cellHeight": "sm",
"footer": {
"show": false
}
}
},
{
@@ -250,7 +311,7 @@
],
"gridPos": {
"x": 0,
"y": 5,
"y": 4,
"w": 24,
"h": 9
},
@@ -267,7 +328,83 @@
"axisBorderShow": false
}
},
"overrides": []
"overrides": [
{
"matcher": {
"id": "byName",
"options": "VW"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "blue"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "JEEP"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "green"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "ZERO"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "purple"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Invite"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "yellow"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Non etiquete"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "orange"
}
}
]
}
]
},
"options": {
"orientation": "auto",
@@ -310,7 +447,7 @@
],
"gridPos": {
"x": 0,
"y": 14,
"y": 13,
"w": 24,
"h": 11
},

View File

@@ -1347,6 +1347,9 @@ WHERE $__timeFilter(debut)
GROUP BY date_trunc(pas.unite, debut), pas.forme
ORDER BY date_trunc(pas.unite, debut)"""
COULEURS_VEHICULES = {"VW": "blue", "JEEP": "green", "ZERO": "purple",
"Invite": "yellow", "Non etiquete": "orange"}
vehicules = dashboard("evcs-vehicules", "Les vehicules", (
"Ce que chaque voiture encaisse, session par session et sur la periode "
"choisie. L'etiquette vient d'un selecteur manuel : elle peut etre fausse, "
@@ -1356,39 +1359,38 @@ vehicules = dashboard("evcs-vehicules", "Les vehicules", (
"service, amis)."),
frm="now-7d", refresh="5m", panels=[
stat("Sur la periode", [
table("Sur la periode", [
sql("A",
"SELECT round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'VW'), 0)::numeric, 1) AS \"VW\",\n"
" round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'JEEP'), 0)::numeric, 1) AS \"JEEP\",\n"
" round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule = 'ZERO'), 0)::numeric, 1) AS \"ZERO\",\n"
" round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule NOT IN ('VW', 'JEEP', 'ZERO')), 0)::numeric, 1) AS \"Invite\",\n"
" round(coalesce(sum(coalesce(energie_station_kwh, energie_kwh)) FILTER (WHERE vehicule IS NULL), 0)::numeric, 1) AS \"Non etiquete\",\n"
" count(*) AS \"Sessions\",\n"
" count(*) FILTER (WHERE NOT vehicule_sur OR vehicule IS NULL) AS \"A confirmer\"\n"
"FROM session_charge WHERE $__timeFilter(debut)", fmt="table")],
PG, 0, 0, 24, 5,
"« Etiquette douteuse » compte les sessions ou le selecteur a change en "
"cours de route, ou n'etait pas renseigne. C'est la mesure honnete de "
"l'incertitude : elle ne peut pas etre levee autrement qu'en positionnant "
"le selecteur au branchement.",
taille={"valueSize": 34, "titleSize": 12},
overrides=[
sur("VW", [{"id": "unit", "value": "kwatth"},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "blue"}}]),
sur("JEEP", [{"id": "unit", "value": "kwatth"},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "green"}}]),
sur("ZERO", [{"id": "unit", "value": "kwatth"},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "purple"}}]),
sur("Invite", [{"id": "unit", "value": "kwatth"},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "yellow"}}]),
sur("Etiquette douteuse", [{"id": "thresholds", "value": seuils(
("green", None), ("orange", 1))}])]),
PG, 0, 0, 24, 4,
"kWh charges par vehicule sur la plage choisie (compteur de la borne). "
"« Invite » = tout vehicule hors foyer (Megane de service, amis). "
"« A confirmer » compte les sessions dont l'etiquette vient du selecteur "
"sans confirmation : la seule mesure honnete de l'incertitude.",
overrides=[sur(n, [{"id": "unit", "value": "kwatth"},
{"id": "decimals", "value": 1},
{"id": "custom.cellOptions", "value": {"type": "color-text"}},
{"id": "color", "value": {"mode": "fixed", "fixedColor": c}}])
for n, c in COULEURS_VEHICULES.items()] + [
sur("A confirmer", [{"id": "custom.cellOptions", "value": {"type": "color-text"}},
{"id": "thresholds", "value": seuils(("green", None), ("orange", 1))},
{"id": "color", "value": {"mode": "thresholds"}}])]),
barchart("Energie par periode et par vehicule",
[sql("A", SESSIONS_PERIODE, fmt="table")],
PG, 0, 5, 24, 9, "kwatth",
PG, 0, 4, 24, 9, "kwatth",
"Le pas suit la plage choisie : l'heure jusqu'a 4 jours, le jour jusqu'a "
"70, le mois au-dela. « Non etiquete » est ce qui a ete charge sans que le "
"selecteur soit renseigne — a interpreter, pas a ignorer."),
"selecteur soit renseigne — a interpreter, pas a ignorer.",
overrides=[sur(n, [{"id": "color", "value": {"mode": "fixed", "fixedColor": c}}])
for n, c in COULEURS_VEHICULES.items()]),
table("Les sessions", [
sql("A",
@@ -1404,7 +1406,7 @@ vehicules = dashboard("evcs-vehicules", "Les vehicules", (
" source_mode AS \"Source au depart\",\n"
" to_char(debranche_a, 'Dy HH24:MI') AS \"Debranche\"\n"
"FROM session_charge WHERE $__timeFilter(debut) ORDER BY debut DESC", fmt="table")],
PG, 0, 14, 24, 11,
PG, 0, 13, 24, 11,
"« kWh » vient du compteur de la BORNE, qui compte depuis le vrai debut "
"de la session. « kWh integres » est mon propre calcul, qui ne couvre que "
"ce que le service a vu — un ecart entre les deux signale un demarrage ou "
@@ -1789,7 +1791,7 @@ journee = dashboard(
# found ». Ici on veut les quatre colonnes, tout le temps.
barchart("Energie heure par heure",
[sql("A", energie_sql(prevision=True), fmt="table")],
PG, 0, 5, 24, 9, "kwatth",
PG, 0, 4, 24, 9, "kwatth",
"La forme de la journee : quand le solaire a couvert la maison, quand il "
"a fallu acheter — et, a la suite des barres mesurees, ce que la derniere "
"prevision annonce pour les heures qui restent. L'heure EN COURS n'a pas "