2019-02-13 22:32:50 +00:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "Sébastien Reuiller"
# __licence__ = "Apache License 2.0"
# Python 3, prerequis : pip install pySerial influxdb
#
# Exemple de trame:
# {
2020-08-28 20:43:23 +00:00
# 'BASE': '123456789' # Index heure de base en Wh
# 'OPTARIF': 'HC..', # Option tarifaire HC/BASE
# 'IMAX': '007', # Intensité max
# 'HCHC': '040177099', # Index heure creuse en Wh
2019-02-13 22:32:50 +00:00
# 'IINST': '005', # Intensité instantanée en A
2020-08-28 20:43:23 +00:00
# 'PAPP': '01289', # Puissance Apparente, en VA
2019-02-13 22:32:50 +00:00
# 'MOTDETAT': '000000', # Mot d'état du compteur
# 'HHPHC': 'A', # Horaire Heures Pleines Heures Creuses
# 'ISOUSC': '45', # Intensité souscrite en A
# 'ADCO': '000000000000', # Adresse du compteur
# 'HCHP': '035972694', # index heure pleine en Wh
# 'PTEC': 'HP..' # Période tarifaire en cours
# }
import serial
import logging
import time
import requests
from datetime import datetime
from influxdb import InfluxDBClient
# clés téléinfo
2020-08-28 20:43:23 +00:00
int_measure_keys = [ ' BASE ' , ' IMAX ' , ' HCHC ' , ' IINST ' , ' PAPP ' , ' ISOUSC ' , ' ADCO ' , ' HCHP ' ]
no_checksum = [ ' MOTDETAT ' ]
2019-02-13 22:32:50 +00:00
# création du logguer
logging . basicConfig ( filename = ' /var/log/teleinfo/releve.log ' , level = logging . INFO , format = ' %(asctime)s %(message)s ' )
logging . info ( " Teleinfo starting.. " )
# connexion a la base de données InfluxDB
client = InfluxDBClient ( ' localhost ' , 8086 )
db = " teleinfo "
connected = False
while not connected :
try :
logging . info ( " Database %s exists? " % db )
if not { ' name ' : db } in client . get_list_database ( ) :
logging . info ( " Database %s creation.. " % db )
client . create_database ( db )
logging . info ( " Database %s created! " % db )
client . switch_database ( db )
logging . info ( " Connected to %s ! " % db )
except requests . exceptions . ConnectionError :
logging . info ( ' InfluxDB is not reachable. Waiting 5 seconds to retry. ' )
time . sleep ( 5 )
else :
connected = True
def add_measures ( measures , time_measure ) :
points = [ ]
for measure , value in measures . items ( ) :
point = {
" measurement " : measure ,
" tags " : {
2020-08-28 20:43:23 +00:00
# identification de la sonde et du compteur
2019-02-13 22:32:50 +00:00
" host " : " raspberry " ,
" region " : " linky "
} ,
" time " : datetime . utcnow ( ) . strftime ( " % Y- % m- %d T % H: % M: % SZ " ) ,
" fields " : {
" value " : value
}
}
points . append ( point )
client . write_points ( points )
2020-08-29 14:39:04 +00:00
def verif_checksum ( data , checksum ) :
2020-08-26 07:06:42 +00:00
data_unicode = 0
2020-08-29 14:39:04 +00:00
for caractere in data :
data_unicode + = ord ( caractere )
2020-08-26 07:06:42 +00:00
sum_unicode = ( data_unicode & 63 ) + 32
sum = chr ( sum_unicode )
2020-08-29 14:39:04 +00:00
if ( checksum == sum ) :
return True
else :
return False
2020-08-26 07:06:42 +00:00
2019-02-13 22:32:50 +00:00
def main ( ) :
with serial . Serial ( port = ' /dev/ttyS0 ' , baudrate = 1200 , parity = serial . PARITY_NONE , stopbits = serial . STOPBITS_ONE ,
bytesize = serial . SEVENBITS , timeout = 1 ) as ser :
logging . info ( " Teleinfo is reading on /dev/ttyS0.. " )
trame = dict ( )
# boucle pour partir sur un début de trame
line = ser . readline ( )
while b ' \x02 ' not in line : # recherche du caractère de début de trame
line = ser . readline ( )
# lecture de la première ligne de la première trame
line = ser . readline ( )
while True :
line_str = line . decode ( " utf-8 " )
2020-08-29 14:39:04 +00:00
logging . debug ( line )
ar = line_str . split ( " " ) # separation sur espace /!\ attention le caractere de controle 0x32 est un espace aussi
# preparation données pour verification checksum
data = ar [ 0 ] + " " + ar [ 1 ]
checksum = ( line_str . replace ( ' \x03 \x02 ' , ' ' ) ) [ - 3 : - 2 ] # supprimer les retours charriot et saut de ligne puis selectionne le caractere de controle en partant de la fin
verif_checksum ( data , checksum )
2019-02-13 22:32:50 +00:00
try :
key = ar [ 0 ]
2020-08-29 14:39:04 +00:00
if key in int_measure_keys : # typer les valeurs numériques en "integer"
2019-02-13 22:32:50 +00:00
value = int ( ar [ 1 ] )
else :
2020-08-29 14:39:04 +00:00
value = ar [ 1 ] # typer les autres valeurs en "string"
trame [ key ] = value # creation du champ pour la trame en cours
2020-08-28 20:43:23 +00:00
2019-02-13 22:32:50 +00:00
if b ' \x03 ' in line : # si caractère de fin dans la ligne, on insère la trame dans influx
del trame [ ' ADCO ' ] # adresse du compteur : confidentiel!
time_measure = time . time ( )
# insertion dans influxdb
2020-08-29 14:39:04 +00:00
if ( verif_checksum ) :
2020-08-28 20:43:23 +00:00
add_measures ( trame , time_measure )
2019-02-13 22:32:50 +00:00
# ajout timestamp pour debugger
trame [ " timestamp " ] = int ( time_measure )
logging . debug ( trame )
trame = dict ( ) # on repart sur une nouvelle trame
except Exception as e :
2020-08-28 20:43:23 +00:00
logging . error ( " Exception : %s " % e , exc_info = True )
logging . error ( " %s %s " % ( key , value ) )
2019-02-13 22:32:50 +00:00
line = ser . readline ( )
if __name__ == ' __main__ ' :
if connected :
main ( )