Piloter sa consommation électrique (2ème épisode)

Dans le précédent épisode j’avais mis en place un pilotage de la consommation électrique avec MyElectricalData, sauf qu’il manquait quelque chose. Le tableau de bord n’est pas corrélé avec les jours bleu, blanc, rouge d’un abonnement EDF Tempo, l’objectif est d’aller récupérer les données Tempo sur un autre site pour pouvoir relier tout ça.

Pour ce faire, j’ai mis en place une solution qui permet d’agréger les données venant du site myelectricaldata (qui lui même récupère les informations d’Enedis collectées par le Linky) et les données Tempo qui viennent de ce site. Cette solution est basée sur deux outils:

  • InfluxDB est un système de gestion de base de données plus spécialisée pour gérer des structures de données composée de mesures, de séries et de points. Il intègre également des fonctionnalités de visualisation.
  • Grafana qui est une grosse boite à outil d’analyse et de visualisation de données de multiples sources.

Cela permet de construire les vues comme bon nous semble. Voilà une première vue avec un graphe de consommation en kWh sur un an corrélé avec la couleur Tempo du jour et à gauche avec le coût quotidien de la consommation.

Autre vue avec la couleur Tempo du jour à gauche et celle du lendemain à droite et en bas la consommation et le coût sur deux mois glissants.

J’ai vérifié sur mon compte client EDF, l’information en kWh est juste, en revanche, je ne retrouve pas le même coût, pour octobre myelectricaldata renvoie 91,4€ alors que le coût réel est de 116€, quant au coût cumulé réel, il est de de 1328€ et non 1004€. Cela fait une belle différence, pour essayer de comprendre, dans les petites lignes du site EDF, je vois que le prix comprend également l’abonnement et les taxes moyennées. De fil en aiguille je trouve que mon abonnement mensuel est à 19,7€ (cf. détail ici), donc pour le mois d’octobre j’arrive à 111,1€ calculé au lieu de 116€ réel et pour le montant cumulé 1220,7€ au lieu de 1328€, soit 4% de différence sur un mois et 8€ de différence sur le montant cumulé. En considérant une marge d’erreur à la hausse de 10%, ça me donne donc un résultat plutôt crédible.

Pour configurer tout cela, on utilisera docker, et on fera en sorte que tout ce beau monde discute en connexions sécurisées SSL. Voici le fichier docker-compose.yaml sous /etc/myelectricaldata :

services:
myelectricaldata:
container_name: myelectricaldata
image: m4dm4rtig4n/myelectricaldata:latest
dns:
- 1.1.1.1
- 8.8.8.8
restart: unless-stopped
volumes:
- /etc/myelectricaldata/config:/data
- /etc/myelectricaldata/influxdb_certs/combined-ca-bundle.crt:/etc/ssl/certs/combined-ca-bundle.crt:ro
environment:
TZ: Europe/Paris
SSL_CERT_FILE: /etc/ssl/certs/combined-ca-bundle.crt
REQUESTS_CA_BUNDLE: /etc/ssl/certs/combined-ca-bundle.crt
ports:
- 5000:5000

influxdb:
container_name: influxdb
image: influxdb:2.7
restart: unless-stopped
command: influxd --tls-cert=/etc/ssl/influxdb-selfsigned.crt --tls-key=/etc/ssl/influxdb-selfsigned.key
volumes:
- /etc/myelectricaldata/influxdb_data:/var/lib/influxdb2
- /etc/myelectricaldata/influxdb_certs/influxdb-selfsigned.crt:/etc/ssl/influxdb-selfsigned.crt:ro
- /etc/myelectricaldata/influxdb_certs/influxdb-selfsigned.key:/etc/ssl/influxdb-selfsigned.key:ro
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: admin
DOCKER_INFLUXDB_INIT_PASSWORD: mot-de-passe
DOCKER_INFLUXDB_INIT_ORG: myelectricaldata
DOCKER_INFLUXDB_INIT_BUCKET: myelectricaldata
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: MonTokenInfluxDB
INFLUXD_TLS_CERT: /etc/ssl/influxdb-selfsigned.crt
INFLUXD_TLS_KEY: /etc/ssl/influxdb-selfsigned.key
ports:
- 8086:8086

