From 3fe84e09d4ebc546feaa2829641830c0d9237996 Mon Sep 17 00:00:00 2001 From: Tallagrand Thierry Date: Sun, 6 Sep 2026 15:44:30 +0200 Subject: [PATCH] Les pointilles s effacent, et une sauvegarde ne se faisait plus depuis juin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trois choses vues en regardant deux captures. La tache Hyper Backup « Synology NAS 1 » echoue en zero seconde : sa destination, le dossier partage ARCHIVEFAMILLE sur 10.10.10.22, n existe pas — ni en clair, ni chiffre, ni dans la configuration Samba. Sa jumelle, qui vise le dossier video du meme hote, reussit. Dix notifications d echec retrouvees, zero reussite, la plus ancienne du 6 juin : les photos 2008-2015 n ont aucune sauvegarde depuis trois mois. Non corrige, la machine source n accepte pas ma cle et le choix de destination appartient au proprietaire. Les annotations Grafana deviennent opt-in, et le genre bilan en est ecarte : a lui seul un quart des lignes, presque toutes des bascules d un drapeau qui change plusieurs fois par heure. Un trait vertical marque ce qui arrive, pas ce qui clignote. Au passage les deux panneaux de comparaison affichaient huit courbes dont quatre mortes ; ils ne montrent plus que les modules ayant emis dans les deux dernieres heures — un critere d activite, pas un prefixe de code-barres. Et la marge de 50 % de la nuit est verifiee : il fallait couvrir 2,22 kWh jusqu au croisement solaire, le bilan en avait reserve 2,65. Dix-neuf pour cent d assurance sur un parc de quatre modules. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ --- HANDOFF.md | 72 +++++++++++++++++++ .../grafana/dashboards/batteries.json | 8 +-- .../grafana/dashboards/nuit.json | 4 +- .../grafana/dashboards/prevision.json | 4 +- .../grafana/dashboards/solaire.json | 4 +- .../grafana/dashboards/systeme.json | 4 +- .../grafana/dashboards/telephone.json | 4 +- .../grafana/dashboards/vehicules.json | 4 +- docs/mesures/batteries/202609052040-suivi.csv | 4 ++ tools/gen-grafana-dashboards.py | 28 +++++++- 10 files changed, 118 insertions(+), 18 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index 8216d3b..739b7c1 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -4948,6 +4948,78 @@ joignable depuis le telephone. Et une session Claude, meme pilotable a distance, reste un poste de travail — ce n'est pas elle qui doit porter la surveillance de nuit, d'ou le rapport par courriel loge dans le service d'historisation. +### La sauvegarde « Synology NAS 1 » echoue depuis au moins TROIS MOIS +Signalee par une notification DSM apercue dans une capture. Faits, lus dans le +courriel d'echec : + +``` +Tache de sauvegarde : Synology NAS 1 +Destination : 10.10.10.22 / ARCHIVEFAMILLE / ARCHIVE_1_PHOTOS_2008_2015.hbk +Duree : 0 Second +``` + +**Duree zero** : la tache n'a pas pu demarrer, ce n'est pas une erreur de +donnees. Verifie en SSH sur 10.10.10.22 : le dossier partage +**`ARCHIVEFAMILLE` n'existe pas** — ni en clair, ni comme partage chiffre, ni +dans la configuration Samba. Les partages reels y sont `photo`, `video`, +`FILMS`, `PLONGEES`, `KEVIN`, `NetBackup`, `docker`, `projects`... + +La tache jumelle « Synology NAS 2 » vise `10.10.10.22 / video / +ARCHIVE_1_VIDEO.hbk` et **reussit** : l'hote de destination va bien, c'est le +dossier qui a disparu. + +Anciennete : dix notifications d'echec retrouvees, **zero reussite**, la plus +ancienne du **06/06/2026**. Les photos 2008-2015 de ARCHIVE (10.10.10.50) n'ont +donc aucune sauvegarde depuis au moins trois mois, et l'alerte quotidienne +partait dans une boite a 17 600 messages non lus. + +⚠️ Non corrige : 10.10.10.50 n'accepte pas ma cle SSH, et recreer un partage +puis reconfigurer Hyper Backup est une decision qui appartient au proprietaire. +Deux voies : recreer un dossier partage `ARCHIVEFAMILLE` sur 10.10.10.22, ou +repointer la tache vers un partage existant (`NetBackup` est le nom +conventionnel). Dans les deux cas il faudra une sauvegarde COMPLETE au premier +passage, le `.hbk` n'existant pas. + +### Les annotations Grafana etaient devenues illisibles +Sept jours d'historique produisaient une foret de pointilles orange masquant les +courbes. Deux corrections dans `tools/gen-grafana-dashboards.py` : + +1. **`enable: False`** — les evenements deviennent OPT-IN. Le bouton + « Evenements » en tete de tableau les rallume quand on veut le contexte d'un + incident. C'est ce bouton qui etait allume par defaut. +2. **Le genre `bilan` est ecarte** de l'annotation : a lui seul **26 %** des + lignes (36 sur 137), presque toutes des bascules de « production bridee » qui + changent plusieurs fois par heure. Un trait vertical doit marquer ce qui + ARRIVE — bascule du contacteur, vehicule branche, changement de mode ACM, + redemarrage, intervention manuelle — pas un drapeau qui clignote. + +Au passage : les deux panneaux qui COMPARENT les modules entre eux affichaient +**huit courbes dont quatre mortes**. Le releveur lit aussi les modules isoles +tant qu'ils sont sous tension ; le pack ancien a cesse d'emettre le 05/09 mais +restait trace sur une fenetre de sept jours. Filtre pose : « module ayant emis +dans les deux dernieres heures » — un critere d'activite, pas un prefixe de +code-barres, donc rebrancher un pack le fait revenir tout seul. +62/62 requetes toujours valides. + +### La marge de 50 % de cette nuit, verifiee +Question du proprietaire : est-elle justifiee pour un demi-parc ? Mesure de +05:05 (fin de la recharge, SOC 55) a 08:45 (croisement PV) : + +| | | +|---|---:| +| consommation maison | 2,57 kWh | +| production PV sur la periode | 0,35 kWh | +| **energie reellement a couvrir** | **2,22 kWh** | +| ce que le bilan avait reserve (49,4 % - plancher 22 %) | **2,65 kWh** | +| ce que la batterie a effectivement fourni | 1,00 kWh | + +**Marge de 19 %** entre ce qui etait reserve et ce qu'il fallait : c'est une +assurance, pas un gaspillage. La batterie n'a fourni que 1,00 kWh parce que le +reseau a porte la maison de 05:05 a 06:47 — mais la reserve devait couvrir le +cas ou le contacteur disparait a 05:05, et dans ce cas les 2,22 kWh etaient +tous a sa charge. Sur un parc de quatre modules (7,1 kWh utiles de 100 a 22 %), +2,65 kWh representent 37 % du parc. Justifie. + ### Reste ouvert - Detecteur de gel dans le service d'historisation : une grandeur qui ne bouge pas alors qu'une autre du meme bilan bouge = alerte. Non fait. diff --git a/deploy/historisation/grafana/dashboards/batteries.json b/deploy/historisation/grafana/dashboards/batteries.json index 3f0af9e..91ab4f0 100644 --- a/deploy/historisation/grafana/dashboards/batteries.json +++ b/deploy/historisation/grafana/dashboards/batteries.json @@ -60,14 +60,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] @@ -166,7 +166,7 @@ "format": "time_series", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, module AS metric, max(mv) - min(mv) AS ecart\nFROM cellule WHERE $__timeFilter(ts)\nGROUP BY ts, module ORDER BY 1" + "rawSql": "SELECT ts AS time, module AS metric, max(mv) - min(mv) AS ecart\nFROM cellule WHERE $__timeFilter(ts)\n AND module IN (SELECT module FROM cellule\n GROUP BY module HAVING max(ts) > now() - interval '2 hours')\nGROUP BY ts, module ORDER BY 1" } ], "gridPos": { @@ -223,7 +223,7 @@ "format": "time_series", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, module || ' — cellule meneuse' AS metric,\n max(mv) AS mv\nFROM cellule WHERE $__timeFilter(ts)\nGROUP BY ts, module ORDER BY 1" + "rawSql": "SELECT ts AS time, module || ' — cellule meneuse' AS metric,\n max(mv) AS mv\nFROM cellule WHERE $__timeFilter(ts)\n AND module IN (SELECT module FROM cellule\n GROUP BY module HAVING max(ts) > now() - interval '2 hours')\nGROUP BY ts, module ORDER BY 1" }, { "refId": "B", diff --git a/deploy/historisation/grafana/dashboards/nuit.json b/deploy/historisation/grafana/dashboards/nuit.json index cc6f787..f0b0a15 100644 --- a/deploy/historisation/grafana/dashboards/nuit.json +++ b/deploy/historisation/grafana/dashboards/nuit.json @@ -46,14 +46,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/deploy/historisation/grafana/dashboards/prevision.json b/deploy/historisation/grafana/dashboards/prevision.json index 7d9a9f3..39e61f2 100644 --- a/deploy/historisation/grafana/dashboards/prevision.json +++ b/deploy/historisation/grafana/dashboards/prevision.json @@ -46,14 +46,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/deploy/historisation/grafana/dashboards/solaire.json b/deploy/historisation/grafana/dashboards/solaire.json index 32467df..dd76758 100644 --- a/deploy/historisation/grafana/dashboards/solaire.json +++ b/deploy/historisation/grafana/dashboards/solaire.json @@ -46,14 +46,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/deploy/historisation/grafana/dashboards/systeme.json b/deploy/historisation/grafana/dashboards/systeme.json index 98a6234..aed90fd 100644 --- a/deploy/historisation/grafana/dashboards/systeme.json +++ b/deploy/historisation/grafana/dashboards/systeme.json @@ -89,14 +89,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/deploy/historisation/grafana/dashboards/telephone.json b/deploy/historisation/grafana/dashboards/telephone.json index 2a7fd0a..63d6190 100644 --- a/deploy/historisation/grafana/dashboards/telephone.json +++ b/deploy/historisation/grafana/dashboards/telephone.json @@ -46,14 +46,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/deploy/historisation/grafana/dashboards/vehicules.json b/deploy/historisation/grafana/dashboards/vehicules.json index b8042dd..597c1ae 100644 --- a/deploy/historisation/grafana/dashboards/vehicules.json +++ b/deploy/historisation/grafana/dashboards/vehicules.json @@ -46,14 +46,14 @@ "type": "grafana-postgresql-datasource", "uid": "evcs-pg" }, - "enable": true, + "enable": false, "iconColor": "semi-dark-orange", "hide": false, "target": { "format": "table", "rawQuery": true, "editorMode": "code", - "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) ORDER BY 1" + "rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1" } } ] diff --git a/docs/mesures/batteries/202609052040-suivi.csv b/docs/mesures/batteries/202609052040-suivi.csv index f1a95ec..09818e9 100644 --- a/docs/mesures/batteries/202609052040-suivi.csv +++ b/docs/mesures/batteries/202609052040-suivi.csv @@ -448,3 +448,7 @@ heure_reelle,etat,courant_mA,c1_mV,c2_mV,c3_mV,c4_mV,c5_mV,c6_mV,c7_mV,c8_mV,c9_ 2026-09-06T13:31:10.870Z,Y230202C30371425,,3312,3312,3312,3312,3311,3311,3312,3311,3312,3312,3312,3312,3311,3312,3311,1 2026-09-06T13:31:10.997Z,Y230202C30371431,,3312,3312,3312,3312,3312,3312,3312,3312,3312,3310,3312,3312,3312,3312,3312,2 2026-09-06T13:31:11.122Z,Y230202C30371427,,3301,3302,3302,3302,3300,3300,3302,3302,3302,3301,3301,3303,3303,3303,3300,3 +2026-09-06T13:41:11.226Z,Y230202C30371426,,3312,3312,3311,3312,3312,3312,3312,3312,3310,3312,3312,3312,3312,3312,3311,2 +2026-09-06T13:41:11.324Z,Y230202C30371425,,3309,3310,3310,3310,3309,3309,3310,3310,3310,3310,3309,3310,3310,3310,3310,1 +2026-09-06T13:41:11.451Z,Y230202C30371431,,3310,3311,3311,3311,3311,3310,3311,3312,3311,3311,3310,3311,3312,3312,3311,2 +2026-09-06T13:41:11.577Z,Y230202C30371427,,3318,3318,3318,3317,3317,3318,3318,3317,3317,3317,3318,3318,3318,3318,3317,1 diff --git a/tools/gen-grafana-dashboards.py b/tools/gen-grafana-dashboards.py index 061fa03..3320707 100644 --- a/tools/gen-grafana-dashboards.py +++ b/tools/gen-grafana-dashboards.py @@ -153,12 +153,25 @@ def dashboard(uid, title, desc, panels, refresh="1m", frm="now-24h", variables=N {"builtIn": 1, "datasource": {"type": "grafana", "uid": "-- Grafana --"}, "enable": True, "hide": True, "name": "Annotations & Alerts", "iconColor": "rgba(0, 211, 255, 1)", "type": "dashboard"}, - {"name": "Evenements", "datasource": PG, "enable": True, + # Les evenements sont OPT-IN : `enable: False`. Ils rendent un + # graphique illisible des qu'ils sont nombreux — le 06/09, sept + # jours d'historique donnaient une foret de pointillies orange qui + # masquait les courbes. Le bouton « Evenements » en tete de tableau + # les rallume quand on veut le contexte d'un incident. + # + # Et meme allumes, on ecarte le genre `bilan` : a lui seul 26 % des + # lignes, presque toutes des bascules de « production bridee » qui + # changent plusieurs fois par heure. Ce qui merite un trait vertical + # est ce qui ARRIVE — une bascule du contacteur, un vehicule + # branche, un changement de mode de charge, un redemarrage, une + # intervention manuelle — pas un drapeau qui clignote. + {"name": "Evenements", "datasource": PG, "enable": False, "iconColor": "semi-dark-orange", "hide": False, "target": {"format": "table", "rawQuery": True, "editorMode": "code", "rawSql": "SELECT ts AS time, resume AS text, " "genre || ',' || coalesce(source,'?') AS tags " - "FROM evenement WHERE $__timeFilter(ts) ORDER BY 1"}}]}, + "FROM evenement WHERE $__timeFilter(ts) " + "AND genre <> 'bilan' ORDER BY 1"}}]}, "panels": panels} # ===================================================================== @@ -1109,9 +1122,18 @@ batteries = dashboard("evcs-batteries", "Les batteries", ( "custom.thresholdsStyle": {"mode": "dashed"}}}}, legend="right"), + # ⚠️ Ces deux panneaux COMPARENT les modules entre eux : ils ne doivent + # montrer que les modules ENCORE SUR LA CHAINE. Le releveur lit aussi les + # modules isoles tant qu'ils sont sous tension — le pack ancien a cesse + # d'emettre le 05/09 mais restait affiche sur une fenetre de sept jours, + # soit huit courbes dont quatre mortes. Le critere est « a emis dans les + # deux dernieres heures », pas un prefixe de code-barres : rebrancher un + # pack le fait revenir tout seul. ts("Ecart entre la plus haute et la plus basse", [ sql("A", "SELECT ts AS time, module AS metric, max(mv) - min(mv) AS ecart\n" "FROM cellule WHERE $__timeFilter(ts)\n" + " AND module IN (SELECT module FROM cellule\n" + " GROUP BY module HAVING max(ts) > now() - interval '2 hours')\n" "GROUP BY ts, module ORDER BY 1")], PG, 0, 10, 12, 8, unit="mvolt", desc="L'indicateur qui resume un module en une courbe. Un module sain de " @@ -1122,6 +1144,8 @@ batteries = dashboard("evcs-batteries", "Les batteries", ( sql("A", "SELECT ts AS time, module || ' — cellule meneuse' AS metric,\n" " max(mv) AS mv\n" "FROM cellule WHERE $__timeFilter(ts)\n" + " AND module IN (SELECT module FROM cellule\n" + " GROUP BY module HAVING max(ts) > now() - interval '2 hours')\n" "GROUP BY ts, module ORDER BY 1"), sql("B", "SELECT ts AS time, 'plafond de charge (A)' AS metric,\n" " valeur * 20 AS mv\n"