Outils pour utilisateurs

Outils du site


tp:work:suiviconso

Suivi de consommation électrique

Ce travail fait appel à des notions :

  • d'administration système (configuration d'un Raspberry Pi)
  • de programmation (Python)
  • de réseaux (serveur Web codé en Python - framework Bottle)
  • de bases de données (enregistrement des points dans une base sqlite)

Préparation du Raspberry

Les informations sont données sur la page : [[publish:install_raspberry|Installer et configurer un Raspberry Pi]]

Vérification du matériel

Nous allons utiliser la sortie téléinformation client disponible sur des compteurs assez récents. L'utilisation de cette sortie est libre (même pour les particuliers). Elle doit toutefois être activée. Les signaux sortant du compteur doivent être démodulés puis récupérés sur une interface série du Raspberry. Une documentation de la sortie téléinfo est disponible ici :

Test de la communication

Une fois tous les appareils branchés, chercher le port utilisé :

# dmesg

...
[  614.584538] usb 1-1.3: FTDI USB Serial Device converter now attached to ttyUSB0

Dans la suite nous supposerons que le port utilisé est ttyUSB0

# stty -F /dev/ttyUSB0 9600
# cat /dev/ttyUSB0

PAPP 00000 !
TDETAT 000000 B
ADCO 031328343332 :
OPTARIF BASE 0
ISOUSC 15 <
BASE 000076171 !
PTEC TH.. $
IINST 000 W
...

Si rien ne s'affiche, la sortie téléinfo n'est pas activée ou un des appareils est mal branché.

Lecture du port série avec Python

import serial
 
SER = serial.Serial("/dev/ttyUSB0", 9600, timeout=1)
for i in range(10):
  l2 = SER.readline()
  print(l2.decode("ascii"))
SER.close()

Composants logiciels à réaliser

  • lecture sur le port ttyUSB0 (module pyserial)
  • prétraitement des données (une mesure toutes les 10 secondes, calcul de valeur moyenne sur une minute)
  • enregistrement dans une base de données sqlite3
  • application Web de consultation des données

Lecture des données du compteur

Nous devons disposer d'une fonction getdata qui prend en paramètre un ensemble de champs à relever (par exemple PAPP ou IINST). Nous fournirons à getdata cet ensemble, et getdata renverrra en retour un dictionnaire contenant les valeurs mesurées et **datées**. Toutes les vérification (checksum, disponibilité des données) doivent être faites dans getdata :

>>> d = getdata({'PAPP', 'IINST'})
>>> print(d)
   {
     'PAPP': (datetime.datetime(2014, 6, 4, 11, 32, 50, 236561), '00000'), 
     'IINST': (datetime.datetime(2014, 6, 4, 11, 32, 50, 220739), '000')
   }

L'horodatage pourra être fait avec la fonction Python : datetime.datetime.now()

Mise en forme des données

