demikl/python-teleinfo

Compatibilité avec TIC Standard, Linky

JBoisseau opened this issue · 5 comments

Bonjour,

le TIC standard de Linky n'a pas exactement le même formatage que le TIC historique:
https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_54E.pdf

dans les grandes lignes : séparateur n'est plus un espace mais un tab, certaines valeur sont horodatées, et le calcul du checksum est aussi légèrement différent, dû au séparateur.

j'ai du faire des modifications dans le parser pour le supporter. (modif non compatible avec le mode historique)

def get_frame(self):
    raw = self._get_raw_frame().strip(self.MARKER_END_LINE)
    frame = {}
    for line in raw.split(self.MARKER_END_LINE):
       els = line.split("\t")
       k = els[0]
       if len(els) == 3:
           v = els[1].strip()
       elif len(els) == 4:
           v = (els[1].strip(),els[2].strip())
       else:
           logger.error('TIC is badly formated for line:' + str(line))
           continue
       data = line[:-1]
       chksum = line[-1]
       computedchksum = self._checksum(data)
       if chksum == computedchksum:
            frame[k] = v
       else:
            logger.debug(str(line) + ':' + str(chksum) + ':' + str(computedchksum))
    if len(frame) != len(raw.split(self.MARKER_END_LINE)):
        logger.error("Discarded fields because of bad checksum")
    return frame

def _checksum(self, data):
    chksum = sum([ord(c) for c in data])
    chksum = (chksum & 63) + 32
    return chr(chksum)

il y a surement moyen de faire une fonction compatible avec les 2 modes, en passant juste un "standard = True or False" en argument

SI tu veux je peux le faire, mais je n'ai pas de linky en mode historique pour tester.

Bonjour.

J'ai un Linky en mode historique, je pourrais donc valider l'évolution de mon côté. Je te remercie d'avance pour ta contribution. En terme d'architecture, je verrais bien un type ou une classe qui porterait le dialecte (à la façon du module parseur CSV), dans lequel seraient spécifiés ces éléments qui changent : tabulation vs. espace, fonction de checksum, etc. . Et deux instances de ce dialecte préconfigurés : linky standard et linky historique. Ensuite on passe un instance en paramètre, avec rétrocompatibilité en étant de base sur le mode historique.

Ca te va ?

Bonjour,

Je pense que la fonction checksum peut rester comme je l'ai faite, pour couvrir les 2 modes.

Je verrais juste la fonction get_frame avec un argument : standardMode = False.

Et ensuite :
If standardMode:
els = line.split("\t")
data = line[:-1]
else:
els = line.split(" ")
data = line[:-2]

La suite serait identique aux 2 modes.

Qu'en penses tu ?

voici la fonction get_frame, compatible avec les 2 modes, je pense. Testé sur mon linky standard.

def get_frame(self,standardMode = False):
    raw = self._get_raw_frame().strip(self.MARKER_END_LINE)
    frame = {}
    lines = raw.split(self.MARKER_END_LINE)
    for line in lines:
       if standardMode:
           els = line.split("\t")
           data = line[:-1] #data should include last separator
       else:
           els = line.split(" ")
           data = line[:-2] #data should not include last separator

       k = els[0]
       if len(els) == 3:
           v = els[1].strip()
       elif len(els) == 4: #standardMode has some fields with date before the value.
           v = (els[1].strip(),els[2].strip())
       else:
           logger.error('TIC is badly formated for line:' + str(line))
           continue

       chksum = line[-1]
       computedchksum = self._checksum(data)
       if chksum == computedchksum:
            frame[k] = v
       else:
            logger.error('Discarded line because of bad checksum:' + str(line) + '| checksum:' + str(chksum) + ', vs:' + str(computedchksum))

    if len(frame) != len(lines):
        logger.error("Discarded fields because of bad checksum")
    return frame

et aussi le checksum générique

def _checksum(self, data):
    chksum = sum([ord(c) for c in data])
    chksum = (chksum & 63) + 32
    return chr(chksum)

par contre le code
#!/usr/bin/env python
from teleinfo import Parser
from teleinfo.hw_vendors import PITInfo
ti = Parser(PITInfo(baudrate=9600))
print ti.get_frame()

ne fonctionne pas.
TypeError: init() got an unexpected keyword argument 'baudrate'

j'ai dû modifier le baudrate dans le code directement.

Bonsoir.

Effectivement si la différence se limite à ces faibles différences, inutile de se compliquer. Ta proposition me convient.