grafana:
container_name: grafana
image: grafana/grafana:latest
restart: unless-stopped
volumes:
- /etc/myelectricaldata/grafana_data:/var/lib/grafana
- /etc/myelectricaldata/grafana_certs:/etc/grafana/certs:ro
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: mot-de-passe
GF_SERVER_PROTOCOL: https
GF_SERVER_CERT_FILE: /etc/grafana/certs/grafana.crt
GF_SERVER_CERT_KEY: /etc/grafana/certs/grafana.key
GF_SERVER_DOMAIN: ultra.kervao.fr
ports:
- 3000:3000

Et le fichier config.yaml qui regroupe la configuration des 3 outils, placé aussi sous /etc/myelectricdata, devient du coup :

port: 5000
debug: true
log2file: false
wipe_influxdb: false # Work only with influxdb > 2.X
# Par défaut le backend en local dans le /data/cache.db du conteneur.
# Mais il est possible de basculer sur une base de données externe de type SQLite ou PostgreSQL
# Exemple pour Postgres :
#storage_uri: postgresql://myelectricaldata:myelectricaldata@postgres:5432/myelectricaldata
home_assistant: # WITH MQTT DISCOVERY
enable: false
discovery: true
discovery_prefix: homeassistant
home_assistant_ws: # FOR ENERGY TAB
enable: false
ssl: true
token: HOME_ASSISTANT_TOKEN_GENERATE_IN_PROFILE_TABS_(BOTTOM)
url: myhomeassistant.domain.fr
max_date: "2021-06-01"
purge: false
ssl:
gateway: true
certfile: /data/fullchain.pem
keyfile: /data/privkey.pem
tempo:
enable: true
influxdb:
enable: true
scheme: https
hostname: influxdb
port: 8086 # 8086 pour influxdb, 8428 pour victoriametrics
token: MonTokenInfluxDB
org: myelectricaldata
bucket: myelectricaldata
ssl: true
ssl_verify: false
# ATTENTION, L'activation de l'importation asynchrone va réduire fortement le temps d'importation dans InfluxDB
# mais va augmenter la consommation mémoire & CPU et donc à activer uniquement sur un hardware robuste.
method: synchronous # Mode disponible : synchronous / asynchronous / batching
version: 2
vm_mode: false # Active le mode VictoriaMetrics true sinon false pour influxdb
# batching_options permet uniquement de configurer la methode `batching`.
# Pour plus d'information : https://github.com/influxdata/influxdb-client-python#batching
batching_options:
batch_size: 1000
flush_interval: 1000
jitter_interval: 0
retry_interval: 5000
max_retry_time: 180_000
max_retries: 5
max_retry_delay: 125_000
exponential_base: 2
mqtt:
enable: false
hostname: mosquitto
port: 1883
username: null
password: null
prefix: myelectricaldata
client_id: myelectricaldata # DOIT ETRE UNIQUE SUR LA TOTALITE DES CLIENTS CONNECTE AU SERVEUR MQTT
retain: true
qos: 0
# ca_cert: /certs/ca.pem # Certificate Authority a utiliser pour etablir une connection SSL au server MQTT
# Configuration SSL optionnel.
#ssl:
# keyfile: "/data/key.pem"
# certfile: "/data/cert.pem"
myelectricaldata:
# Configuration de mon point de livraison (ne pas oublier d'adapter MON_PDL_1 avec votre numéro de PDL)
"numéro-point-livraison":
enable: 'true'
token: montokenmyelectricaldata
name: "Maison"
addresses: 'true'
cache: 'true'
consumption: 'true'
consumption_detail: 'true'
consumption_price_base: '0.145907'
consumption_price_hc: '0.124364'
consumption_price_hp: '0.164915'
consumption_max_date: "2021-06-01"
consumption_detail_max_date: "2021-06-01"
offpeak_hours_0: 22H00-6H00 # LUNDI
offpeak_hours_1: 22H00-6H00 # MARDI
offpeak_hours_2: 22H00-6H00 # MERCREDI
offpeak_hours_3: 22H00-6H00 # JEUDI
offpeak_hours_4: 22H00-6H00 # VENDREDI
offpeak_hours_5: 22H00-6H00 # SAMEDI
offpeak_hours_6: 22H00-6H00 # DIMANCHE
#plan: HC/HP
# Configuration spécifique pour le tarif TEMPO
plan: "tempo"
heures_creuses:
# Les heures creuses Tempo d'EDF sont nationales et fixes : 22h00 à 6h00
tempo: "22:00-06:00"
production: 'false'
production_detail: 'false'
production_price: '0.0'
production_max_date: "2021-06-01"
production_detail_max_date: "2021-06-01"
refresh_addresse: 'false'
refresh_contract: 'false'