Les données lues sur le compteur représentent un instantané de la consommation électrique, au moment précis où la lecture est faire. Pour ne pas omettre des pics de consommation brefs, il faut donc faire des lectures très fréquentes. En revanche, enregistrer un point de données toutes les 2 secondes dans une base de données risque de la faire croître inutilement (si l'enregistrement doit durer 1 mois, cela représenter 1.3 millions de points). Nous devons disposer d'un système qui permet de n'enregistrer qu'une valeur moyenne calculée à partir de plusieurs mesures.

Pour cela, nous allons écrire une fonction valeur_moyenne qui prend en paramètre une liste de mesures (une mesure est un couple (horodatage, valeur)) et renvoie un nouvel horodatage et une valeur moyenne. Sans présumer que les mesures seront régulièrement espacées dans le temps, essayez de minimiser les erreurs dues à ce calcul (faut-il simplement calculer des moyennes, intégrer ? que se passe-t-il s'il y a des données manquantes etc..)

Exemple :

>>> data = [
         (datetime.datetime(2014, 6, 4, 11, 37, 53, 618051), '00210'), 
         (datetime.datetime(2014, 6, 4, 11, 38, 3, 706097), '00200'), 
         (datetime.datetime(2014, 6, 4, 11, 38, 13, 836844), '00200'), 
         (datetime.datetime(2014, 6, 4, 11, 38, 23, 927376), '00200'), 
         (datetime.datetime(2014, 6, 4, 11, 38, 34, 7777), '00220'), 
         (datetime.datetime(2014, 6, 4, 11, 38, 44, 72780), '00210')
        ]
>>> v = valeur_moyenne(data)
>>> print(v)

('2014-06-04 11:38:18.861487', 206.0)

Dans le cas où la grandeur mesurée est l'index (voir la liste des grandeurs disponibles sur la sortie téléinfo), une mise en forme peut être de stocker dans la base la différence entre 2 mesures d'index successifs, afin de refléter la consommation à un moment donné (on pourra ainsi mettre en relation l'index avec la puissance apparente, pas exemple).

Enregistrement dans une base de données

Nous utiliserons une base sqlite, facile à créer, ne nécessitant pas de serveur, et facilement transportable (un seul fichier). La base ne contiendra qu'une table, nommé histo :

CREATE TABLE [histo] ([id] INTEGER PRIMARY KEY ASC AUTOINCREMENT, [type] VARCHAR (10), [valeur] REAL, [date] DATETIME);

L'accès à une base sqlite est facile avec Python. Voici un exemple pour une base de données nommée 'data.db' contenant une table :

CREATE TABLE [tbl] ([id] INTEGER PRIMARY KEY ASC AUTOINCREMENT, [type] VARCHAR (10), [valeur] REAL);
import sqlite3
db = sqlite3.connect('data.db')
c = db.cursor()
req = "insert into tbl (type,valeur) values (?,?)"
c.execute(req, ("PAPP", 230)
c.execute(req, ("PAPP", 240)
db.commit()
db.close()

On peut ensuite vérifier le contenu de la base :

# sqlite data.db
# select * from tbl
1|PAPP|230.0
2|PAPP|240.0

Pour l'enregistrement de la date, on dispose de la méthodeisoformat() utilisable sur une date Python et compréhensible par sqlite :

>>> import datetime
>>> d = datetime.datetime.now()
>>> d
datetime.datetime(2014, 6, 4, 10, 51, 22, 48450)
>>> d.isoformat()
'2014-06-04T10:51:22.048450'

Une fois cette partie réalisée, nous devons disposer d'une fonction lecture_continuelle_bdd qui prend en paramètres le nom du fichier de base de données, et l'ensemble des valeurs à consigner (éventuellement les délais de mesure et d'enregistrement, mais vous pouvez aussi les régler par le biais de variables globales (constantes) dans le code. La fonction pourra être utilisée ainsi:

lecture_continuelle_bdd('historique.db', {'PAPP'})

Voici le type d'enregistrements qu'on trouvera ensuite dans la base de données :

# sqlite3 historique.db
> select * from histo where id > 1160;
1161|PAPP|247.0|2014-06-04T06:47:58.423484
1162|PAPP|262.0|2014-06-04T06:48:59.061081
1163|PAPP|248.0|2014-06-04T06:49:59.680574
1164|PAPP|255.0|2014-06-04T06:51:00.292282
1165|PAPP|269.0|2014-06-04T06:52:00.885810
1166|PAPP|451.0|2014-06-04T06:53:01.496588
1167|PAPP|440.0|2014-06-04T06:54:01.840259
1168|PAPP|429.0|2014-06-04T06:55:02.232305
1169|PAPP|462.0|2014-06-04T06:56:02.569334
1170|PAPP|470.0|2014-06-04T06:57:03.185957
1171|PAPP|468.0|2014-06-04T06:58:03.586237
1172|PAPP|388.0|2014-06-04T06:59:03.932325
1173|PAPP|311.0|2014-06-04T07:00:04.535068
1174|PAPP|306.0|2014-06-04T07:01:05.146657
1175|PAPP|311.0|2014-06-04T07:02:05.754935
1176|PAPP|310.0|2014-06-04T07:03:06.353125
1177|PAPP|307.0|2014-06-04T07:04:06.951739
1178|PAPP|303.0|2014-06-04T07:05:07.567461
1179|PAPP|314.0|2014-06-04T07:06:08.177827
1180|PAPP|300.0|2014-06-04T07:07:08.552106

Application Web de consultation des données

On réalise ici une application Web qui lit des mesures dans la base de données et les présente à l'utilisateur. Nous utiliserons le framework 'bottle' pour réaliser l'application Python. La présentation des données (graphiques) peut être réalisée de plusieurs manières. Une possibilité est d'utiliser la bibliothèque Javascript hicharts.

Exemple d'application bottle:

web.py
import bottle
import datetime
@bottle.route("/time")
def index() :
    heure = datetime.datetime.now().strftime("Nous sommes le %d/%m/%Y, il est %H:%M:%S")
    stri = "<h1>Horloge</h1>"+heure
    return stri
 
bottle.run(bottle.app(), host=’0.0.0.0’, port=8080, debug= True, reloader=True)

Une fois l'application lancée, faire pointer le navigateur sur : ''http://localhost:8080/time </file> La documentation de bottle est disponible ici : http://bottlepy.org/docs/0.12/ Bottle utilise un système de template qu'il faut utiliser dès que les pages sont un peu conséquentes (sous peine de perdre du temps en débuggage et de créer une application difficile à adapter aux besoins). La bibliothèque highcharts est documentée ici : http://www.highcharts.com/. On pourra par exemple utiliser un graphique de type http://www.highcharts.com/demo/spline-irregular-time Une fois ce travail terminé, la consultation de l'URL : http://localhost:8080/last/5'' affichera les données pour les 5 dernières heures.

Voici le type de représentation qu'on peut obtenir par ce moyen :

tp/work/suiviconso.txt · Dernière modification: 2014/09/05 16:39 (modification externe)