Trois tableaux de bord provisionnes depuis git, sur le modele de la regle R2
(le depot est la source de verite, l'interface ne peut pas les ecraser) :
La nuit SOC reel contre SOC exige par le bilan, et la marge entre les
deux. C'est la question qui avait demande une nuit d'archeologie
le 03/09.
Le solaire l'excedent (§36), la censure, et le mode declare par chacun des
sept chargeurs (§37) — le signal le plus direct dont on dispose.
Prevision l'ecart heure par heure, avec la bande de censure dessous : une
production sous la prevision peut vouloir dire mauvaise
prevision OU absence de preneur.
Les evenements de la table `evenement` deviennent des marqueurs verticaux sur
tous les graphiques — une courbe sans ses evenements ne s'interprete pas.
tools/verifier-dashboards.mjs rejoue CHAQUE requete pour de vrai (SQL contre
PostgreSQL, Flux contre InfluxDB, macros Grafana substituees), annotations
comprises puisqu'elles s'executent sur tous les panneaux. Sans lui une requete
cassee ne se voit qu'a l'ecran, panneau par panneau. 19/19 au deploiement.
Port 3001 et non 3000 : sonde avant d'ecrire la ligne, quelque chose ecoute
deja sur 3000 — la lecon du 5432 deja pris par le PostgreSQL de DSM.
Connexion PostgreSQL par le role evcs_lecture : un tableau de bord ne doit pas
pouvoir ecrire dans la memoire. Aucun secret duplique, aucun secret commite :
le provisionnement les reference par $VARIABLE depuis les deux .env.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
251 lines
10 KiB
Markdown
251 lines
10 KiB
Markdown
# Mémoire de mesures EVCS
|
|
|
|
Deux bases sur **10.10.10.22**, décidées le 04/09/2026 : on met les deux en
|
|
service et on décide à l'usage s'il faut garder les deux.
|
|
|
|
| | rôle | source | résolution |
|
|
|---|---|---|---|
|
|
| **PostgreSQL** | ce que n8n **calcule** — bilan, décisions, prévisions publiées | workflows n8n | cadence des workflows |
|
|
| **InfluxDB** | ce que Home Assistant **observe** — tous les états du périmètre énergie | intégration HA | chaque changement d'état |
|
|
|
|
Le raisonnement complet et le comparatif : `HANDOFF.md` §42 et suivantes.
|
|
|
|
## Pourquoi pas sur 10.10.10.17
|
|
|
|
Cette machine porte déjà Home Assistant, n8n, openclaw et open-webui. Une
|
|
mémoire hébergée par la machine dont elle documente les pannes ne survit pas à
|
|
celles-ci. Le volume n'est pas l'argument : les deux Synology ont des téraoctets
|
|
libres.
|
|
|
|
## Mise en service
|
|
|
|
### 1. Les deux bases (à faire sur 10.10.10.22)
|
|
|
|
```sh
|
|
cd /volume2/projects/EVCS/EVCS/deploy/historisation
|
|
bash preparer-env.sh # génère .env avec des secrets aléatoires
|
|
docker compose up -d
|
|
docker compose logs -f
|
|
```
|
|
|
|
### D'où viennent les secrets
|
|
|
|
| secret | origine |
|
|
|---|---|
|
|
| `HA_TOKEN` | **existe déjà** — repris du `.env` à la racine du dépôt |
|
|
| `POSTGRES_PASSWORD` | **créé ici** — la base n'existe pas encore, ce fichier décide de son mot de passe |
|
|
| `DOCKER_INFLUXDB_INIT_PASSWORD` | **créé ici**, idem (InfluxDB exige au moins 8 caractères) |
|
|
| `DOCKER_INFLUXDB_INIT_ADMIN_TOKEN` | **créé ici** — c'est le jeton que Home Assistant utilisera pour écrire |
|
|
|
|
Aucun ne s'obtient auprès de quelqu'un, et aucun ne doit être choisi à la main :
|
|
personne ne les tape jamais — les conteneurs les lisent dans `.env`, et Home
|
|
Assistant lit le jeton dans son propre `secrets.yaml`. Une phrase inventée est
|
|
plus courte et plus devinable qu'elle n'en a l'air ; `openssl rand` ne l'est pas.
|
|
|
|
`preparer-env.sh` refuse d'écraser un `.env` existant : régénérer les mots de
|
|
passe d'une base déjà créée la rendrait inaccessible, puisqu'elle continuerait
|
|
d'attendre les anciens.
|
|
|
|
Vérifications :
|
|
|
|
```sh
|
|
docker compose exec postgres psql -U evcs -d evcs -c '\dt'
|
|
curl -s http://10.10.10.22:8086/health
|
|
docker compose logs historisation --tail 5
|
|
```
|
|
|
|
### Ports : 5433, et pas 5432
|
|
|
|
DSM fait tourner **son propre PostgreSQL sur 5432**, pour ses services internes.
|
|
Notre base est donc publiée sur **5433**. Ce port ne sert qu'à l'analyse depuis
|
|
un poste de travail :
|
|
|
|
```sh
|
|
psql -h 10.10.10.22 -p 5433 -U evcs -d evcs
|
|
```
|
|
|
|
Les trois conteneurs, eux, se parlent par le réseau interne du compose et par
|
|
nom de service (`postgres:5432`) — ni adresse IP en dur, ni dépendance au port
|
|
publié. Vérifier ce qui occupe un port avant de conclure :
|
|
|
|
```sh
|
|
sudo ss -lntp | grep -E '5432|5433|8086'
|
|
```
|
|
|
|
Le schéma (`schema.sql`) est appliqué **une seule fois**, à la création de la
|
|
base. Pour le faire évoluer ensuite, écrire une migration et la passer à `psql` :
|
|
recréer le volume effacerait l'historique, ce qui est précisément ce qu'on
|
|
cherche à ne plus faire.
|
|
|
|
### 2. Brancher Home Assistant sur InfluxDB
|
|
|
|
⚠️ **Demande un redémarrage de Home Assistant**, pendant lequel le contrôleur
|
|
EVCS ne décide plus rien. **Jamais entre 01:24 et 07:24**, ni pendant une charge.
|
|
Le bon créneau est le milieu de matinée.
|
|
|
|
1. mettre le jeton dans `secrets.yaml` sous la clé `influxdb_token` ;
|
|
2. coller le bloc de `ha-influxdb.yaml` dans `configuration.yaml` ;
|
|
3. `homeassistant.check_config`, puis redémarrer.
|
|
|
|
### 3. Alimenter PostgreSQL depuis n8n
|
|
|
|
À faire après l'étape 1 — n8n a besoin que la base existe pour qu'on y crée
|
|
l'identifiant de connexion.
|
|
|
|
## Événements : détectés par le service, annotés à la main
|
|
|
|
La table `evenement` existe parce qu'une courbe sans ses événements ne
|
|
s'interprète pas : « le rendement a changé le 12 novembre » ne veut rien dire
|
|
sans la ligne qui dit qu'un pack a été rebranché ce jour-là.
|
|
|
|
**Le service consigne seul ce qu'il peut constater** — il voit passer les états
|
|
toutes les minutes, autant qu'il en tire les conclusions plutôt que d'attendre
|
|
que quelqu'un y pense :
|
|
|
|
| genre | ce qui est consigné |
|
|
|---|---|
|
|
| `systeme` | démarrage du service, redémarrage de Home Assistant, épisode d'indisponibilité avec sa durée |
|
|
| `reseau` | contacteur EDF, session réseau de nuit, reprise nuit, verrou hystérésis |
|
|
| `vehicule` | véhicule branché ou débranché |
|
|
| `intervention` | changement de stratégie ou de véhicule sélectionné |
|
|
| `ess` | état BatteryLife, mode de l'Auto Charge Manager |
|
|
| `bilan` | réseau nécessaire, vigilance orage, production bridée |
|
|
|
|
On suit des états **discrets** dont chaque changement mérite une ligne. Les
|
|
grandeurs continues sont dans `mesure`, les décisions du contrôleur dans
|
|
`decision` : un événement qui double une autre table est du bruit. Une lecture
|
|
`unavailable` n'est pas une transition mais une absence de lecture — elle n'est
|
|
pas consignée.
|
|
|
|
Le redémarrage de Home Assistant est detecté **sans capteur d'uptime**, qui
|
|
n'existe pas sur cette installation : au redémarrage HA restaure ses helpers et
|
|
leur pose un `last_changed` neuf. Le 04/09, 352 entités partageaient la seconde
|
|
du redémarrage, dont 183 `input_number`. Le service prend donc le **mode** des
|
|
`last_changed` des `input_number` — aucune entité codée en dur, et l'estimation
|
|
se corrige d'elle-même.
|
|
|
|
**Les annotations qu'aucun service ne peut deviner** — « pack rebranché »,
|
|
« correctif déployé » — s'écrivent à la main. Pour cela le rôle d'analyse a
|
|
besoin d'un `INSERT` sur cette seule table :
|
|
|
|
```sh
|
|
sudo docker compose exec -T postgres psql -U evcs -d evcs -c \
|
|
"GRANT INSERT ON evenement TO evcs_lecture;
|
|
GRANT USAGE, SELECT ON SEQUENCE evenement_id_seq TO evcs_lecture;"
|
|
```
|
|
|
|
`INSERT` seulement : ni `UPDATE`, ni `DELETE`. On peut ajouter une annotation,
|
|
jamais réécrire ni effacer les précédentes — y compris les siennes. C'est ce
|
|
qu'on attend d'un journal, et ça laisse les tables de mesure hors de portée.
|
|
|
|
## Accès en lecture pour l'analyse
|
|
|
|
```sh
|
|
sudo bash creer-role-lecture.sh
|
|
```
|
|
|
|
Crée le rôle `evcs_lecture` en **lecture seule** et dépose son mot de passe dans
|
|
le `.env` à la racine du dépôt. Le mot de passe est généré, jamais choisi, et
|
|
**n'est pas affiché** : il va du générateur au fichier, donc rien à recopier et
|
|
rien à exposer dans une capture.
|
|
|
|
Deux raisons de ne pas analyser avec le compte `evcs` : une mémoire dont tout
|
|
l'intérêt est de ne pas être réécrite ne se consulte pas avec un compte qui peut
|
|
écrire, et un mot de passe rangé dans un fichier lisible ne doit pas être celui
|
|
qui gouverne la base.
|
|
|
|
Le script est rejouable : si le rôle existe déjà et que son mot de passe est
|
|
dans le `.env`, il ne fait rien.
|
|
|
|
## Ce qu'aucune des deux ne fait
|
|
|
|
Elles ne remontent pas dans le passé. La mémoire commence le jour où on les
|
|
branche : c'est un argument pour les mettre en service vite, pas pour les
|
|
mettre en service parfaitement.
|
|
|
|
## Sauvegarde
|
|
|
|
Les deux bases vivent dans des volumes Docker nommés, donc **hors du dépôt et
|
|
hors des sauvegardes Home Assistant**. Une mémoire non sauvegardée est une
|
|
mémoire qu'on perdra une fois — voir `HANDOFF.md` §34, qui raconte la même
|
|
histoire pour Home Assistant.
|
|
|
|
---
|
|
|
|
## Consultation — Grafana (ajouté le 04/09/2026)
|
|
|
|
### Ce qu'il y a à consulter, et où
|
|
|
|
| Base | Où | Ce qu'elle garde | Consultable dans Grafana |
|
|
|---|---|---|---|
|
|
| **PostgreSQL `evcs`** | 10.10.10.22:5433 | ce que le système **calcule** : bilan, décisions, prévision publiée, événements | oui |
|
|
| **InfluxDB `evcs`** | 10.10.10.22:8086 | ce que HA **observe**, ~1 point/s, 113 grandeurs | oui |
|
|
| SQLite de Home Assistant | 10.10.10.17 | son historique brut (20 j) et ses statistiques long terme (186 j) | **non — volontairement** |
|
|
|
|
Le PostgreSQL du port **5432** appartient à DSM et à ses services internes.
|
|
Ce n'est pas une base du projet ; ne pas s'y connecter.
|
|
|
|
L'historique de Home Assistant reste consulté **dans Home Assistant**. L'y
|
|
brancher demanderait de lire un fichier SQLite de 4,4 Go en mode WAL, à travers
|
|
un partage réseau, pendant que HA écrit dedans : c'est la meilleure façon de
|
|
lire une base incohérente, et le risque n'est pas payé en retour puisque tout
|
|
ce qui compte pour l'avenir arrive désormais dans InfluxDB à une résolution
|
|
bien meilleure.
|
|
|
|
### Mise en service
|
|
|
|
```bash
|
|
cd /volume2/projects/EVCS/EVCS/deploy/historisation
|
|
bash preparer-grafana.sh # génère le mot de passe admin, l'affiche une fois
|
|
docker compose up -d grafana
|
|
docker compose logs -f grafana
|
|
```
|
|
|
|
Puis **http://10.10.10.22:3001** — port 3001 et non 3000, occupé sur cette
|
|
machine par autre chose.
|
|
|
|
Mot de passe perdu :
|
|
`grep GRAFANA_ADMIN_PASSWORD deploy/historisation/.env`
|
|
|
|
### Les trois tableaux de bord
|
|
|
|
- **La nuit** — le SOC réel contre le SOC exigé par le bilan, la marge entre
|
|
les deux, la session réseau, et ce que la nuit a coûté. C'est la question qui
|
|
avait demandé une nuit d'archéologie le 03/09.
|
|
- **Le solaire** — production, maison, et surtout **l'excédent** (la grandeur
|
|
qui décide d'un démarrage depuis le 03/09), avec la censure du MPPT et le
|
|
mode déclaré par chacun des sept chargeurs.
|
|
- **Prévision contre réel** — le biais de forme de la prévision, question
|
|
ouverte qui demande des semaines de données.
|
|
|
|
Les événements de la table `evenement` apparaissent en **marqueurs verticaux
|
|
orange sur tous les graphiques** : une courbe sans ses événements ne
|
|
s'interprète pas.
|
|
|
|
### Modifier un tableau de bord
|
|
|
|
Ils viennent du dépôt git, comme le code des nodes n8n — et pour la même
|
|
raison : une modification faite dans l'interface serait écrasée au prochain
|
|
démarrage, en silence. Le générateur est `tools/gen-grafana-dashboards.py` :
|
|
|
|
```bash
|
|
python3 tools/gen-grafana-dashboards.py # réécrit les trois JSON
|
|
node tools/verifier-dashboards.mjs # rejoue CHAQUE requête pour de vrai
|
|
```
|
|
|
|
`verifier-dashboards.mjs` exécute les requêtes SQL contre PostgreSQL et les
|
|
requêtes Flux contre InfluxDB, macros de Grafana substituées. Sans lui, une
|
|
requête cassée ne se voit qu'à l'écran, panneau par panneau. Sortie non nulle
|
|
si une seule échoue.
|
|
|
|
Grafana relit le dossier toutes les 30 s : pas besoin de redémarrer.
|
|
|
|
Pour explorer librement sans rien casser : **« Save as… »** depuis n'importe
|
|
quel tableau de bord en crée une copie personnelle et modifiable.
|
|
|
|
### Ce que Grafana ne peut pas faire
|
|
|
|
Il ne **stocke** rien : il interroge les deux bases à la demande. Le perdre ne
|
|
perd aucune mesure. Il n'écrit rien non plus — sa connexion PostgreSQL utilise
|
|
le rôle `evcs_lecture`, en lecture seule.
|