Un petit projet que je prévoyais depuis longtemps : mesurer ma consommation électrique plus ou moins en temps réel avec un Raspberry Pi. Si vous avez un compteur EDF assez récent (moins de 10 ans), c’est assez simple à faire avec un Raspberry Pi, même si les valeurs restent indicatives (et surévaluées, je l’explique dans le texte).
C’est assez long, je vous préviens. Première chose, le matériel. J’ai utilisé un Raspberry Pi A+ relié en Wi-Fi et – pour m’éviter les soudures – un adaptateur pour connecter directement la prise téléinfo aux GPIO du Raspberry Pi. Ca existe aussi en USB (là) et il est parfaitement possible de se monter l’adaptateur manuellement, ce site (sur lequel j’ai récupéré le code) l’explique.
Le branchement au compteur ne pose pas de soucis : il existe deux prises (à vis) dans lesquelles il suffit de mettre des câbles et c’est tout. Pas besoin de couper le courant, étant donné que le disjoncteur est généralement après le compteur.
La partie logicielle demande plus de travail pour un truc propre.
Première chose, mettre à jour l’OS.
sudo apt-get update
sudo apt-get upgrade
Ensuite, lancez un raspi-config et désactivez la console série dans les options. Il est aussi nécessaire de bien fixer la date (et le lieu) pour être certain d’être à l’heure.
sudo raspi-config
Enfin, une petite modification est nécessaire pour lire correctement les données téléinfo.
sudo nano /etc/rc.local
Dans le fichier, juste avant exit 0
, il faut ajouter la ligne suivante.
stty -F /dev/ttyAMA0 1200 sane evenp parenb cs7 -crtscts
Un truc que je fais toujours, ce qui simplifie l’accès à distance avec un Mac, c’est d’annoncer via Bonjour. J’explique ça sur un post dédié.
Etape suivante, un serveur Web. L’idée va être de faire une page dédiée avec les données. J’ai utilisé ce qui est expliqué sur ce site, avec quelques corrections.
sudo apt-get install apache2 php5 php5-sqlite libapache2-mod-php5
sudo a2enmod rewrite
sudo /etc/init.d/apache2 restart
cd /var/www/html
sudo rm index.html
Premièrement, le fichier avec les fonctions (teleinfo_func.php) du magdiblog. Vu la taille, je vous mets la version originale directement là. Les corrections à effectuer :
ligne 10, remplacer $handle = fopen ('/dev/ttyACM0', "r");
par $handle = fopen ('/dev/ttyAMA0', "r");
.
ligne 3, remplacer $sqlite = 'teleinfo.sqlite';
par $sqlite = '/home/pi/teleinfo.sqlite';
.
ligne 137, remplacer $month = date("n", $row['timestamp']-1);
par $month = date("n", $row['timestamp'])-1;
.
ligne 142, remplacer kW
par W
.
Ensuite, un fichier qui va récupérer la puissance (en V.A, je vais développer ensuite).
sudo nano teleinfo_puissance.php
Le contenu :
#!/usr/bin/php5
<?php
header('Content-type: text/html; charset=utf-8');
require_once('/var/www/html/teleinfo_func.php');
handlePuissance();
?>
Ensuite, un fichier qui va récupérer la consommation journalière (en kWh).
sudo nano teleinfo_conso.php
Le contenu :
#!/usr/bin/php5
<?php
header('Content-type: text/html; charset=utf-8');
require_once('/var/www/html/teleinfo_func.php');
handleConso();
?>
Enfin, la page qui va afficher les graphiques. Même chose, c’est un peu long, donc je vous file le fichier brut de Magdiblog.
Pour des raisons pratiques, je l’appelle index.php
, avec une modification cosmétique : ligne 21, remplacer kW
par W
.
Maintenant, il faut lancer les deux petits scripts régulièrement pour stocker les données dans une base de données. Il faut donc les rendre exécutables et programmer une tâche. Le premier toutes les minutes, le second tous les jours à 23h58.
sudo chmod +x teleinfo_puissance.php
sudo chmod +x teleinfo_conso.php
crontab -e
Ajoutez les deux lignes suivantes.
* * * * * php /var/www/html/teleinfo_puissance.php
58 23 * * * php /var/www/html/teleinfo_conso.php
Techniquement, si votre Raspberry Pi est branché, il suffit de tester avec les lignes suivantes.
cat /dev/ttyAMA0
Cette ligne devrait afficher les données envoyées par le compteur. Si rien ne s’affiche, vous avez mal effectué les branchements. Si une seule ligne s’affiche et qu’elle commence par ADCO
, la gestion téléinfo n’est pas activée, vous pouvez demander à EDF de le faire.
Normalement, il suffit ensuite de se connecter sur le Raspberry en tapant son adresse IP dans la barre d’adresse pour accéder au graphique.
Les valeurs en V.A et en W sont intéressantes : elles ne représentent pas la consommation réelle. En fait, la gestion téléinfo ne donne pas en temps réel la consommation en W classique (puissance active), mais bien la consommation en V.A (puissance apparente). Chez les particuliers, c’est la première qui est facturée, la seconde étant plus élevée. En simplifiant, EDF doit envoyer plus de puissance dans le réseau, et c’est cette valeur (non corrigée) qui est affichée. La valeur en V.A est donc systématiquement plus élevée que la valeur facturée par EDF (si des puristes veulent me corriger, pas de soucis). Le script utilisé ici affiche la valeur en V.A mais aussi la valeur en « Watts » qui est en fait calculé de façon basique en multipliant l’intensité renvoyée par 220 V (la tension théorique). En pratique, les deux valeurs de la courbe ne sont pas identiques parce que la tension varie. De plus, comme la gestion téléinfo ne renvoie pas de décimale pour l’intensité, la valeur réelle peut être plus faible ou plus élevée (en fonction de l’intensité réelle et de la façon d’arrondir le résultat). Les valeurs de consommation sont donc surévaluées, mais les courbes restent valables pour identifier un pic de consommation ou un appareil qui se met en marche périodiquement.
Techniquement, il est possible de récupérer la valeur en kWh en comparant deux relevés de consommation, mais ça demande un peu de travail d’adaptation pour le script.
Les bonus
Si comme moi, vous connectez le Raspberry Pi en Wi-Fi, quelques petits trucs.
Premièrement, activer le Wi-Fi et empêcher la mise en veille de la carte.
sudo nano /etc/network/interfaces
Remplacez auto lo
par auto wlan0
.
Remplacez iface wlan0 inet manual
par iface wlan0 inet dhcp
.
Ajoutez wireless-power off
.
Deuxièmement, configurez les paramètres du réseau.
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
Ajoutez les lignes suivantes (pour un réseau protégé en WPA2).
network={
ssid="YOUR_NETWORK_NAME"
psk="YOUR_NETWORK_PASSWORD"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
auth_alg=OPEN
}
Le second, pratique avec un Mac, c’est d’annoncer la présence de la page sur le réseau, pour un acès via Bonjour. Une fois l’accès SSH activé (comme expliqué là), il suffit des deux commandes suivantes.
sudo nano /etc/avahi/services/teleinfo.service
Avec comme contenu.
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>Téléinfo</name>
<service>
<type>_http._tcp</type>
<port>80</port>
<txt-record>path=/index.php</txt-record>
</service>
</service-group>
Puis de relancer le démon.
sudo service avahi-daemon restart
Ensuite, la page téléinfo sera accessible via Bonjour avec Safari.
Super tuto merci !
Quelques remarques :
– J’ai pris la version avec port USB. Je suis resté bloqué au niveau de la récupération des informations de mon compteur (je débute avec un raspberry pi) : dans ce cas là sortie n’est pas sur /dev/ttyAMA0 mais sur /dev/ttyUSB0 (le dernier chiffre peut changer selon les ports utilisés). Il faut faire cette modification dans /etc/rc.local et dans teleinfo_func.php. Et à la fin il faut faire un cat /dev/ttyUSB0 pour tester ;
– J’ai modifié teleinfo_func.php pour le faire fonctionner avec mysql (quelques ajustements pour pdo, si ça sert à des gens)
$message) {
$message = explode (‘ ‘, $message, 3); // on separe l’etiquette, la valeur et la somme de controle de chaque message
if(!empty($message[0]) && !empty($message[1])) {
$etiquette = $message[0];
$valeur = $message[1];
$datas[$etiquette] = $valeur; // on stock les etiquettes et les valeurs de l’array datas
}
}
return $datas;
}
//
// enregistre la puissance instantanée en V.A et en W
//
function handlePuissance () {
global $sqlUrl;
global $sqlBdd;
global $sqlUser;
global $sqlPass;
try {
$db = new PDO(‘mysql:host=’.$sqlUrl.’;dbname=’.$sqlBdd, $sqlUser, $sqlPass);
} catch (PDOException $e) {
print « Erreur !: » . $e->getMessage() . « »;
die();
}
$db->exec(‘CREATE TABLE IF NOT EXISTS puissance (timestamp INTEGER, hchp TEXT, va REAL, iinst REAL, watt REAL);’); // cree la table puissance si elle n’existe pas
$trame = getTeleinfo (); // recupere une trame teleinfo
$datas = array();
$datas[‘timestamp’] = time();
$datas[‘hchp’] = substr($trame[‘PTEC’],0,2); // indicateur heure pleine/creuse, on garde seulement les carateres HP (heure pleine) et HC (heure creuse)
$datas[‘va’] = preg_replace(‘`^[0]*`’, »,$trame[‘PAPP’]); // puissance en V.A, on supprime les 0 en debut de chaine
$datas[‘iinst’] = preg_replace(‘`^[0]*`’, »,$trame[‘IINST’]); // intensité instantanée en A, on supprime les 0 en debut de chaine
$datas[‘watt’] = $datas[‘iinst’]*220; // intensite en A X 220 V
$db->exec(« INSERT INTO puissance (timestamp, hchp, va, iinst, watt) VALUES (« .$datas[‘timestamp’]. », ‘ ».$datas[‘hchp’]. »‘, « .$datas[‘va’]. », « .$datas[‘iinst’]. », « .$datas[‘watt’]. »); »);
return 1;
}
//
// enregistre la consommation en Wh
//
function handleConso () {
global $sqlUrl;
global $sqlBdd;
global $sqlUser;
global $sqlPass;
try {
$db = new PDO(‘mysql:host=’.$sqlUrl.’;dbname=’.$sqlBdd, $sqlUser, $sqlPass);
} catch (PDOException $e) {
print « Erreur !: » . $e->getMessage() . « »;
die();
}
$db->exec(‘CREATE TABLE IF NOT EXISTS conso (timestamp INTEGER, total_hc INTEGER, total_hp INTEGER, daily_hc REAL, daily_hp REAL);’); // cree la table conso si elle n’existe pas
$trame = getTeleinfo (); // recupere une trame teleinfo
$today = strtotime(‘today 00:00:00’);
$yesterday = strtotime(« -1 day 00:00:00 »);
// recupere la conso totale enregistree la veille pour pouvoir calculer la difference et obtenir la conso du jour
$previous = $db->query(« SELECT * FROM conso WHERE timestamp = ‘ ».$yesterday. »‘; »)->fetch(PDO::FETCH_ASSOC);
if(empty($previous)){
$previous = array();
$previous[‘timestamp’] = $yesterday;
$previous[‘total_hc’] = 0;
$previous[‘total_hp’] = 0;
$previous[‘daily_hc’] = 0;
$previous[‘daily_hp’] = 0;
}
$datas = array();
$datas[‘query’] = ‘hchp’;
$datas[‘timestamp’] = $today;
$datas[‘total_hc’] = preg_replace(‘`^[0]*`’, »,$trame[‘HCHC’]); // conso total en Wh heure creuse, on supprime les 0 en debut de chaine
$datas[‘total_hp’] = preg_replace(‘`^[0]*`’, »,$trame[‘HCHP’]); // conso total en Wh heure pleine, on supprime les 0 en debut de chaine
if($previous[‘total_hc’] == 0){
$datas[‘daily_hc’] = 0;
}
else{
$datas[‘daily_hc’] = ($datas[‘total_hc’]-$previous[‘total_hc’])/1000; // conso du jour heure creuse = total aujourd’hui – total hier, on divise par 1000 pour avec un resultat en Wh
}
if($previous[‘total_hp’] == 0){
$datas[‘daily_hp’] = 0;
}
else{
$datas[‘daily_hp’] = ($datas[‘total_hp’]-$previous[‘total_hp’])/1000; // conso du jour heure pleine = total aujourd’hui – total hier, on divise par 1000 pour avec un resultat en Wh
}
// stock les donnees
$db->exec(« INSERT INTO conso (timestamp, total_hc, total_hp, daily_hc, daily_hp) VALUES (« .$datas[‘timestamp’]. », « .$datas[‘total_hc’]. », « .$datas[‘total_hp’]. », « .$datas[‘daily_hc’]. », « .$datas[‘daily_hp’]. »); »);
}
//
// recupere les donnees de puissance des $nb_days derniers jours et les met en forme pour les affichers sur le graphique
//
function getDatasPuissance ($nb_days) {
global $sqlUrl;
global $sqlBdd;
global $sqlUser;
global $sqlPass;
$months = array(’01’ => ‘janv’, ’02’ => ‘fev’, ’03’ => ‘mars’, ’04’ => ‘avril’, ’05’ => ‘mai’, ’06’ => ‘juin’, ’07’ => ‘juil’, ’08’ => ‘aout’, ’09’ => ‘sept’, ’10’ => ‘oct’, ’11’ => ‘nov’, ’12’ => ‘dec’);
$now = time();
$past = strtotime(« -$nb_days day », $now);
try {
$db = new PDO(‘mysql:host=’.$sqlUrl.’;dbname=’.$sqlBdd, $sqlUser, $sqlPass);
} catch (PDOException $e) {
print « Erreur !: » . $e->getMessage() . « »;
die();
}
$results = $db->query(« SELECT * FROM puissance WHERE timestamp > $past ORDER BY timestamp ASC; »);
$sums = array();
$days = array();
$datas = array();
while($row = $results->fetch(PDO::FETCH_ASSOC)){
$year = date(« Y », $row[‘timestamp’]);
$month = date(« n », $row[‘timestamp’])-1;
$day = date(« j », $row[‘timestamp’]);
$hour = date(« G », $row[‘timestamp’]);
$minute = date(« i », $row[‘timestamp’]);
$second = date(« s », $row[‘timestamp’]);
$datas[] = « [{v:new Date($year, $month, $day, $hour, $minute, $second), f:' ».date(« j », $row[‘timestamp’]). » « .$months[date(« m », $row[‘timestamp’])]. » « .date(« H\hi », $row[‘timestamp’]). »‘}, {v: ».$row[‘va’]. », f:' ».$row[‘va’]. » V.A’}, {v: ».$row[‘watt’]. », f:' ».$row[‘watt’]. » W’}] »;
}
return implode(‘, ‘, $datas);
}
//
// recupere les donnees de consommation des $nb_days derniers jours et les met en forme pour les affichers sur le graphique
//
function getDatasConso ($nb_days) {
global $sqlUrl;
global $sqlBdd;
global $sqlUser;
global $sqlPass;
$months = array(’01’ => ‘janv’, ’02’ => ‘fev’, ’03’ => ‘mars’, ’04’ => ‘avril’, ’05’ => ‘mai’, ’06’ => ‘juin’, ’07’ => ‘juil’, ’08’ => ‘aout’, ’09’ => ‘sept’, ’10’ => ‘oct’, ’11’ => ‘nov’, ’12’ => ‘dec’);
$now = time();
$past = strtotime(« -$nb_days day », $now);
try {
$db = new PDO(‘mysql:host=’.$sqlUrl.’;dbname=’.$sqlBdd, $sqlUser, $sqlPass);
} catch (PDOException $e) {
print « Erreur !: » . $e->getMessage() . « »;
die();
}
$results = $db->query(« SELECT * FROM conso WHERE timestamp > $past ORDER BY timestamp ASC; »);
$datas = array();
while($row = $results->fetch(PDO::FETCH_ASSOC)){
$day = date(« j », $row[‘timestamp’]). » « .$months[date(« m », $row[‘timestamp’])];
$datas[] = « [‘ ».$day. »‘, {v: ».$row[‘daily_hp’]. », f:' ».$row[‘daily_hp’]. » kWh’}, {v: ».$row[‘daily_hc’]. », f:' ».$row[‘daily_hc’]. » kWh’}] »;
}
return implode(‘, ‘, $datas);
}
?>
Et j’ai un dernier soucis : au démarrage /etc/rc.local n’est pas exécuté. Du coup la sortie USB est illisible tant que je ne l’ai pas lancé manuellement…
Bonjour,
Tout d’abord merci pour ce tuto clair qui m’a tout de suite donné envie de le réaliser !
J’ai un petit soucis lorsque je tape l’adresse IP de ma RPi. En ouvrant les différents fichiers, je me retrouve avec des Warnings un peu partout dans les fichiers teleinfo_conso.php et teleinfo_puissance.php :
#!/usr/bin/php5
Warning: Cannot modify header information – headers already sent by (output started at /var/www/html/teleinfo_conso.php:2) in /var/www/html/teleinfo_conso.php on line 3
Warning: fopen(/dev/ttyAMA0): failed to open stream: Permission denied in /var/www/html/teleinfo_func.php on line 10
Warning: fread() expects parameter 1 to be resource, boolean given in /var/www/html/teleinfo_func.php on line 12
Warning: fread() expects parameter 1 to be resource, boolean given in /var/www/html/teleinfo_func.php on line 12
Warning: fread() expects parameter 1 to be resource, boolean given in /var/www/html/teleinfo_func.php on line 12
Warning: fread() expects parameter 1 to be resource, boolean given in /var/www/html/teleinfo_func.php on line 12
Warning: fread() expects parameter 1 to be resource, boolean given in /var/www/html/teleinfo_func.php on line 12
Dans les fichiers, teleinfo_graph.php et teleinfo_func.php, rien ne s’affiche.
Merci de votre aide !
Il faut vérifier que c’est bien /dev/ttyAMA0 pour votre adaptateur
Et aussi qu’il n’y a pas un espace ou un caractères bizarre avant le code PHP dans les fichiers (surtout en cas de copier/coller). Parfois, il suffit simplement de supprimer les fichiers et les refaire en faisant un copier/coller depuis un éditeur de texte basique, pour être certain qu’il ne modifie pas les caractères (le blocnote sous Windows, par exemple)
Merci de votre réponse rapide !
Je suis sous Rpi 3. Est-ce bien le bon chemin ? J’ai cru comprendre qu’il y avait également ttyS0 mais je n’en suis pas certain.
Je ne pense pas qu’il y ait d’espace en trop. J’ai essayé de faire attention ^^’
Il faut faire ls /dev/tty* et regarder le résultat. Quel adaptateur utilisez-vous ? S’il est en USB, son nom doit être différent, sûrement avec un « usb » dedans
je n’utilise pas d’adaptateur usb. Je l’ai monté directement par l’intermédiaire une breadboard. J’ai trouvé le montage sur http://www.magdiblog.fr/gpio/teleinfo-edf-suivi-conso-de-votre-compteur-electrique/
Voilà ce que j’observe que je fais ls /dev/tty* :
/dev/tty /dev/tty16 /dev/tty24 /dev/tty32 /dev/tty40 /dev/tty49 /dev/tty57 /dev/tty8
/dev/tty0 /dev/tty17 /dev/tty25 /dev/tty33 /dev/tty41 /dev/tty5 /dev/tty58 /dev/tty9
/dev/tty1 /dev/tty18 /dev/tty26 /dev/tty34 /dev/tty42 /dev/tty50 /dev/tty59 /dev/ttyAMA0
/dev/tty10 /dev/tty19 /dev/tty27 /dev/tty35 /dev/tty43 /dev/tty51 /dev/tty6 /dev/ttyprintk
/dev/tty11 /dev/tty2 /dev/tty28 /dev/tty36 /dev/tty44 /dev/tty52 /dev/tty60
/dev/tty12 /dev/tty20 /dev/tty29 /dev/tty37 /dev/tty45 /dev/tty53 /dev/tty61
/dev/tty13 /dev/tty21 /dev/tty3 /dev/tty38 /dev/tty46 /dev/tty54 /dev/tty62
/dev/tty14 /dev/tty22 /dev/tty30 /dev/tty39 /dev/tty47 /dev/tty55 /dev/tty63
/dev/tty15 /dev/tty23 /dev/tty31 /dev/tty4 /dev/tty48 /dev/tty56 /dev/tty7
C’est a priori bien le bon. Donc faut vérifier les espaces au début des fichiers et la présence de PHP5, vu le message
Je revérifie et je vous tiens au courant !
Etant néophyte du système je voudrais savoir comment faire pour démarrer l’application, car jusqu’à la fin de l’installation pas de problème j’ai bien l’apparition des données avec cat /dev/ttyAMA0 mais impossible d’avoir le graph.Quel serait la commande à faire et quel ordre lui donner.
Il faut simplement taper l’adresse IP du Raspberry Pi dans un navigateur sur un ordinateur connecté au même réseau
Bonjou Pierre
En ce qui concerne la config: unRPI2 avec un écran sur RCA une clef WI FI et une clef pour le clavier + la liaison avec l’opto. Les 3 fichiers se trouvent dans le root (conso-func-puissance). Vous citez « Pour des raisons pratiques, je l’appelle index.php » je suppose que c’est le fichier teleinfo_func que j’ai renommé index.html.J’ai bien effectué opération mais hélas sans résultat.
Je vous remercie pour votre première réponse
Cordialement
Et si j’utilise des anciens compteurs, ça sera le même travail?
bonjour à tous,
merci pour ce tuto qui m’a permis d’avancer un peu mais tous mes problèmes ne sont pas résolus.
j’ai des connaissances très limitées en programmation, je vous expose mon problème au cas ou quelqu’un essaierait de m’aider.
j’utilise un pi zero associé au Ptinfo, j’arrive à recevoir les trames à partir de la cde cat/dev/ttyAMA0
lorsque que je tape l’adresse tu pi, j’ai la page apache2 qui s’affiche.
comment savoir si les données arrivent bien dans sqlite ?
merci d’avance pour vos conseils
cdt
bonjour à tous,
Je recherche une aide pour réaliser une teleinfo sur linky.
ma config raspberry pi zero w- module PiTInfo V1.2.
ce qui fonctionne :
la transmission des trames cat /dev/ttyAMA0
pas de log d’erreur dans Apache2
dans sqlite3 /home/pi/teleinfo.sqlite, je retrouve bien les tables conso & puissance
lorsque je passe la commande select * from puissance ou conso, elles sont vides
un conseil pour progresser serait le bienvenu
cdt
Merci pour le tuto, très clair
Ça fonctionne…Maintenant je veux ajouter un compteur de production sur le même raspberry.
Il faut probablement un second interface après sur quel les broches faut il le brancher?et comment configurer le port série correspondant?
Merci….