Skip to content

Commit

Permalink
teleinfo.py
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Emmanuel Brinette committed Feb 16, 2024
2 parents 32f8521 + 2dc277e commit 52f44df
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 39 deletions.
3 changes: 3 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=119
24 changes: 24 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# - https://timothycrosley.github.io/isort/
# - https://github.com/timothycrosley/isort#configuring-isort
# - https://github.com/timothycrosley/isort/wiki/isort-Settings

[isort]
combine_as_imports = True
ensure_newline_before_comments = True
force_grid_wrap = 0
include_trailing_comma = True
known_first_party = itou
lines_after_imports = 2
line_length = 119
multi_line_output = 3
use_parentheses = True

# - https://www.flake8rules.com
# - http://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html#changing-the-ignore-list

[flake8]
# E203: Whitespace before ':', used to please Black in `yield items[i : i + n]`
# E266: Too many leading '#' for block comment
# W503: Line break occurred before a binary operator
ignore = E203, E266, W503
max-line-length = 119
93 changes: 54 additions & 39 deletions teleinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
# __author__ = "Sébastien Reuiller"
# __licence__ = "Apache License 2.0"

# Python 3, prerequis : pip install pySerial influxdb
# Python 3, prérequis : pip install pySerial influxdb
#
# Exemple de trame:
# {
# 'OPTARIF': 'HC..', # option tarifaire
# 'IMAX': '007', # intensité max
# 'HCHC': '040177099', # index heure creuse en Wh
# '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
# 'IINST': '005', # Intensité instantanée en A
# 'PAPP': '01289', # puissance Apparente, en VA
# 'PAPP': '01289', # Puissance Apparente, en VA
# 'MOTDETAT': '000000', # Mot d'état du compteur
# 'HHPHC': 'A', # Horaire Heures Pleines Heures Creuses
# 'ISOUSC': '45', # Intensité souscrite en A
Expand All @@ -21,33 +22,35 @@
# }


import serial
import logging
import time
import requests
from datetime import datetime

import requests
import serial
from influxdb import InfluxDBClient


# clés téléinfo
int_measure_keys = ['IMAX', 'HCHC', 'IINST', 'PAPP', 'ISOUSC', 'ADCO', 'HCHP']
INT_MESURE_KEYS = ['BASE', 'IMAX', 'HCHC', 'IINST', 'PAPP', 'ISOUSC', 'ADCO', 'HCHP']

# 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) # , username='teleinfo', password='PWDteleinfo2021')
db = "teleinfo"
client = InfluxDBClient('localhost', 8086)
DB_NAME = "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)
logging.info("Database %s exists?" % DB_NAME)
if not {'name': DB_NAME} in client.get_list_database():
logging.info("Database %s creation.." % DB_NAME)
client.create_database(DB_NAME)
logging.info("Database %s created!" % DB_NAME)
client.switch_database(DB_NAME)
logging.info("Connected to %s!" % DB_NAME)
except requests.exceptions.ConnectionError:
logging.info('InfluxDB is not reachable. Waiting 5 seconds to retry.')
time.sleep(5)
Expand All @@ -59,21 +62,30 @@ def add_measures(measures, time_measure):
points = []
for measure, value in measures.items():
point = {
"measurement": measure,
"tags": {
"host": "raspberry",
"region": "linky"
},
"time": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
"fields": {
"value": value
}
}
"measurement": measure,
"tags": {
# identification de la sonde et du compteur
"host": "raspberry",
"region": "linky"
},
"time": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
"fields": {
"value": value
}
}
points.append(point)

client.write_points(points)


def verif_checksum(data, checksum):
data_unicode = 0
for caractere in data:
data_unicode += ord(caractere)
sum_unicode = (data_unicode & 63) + 32
return (checksum == chr(sum_unicode))


def main():
with serial.Serial(port='/dev/ttyUSB0', baudrate=1200, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS, timeout=1) as ser:
Expand All @@ -92,16 +104,20 @@ def main():

while True:
line_str = line.decode("utf-8")
ar = line_str.split(" ")
logging.debug(line)

try:
key = ar[0]
if key in int_measure_keys :
value = int(ar[1])
else:
value = ar[1]

checksum = ar[2]
trame[key] = value
# separation sur espace /!\ attention le caractere de controle 0x32 est un espace aussi
[key, val, *_] = line_str.split(" ")

# supprimer les retours charriot et saut de ligne puis selectionne le caractere
# de controle en partant de la fin
checksum = (line_str.replace('\x03\x02', ''))[-3:-2]

if verif_checksum(f"{key} {val}", checksum):
# creation du champ pour la trame en cours avec cast des valeurs de mesure en "integer"
trame[key] = int(val) if key in INT_MESURE_KEYS else val

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()
Expand All @@ -115,12 +131,11 @@ def main():

trame = dict() # on repart sur une nouvelle trame
except Exception as e:
logging.error("Exception : %s" % e)
logging.error("Exception : %s" % e, exc_info=True)
logging.error("%s %s" % (key, val))
line = ser.readline()


if __name__ == '__main__':
if connected:
main()


0 comments on commit 52f44df

Please sign in to comment.