On créera également les répertoires suivants /etc/myelectricaldata/grafana_certs/ pour y mettre le certificat et la clé de chiffrement pour une connexion sécurisée, /etc/myelectricaldata/grafana_data/ pour les données de Grafana comme son nom l’indique. Grafana tourne avec l’utilisateur avec l’UID 472 que j’ai créé en tapant adduser –system –uid 472 grafana. Cet utilisateur doit être propriétaire de deux répertoires précédents. Pour InfluxDB, on trouvera /etc/myelectricaldata/influxdb_data pour les données et /etc/myelectricaldata/influxdb_certs pour le certificat et la clé de chiffrement. InfluxDB tourne avec l’utilisateur avec l’UID 1000, qu’on créera préalablement avec la commande adduser –system –uid 1000 influxdb. Il doit être propriétaire des deux répertoires précédents.

Pour la connexion sécurisée avec MyElectricalData sur le port par défaut 5000, j’ai copié le certificat et la clé de Let’s Encrypt que j’ai placé sous /etc/myelectricaldata/config. Ce n’est pas une solution pérenne car les mises à jour des fichiers ne seront pas prises en compte et comme les liens ne marchent pas il faudrait rendre accessible /etc/letsencrypt/live/ dans l’environnement isolé docker.

Pour la création des certificats et des clés pour avoir une connexion sécurisée avec Grafana sur le port par défaut 3000, j’ai choisi de les autosigner, ils ne seront valables que sur mon réseau local :

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/myelectricaldata/grafana_certs/grafana.key \
-out /etc/myelectricaldata/grafana_certs/grafana.crt \
-subj "/CN=ultra.kervao.fr"

on fera de même pour InfluxDB pour une connexion sur le port par défaut 8086, en tapant la commande :

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/myelectricaldata/influxdb_certs/influxdb-selfsigned.key \
-out /etc/myelectricaldata/influxdb_certs/influxdb-selfsigned.crt \
-subj "/CN=ultra.kervao.fr" \
-addext "subjectAltName = DNS:ultra.kervao.fr,DNS:influxdb,DNS:localhost,IP:127.0.0.1"

Il y a une subtilité, que m’a soufflé l’IA, dans la création de ce certificat et clé car j’ai rencontré des difficultés avec myelectricaldata qui n’arrivait pas à envoyer des données à InfluxDB. Depuis Python 3.10+, la vérification SSL standard rejette les certificats qui ne possèdent pas d’extension Subject Alternative Name, d’où la création du SAN et pour la résolution réseau interne, j’ai mis toutes les noms et adresses possibles. Ce n’est pas nécessaire avec la commande de création pour Grafana, car c’est via Firefox qu’on accepte le certificat en acceptant le risque. Ce n’est pas fini pour InfluxDB, on tapera aussi la commande :

cat /etc/ssl/certs/ca-bundle.crt /etc/myelectricaldata/influxdb_certs/influxdb-selfsigned.crt > /etc/myelectricaldata/influxdb_certs/combined-ca-bundle.crt

C’est également une subtilité soufflée par l’IA pour que Python valide à la fois le certificat auto-signé local et les certificats publics d’internet et ne rejette pas le certificat de myelectricaldata.fr.

