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:
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:
Hier sehen wir jetzt die Obis-Kennzahlen und deren Werte. Die braucht man für das anlegen der items.
items.conf
Das Plugin liegt unter /plugins/dlms/__init__.py
plugin.conf:
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:
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]
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
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]"
plugin.conf:
Code:
[smartmeter] class_name = DLMS class_path = plugins.dlms serialport = "/dev/ttyUSB0" baudrate = auto cycle = 60
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__(self, smarthome, serialport, baudrate, cycle):
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.connect, cycle=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:
i = line[:-2].split("(")
j = i[1].split("*")
k = 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(self, item):
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 Exception, e:
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())
Kommentar