Ankündigung

Einklappen
Keine Ankündigung bisher.

Smartmeter Plugin - Tester gesucht

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • JuMi2006
    antwortet
    Die serielle mag einfach keine Baudratenumstellung innerhalb der Kommunikation, das ist mir weder mit Python noch mit Perl gelungen ... tausend mal die man-pages gelesen und verstanden ... erst deswegen bin ich wieder beim socat gelandet. In der Kommunikation gibt es da ja keine riesigen Unterschiede zwischen perl und Python was die serielle angeht -> open/recv/close.

    Das Plugin stand hier such schon komplett auf serieller Ebene, aber ich hab einfach keine Lust 120! Sekunden auf einen Datensatz meines WP_Zählers zu warten weil der nur mit 300baud dröselt und aus 120 Zeilen genau eine gebraucht wird.

    Der socat ist schon nett für die serielle im LAN, ansonsten macht er das Leben auch nicht einfacher, das bisschen "\n" und ”\r” was man meist sucht findet man auch leichter/verständlicher.

    Grüße

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    Hallo Mirko,

    wenn Du mal wieder Zeit und Lust hast, kannst Du Dir ja mal das DMX-Plugin ansehen, dort wird auch über eine serielle Schnittstelle kommuniziert.
    Das ist ziemlich direkt und stabil.
    Ich verstehe auch nicht wieso das WG-Lager socat so verehrt.

    Bis bald

    Marcus

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Hallo Marcus,

    Danke nochmal für Deine Tips, haben mir gut geholfen das ganze zu verstehen.
    Die Doku für das Plugin mache ich noch fertig, ansonsten nervt mich hier gerade wieder das ganze serielle/socat Gefrickel mit den unzuverlässigen eHZ.

    Ich persönlich bleib da bei meinen meinen zwei perl/cronjob-scripten die seit über einem Jahr fehlerfrei laufen. Vielleicht will sich jemand anders ja dessen noch mal annehmen - ich kann/will da im Moment keine weitere Zeit versenken.

    Grüße

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    Hallo Mirko,

    +1

    Zitat von JuMi2006 Beitrag anzeigen
    Momentan fehlt mir noch die Idee wie ich bei mehreren Zählern/Ausleseköpfen die items der passenden Zähler-id zuordne und dass noch mit dem sheduler kombiniere.
    vllt. gefällt Dir die Lösung aus dem mpd-Plugin: https://github.com/mknx/smarthome/bl..._init__.py#L79

    Doku folgt noch...

    Bis bald

    Marcus

    Einen Kommentar schreiben:


  • JuMi2006
    hat ein Thema erstellt Smartmeter Plugin - Tester gesucht.

    Smartmeter Plugin - Tester gesucht

    Ich hab für DLMS/D0/IEC-62056 Zähler ein Plugin fertig gemacht.

    Das Plugin kann in der Kommandozeile aufgerufen werden und zeigt dann die verfügbaren Werte des Zählers an:

    Code:
    python /usr/local/smarthome/plugins/dlms/__init__.py [COLOR="SeaGreen"]/dev/ttyUSB0[/COLOR] [COLOR="Red"]auto[/COLOR]
    Mitzugeben sind die Parameter device und baudrate.
    Die Baudrate wird mit "auto" automatisch anhand der Zählerkennung ermittelt, kann aber auch mit "300" auf z.B. 300baud verbleiben.

    Ergebnis:
    Code:
    reading from device: /dev/ttyUSB0
    baudrate: auto
    /LGZ4ZMF100AC.M23
    [B]1.8.1[/B] 004442.544 kWh
    1.8.2 000000.000 kWh
    1.8.3 000000.000 kWh
    1.8.4 000000.000 kWh
    1.8.0 004442.544 kWh
    2.8.0 000000.000 kWh
    15.8.0 004442.544 kWh
    32.7 240 V
    52.7 240 V
    72.7 241 V
    [B]31.7[/B] 003.36 A
    51.7 001.11 A
    [B]71.7[/B] 001.85 A
    16.7 000.78 kW
    Reading takes: 4.73436403275
    Hier sehen wir jetzt die Obis-Kennzahlen und deren Werte. Die braucht man für das anlegen der items.

    items.conf
    Code:
    [zaehler]
        [[stand]]
            type = num
            dlms_code = "[B]1.8.1[/B]"
        [[strom_l1]]
            type = num
            dlms_code = "[B]31.7[/B]"
        [[strom_l3]]
            type = num
            dlms_code = "[B]71.7[/B]"
    Das Plugin liegt unter /plugins/dlms/__init__.py
    plugin.conf:
    Code:
    [smartmeter]
        class_name = DLMS
        class_path = plugins.dlms
        serialport = "/dev/ttyUSB0"
        baudrate = auto
        cycle = 60
    Hier also alle 60 Sekunden die Werte für Zählerstand absolut und Stromstärke L1 & L3.

    ToDo:
    - Unterstützung von mehreren Zählern/seriellen Ports im Plugin
    - Unterstützung von mehreren Zählern über einen IR-Auslesekopf

    Momentan fehlt mir noch die Idee wie ich bei mehreren Zählern/Ausleseköpfen die items der passenden Zähler-id zuordne und dass noch mit dem sheduler kombiniere.

    Grüße

    ../plugins/dlms/__init__.py:
    PHP-Code:
    #!/usr/local/bin/python

    import os
    import sys
    import logging
    import struct
    import time

    logger 
    logging.getLogger('')

    class 
    DLMS():
        
    def __init__(selfsmarthomeserialportbaudratecycle):
            
    self._sh smarthome
            self
    .port serialport
            self
    .obis = {}
            
    self.baud baudrate
            self
    .cycle int(cycle)
            
        
    def run(self):
            
    self.alive True 
            self
    ._sh.scheduler.add('DLMS'self.connectcycle=self.cycle)
            
    logger.debug("Cycle: {0}".format(self.cycle))
            global 
    from_shell
            from_shell 
    False
            self
    .connect()
            
        
    def stop(self): 
            
    self.alive False 
        
        def connect
    (self):
            
    logger.debug("DLMS: connect")
            
    request "\x2f\x3f\x21\x0d\x0a"
            
    cmd "echo '"+request+"' | socat -T 1 - "+self.port+",raw,echo=0,b300,parenb=1,parodd=0,cs7,cstopb=0"
            
    try:
                
    self.id os.popen(cmd).readline()
            
    except:
                if 
    from_shell:
                    print(
    "[connect] error main: {0}".format(e))
                else:
                    
    logger.warning("DLMS: {0}".format(e))
                
            if 
    len(self.id) > 0:
                if 
    from_shell:
                    print 
    self.id.strip()
                    
    self.ack(self.id)
                else:
                    
    self.ack(self.id)
            
        
    def ack(self,id):    
            
    speedrates = ['300','600','1200','2400','4800','9600']
            
    acks = ["\x06\x30\x30\x30\x0d\x0a","\x06\x30\x31\x30\x0d\x0a","\x06\x30\x32\x30\x0d\x0a","\x06\x30\x33\x30\x0d\x0a","\x06\x30\x34\x30\x0d\x0a","\x06\x30\x35\x30\x0d\x0a"]
            
    arr = [[0,"300","\x06\x30\x30\x30\x0d\x0a"],[1,"600","\x06\x30\x31\x30\x0d\x0a"],[2,"1200","\x06\x30\x32\x30\x0d\x0a"],[3,"2400","\x06\x30\x33\x30\x0d\x0a"],[4,"4800","\x06\x30\x34\x30\x0d\x0a"],[5,"9600","\x06\x30\x35\x30\x0d\x0a"]]
            
            if 
    self.baud == "auto":
                
    speed speedrates[int(self.id[4])]
                
    ack acks[int(self.id[4])]
            else:
                for 
    n in arr:
                    if 
    n[1] == self.baud:
                        
    speed n[1]
                        
    ack n[2]
            try:
                
    cmd "echo '"+ack+"' | socat -T 1 - "+self.port+",raw,echo=0,b300,parenb=1,parodd=0,cs7,cstopb=0; socat -T 1 - "+self.port+",raw,echo=0,b"+speed+",parenb=1,parodd=0,cs7,cstopb=0"
                
    lines os.popen(cmd).readlines()
            
    except:
                print(
    "[ack] error main: {0}".format(e))
            
    self.parse(lines)

        
    def parse(self,lines):
            for 
    line in lines[:-2]:
                if 
    "*" in line:
                    
    line[:-2].split("(")
                    
    i[1].split("*")
                    
    j[1].split(")")
                    
    c_obis i[0]
                    
    c_value float(j[0])
                    
    c_unit k[0]
                    if 
    not from_shell:
                        
    self.refresh(c_obis,c_value,c_unit)
                    else:
                        print 
    i[0] + " " j[0] + " " k[0]
        
        
    def refresh(self,c_obis,c_value,c_unit):
            for 
    codes in self.obis
                if 
    codes == c_obis
                    
    self.obis[codes](c_value,'DLMS''refresh')
                    
    #logger.debug("DLMS: Parameter/Refresh: {0}".format(codes)) 

        
    def parse_item(selfitem):
            if 
    'dlms_code' in item.conf:
                
    logger.debug("parse item: {0}".format(item))
                
    obis_code item.conf['dlms_code']
                
    self.obis[obis_code] = item
                logger
    .debug("DLMS: new set = item:{0} obis:{1}".format(item,obis_code))
                
    def main():
        try:
            
    start time.time()
            
    #serialport = '/dev/usbserial-alcdut1'
            #serialport = '/dev/usbserial-A600eZF1'
            
    if sys.argv[1]:
                
    serialport sys.argv[1]
                print (
    "reading from device: {0}".format(serialport))
            if 
    sys.argv[2]:
                
    baudrate sys.argv[2]
                print (
    "baudrate: {0}".format(baudrate))
            
    smarthome ''
            
    cycle 60
            
    global from_shell
            from_shell 
    True
            meter 
    DLMS(smarthome,serialport,baudrate,cycle)
            
    meter.connect()

            
    cycletime time.time() - start
            
    print ("Reading takes: {0}".format(cycletime))
            
        
    except Exceptione:
            print 
    "[main]: {0}".format(e)
            print 
    "usage: __init__.py <serial_port> <baudrate>"
            
    print "baudrate: auto,300,600,1200,2400,4800,9600"
            
    return 1

    if __name__ == "__main__":
        
    sys.exit(main()) 
Lädt...
X