Maintenant pour vérifier que tout ce beau monde cohabite bien, les logs de myelectricaldata doivent renvoyer que l’envoi vers InfluxDB est bien effectif :

2026-11-13 14:04:36.388 -     INFO : Envoi des données "CONSUMPTION" dans influxdb
2026-11-13 14:04:36.514 - INFO : => Données synchronisées (1098 valeurs)
2026-11-13 14:04:36.516 - INFO : Envoi des données "CONSUMPTION_DETAIL" dans influxdb
2026-11-13 14:04:36.737 - INFO : Cache : 3524 / InfluxDb : 3477
2026-11-13 14:04:36.737 - INFO : - 2026-06
2026-11-13 14:04:42.342 - INFO : - 2026-07
2026-11-13 14:05:06.241 - INFO : - 2026-08
2026-11-13 14:05:29.857 - INFO : - 2026-09
2026-11-13 14:05:53.305 - INFO : - 2026-10
2026-11-13 14:06:18.495 - INFO : - 2026-11
2026-11-13 14:06:31.530 - INFO : => OK
2026-11-13 14:06:31.540 - INFO : Envoi des données "TEMPO" dans influxdb
2026-11-13 14:07:08.553 - INFO : => OK
2026-11-13 14:07:08.557 - INFO : Envoi des données "ECOWATT" dans influxdb

Le point délicat est également la connexion sous Grafana à la base InfluxDB, voici quelques copies d’écran si ça peut aider :

Pour créer une vue, il faudra d’abord mettre en place la requête de récupération des données avec l’interface d’InfluxDB, ici la consommation en kWh :

En cliquant sur SCRIPT EDITOR, on récupère la commande qu’il faudra copier ensuite dans Grafana.

sous Grafana on reporte ensuite la formule pour créer une vue d’un tableau de bord :

Il y a ensuite plein d’options possibles comme la forme du graphique et tout un tas de paramètres accessibles sur le panneau à droite.

Pour mixer les données de deux sources, c’est un peu plus complexe, il faut installer le plugin infinity. Ensuite on crée une source de données Mixed, puis on crée deux requêtes, la requête myelectricaldata équivalente à l’image ci-dessus et une requête infinity qui ira chercher les informations sur les jours Tempo à l’URL indiqué dans l’image ci-dessous :

Il y a des options supplémentaires à indiquer dans Parsing options & Result fields :

Maintenant pour lui indiquer de remplir la couleur de la barre de consommation avec la couleur Tempo du jour, tout se passe dans le panneau de contrôle à droite avec les champs à saisir :

Il me reste à régler un problème de stabilité, le conteneur myelectricaldata ne tient pas 24h et part en erreur avec l’affichage du message suivant :

2026-11-13 13:49:23.089 -     INFO : ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ◦ ❖ ◦ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2026-11-13 13:49:23.089 - INFO : RÉCUPÉRATION DU STATUT DE LA PASSERELLE :
2026-11-13 13:49:23.089 - INFO : ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ◦ ❖ ◦ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2026-11-13 13:49:27.093 - ERROR : HTTPSConnectionPool(host='myelectricaldata.fr', port=443): Max retries exceeded with url: /ping (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7f653a269670>: Failed to resolve 'myelectricaldata.fr' ([Errno -3] Temporary failure in name resolution)"))
2026-11-13 13:59:27.099 - INFO : ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ◦ ❖ ◦ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2026-11-13 13:59:27.099 - INFO : RÉCUPÉRATION DU STATUT DE LA PASSERELLE :
2026-11-13 13:59:27.099 - INFO : ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ◦ ❖ ◦ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2026-11-13 13:59:31.104 - ERROR : HTTPSConnectionPool(host='myelectricaldata.fr', port=443): Max retries exceeded with url: /ping (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7f653a2686b0>: Failed to resolve 'myelectricaldata.fr' ([Errno -3] Temporary failure in name resolution)"))

Je n’ai pas d’autres solutions que de relancer le service docker pour que tout rentre dans l’ordre.

Laisser un commentaire