[vz-dev] iskra mt171
Ralf Löhmer
rl at loehmer.de
Sun Mar 2 15:45:20 CET 2014
Am 22.02.2014 02:18, schrieb Jakob Hirsch:
> On 09.02.2013 15:35, Jaco van Iterson wrote:
>> I added the code and some info to the
>> http://wiki.volkszaehler.org/hardware/channels/meters/power/edl-ehz/iskraemeco_mt171
> Looks nice, but it's not working on my MT171. First, I get no echo of
> the stuff I send. And it seems to ignore the speed setting in
> "<ACK>0x0\r\n", i.e. is stays at 300 bps for x=0..4, for x>4 there's no
> reply, even though it's given in the id output "/ISk5MT171-0222".
>
>
modified for use with python 3.3.2
it works for my mt171 now.
I have no echo with my MT171 and i marked where I found critical timing.
please try, no warranty.
rl
-------------- next part --------------
"""
angepasst python3.3.2
"""
from __future__ import print_function
import serial
import time
iskraID="/ISk5MT171-0222\r\n"
def send(port, bytes, tr):
""" sends an command to serial and reads and checks the echo
port - the open serial port
bytes - the string to be send
tr - the responce time
"""
port.write(bytearray(bytes,'ascii'))
time.sleep(tr)
def read_datablock():
ACK = '\x06'
STX = '\x02'
ETX = '\x03'
tr = 1
""" does all that's needed to get meter data from the meter device """
try:
IskraMT171=serial.Serial(port='COM4', baudrate=300, bytesize=7, parity='E', stopbits=1, timeout=3); # open port at specified speed
# 1 ->
time.sleep(tr)
Request_message='/?!\r\n' # IEC 62056-21:2002(E) 6.3.1
send(IskraMT171, Request_message, tr)
# 2 <-
ID_message=IskraMT171.readline()
ID_message=ID_message.decode()
if ID_message[0] != '/':
print("no Identification message")
IskraMT171.close()
return ""
if (len(ID_message) < len(iskraID)):
print("Identification message to short")
IskraMT171.close()
return ""
if ID_message[3].islower():
#tr = 0.02
tr = 0.2 #critical timing
manufacturers_ID = ID_message[1:4]
if (ID_message[5] == '\\'):
identification = ID_message[7:-2]
else:
identification = ID_message[5:-2]
speed = ID_message[4]
if (speed == "1"): new_baud_rate = 600
elif (speed == "2"): new_baud_rate = 1200
elif (speed == "3"): new_baud_rate = 2400
elif (speed == "4"): new_baud_rate = 4800
elif (speed == "5"): new_baud_rate = 9600
elif (speed == "6"): new_baud_rate = 19200
else:
new_baud_rate = 300
speed = "0"
#print(manufacturers_ID, " ", identification, " speed=", speed)
# 3 ->
Acknowledgement_message = ACK + '0' + speed + '0\r\n' # IEC 62056-21:2002(E) 6.3.3
time.sleep(tr)
send(IskraMT171, Acknowledgement_message, tr) #300 Bps
time.sleep(tr) #critical timing
IskraMT171.baudrate=new_baud_rate #9600Bps
# 4 <-
datablock = ""
inread = IskraMT171.read()
if ord(inread) == ord(STX):
x = IskraMT171.read().decode()
BCC = 0
while (x != '!'):
BCC = BCC ^ ord(x)
datablock = datablock + x
x = IskraMT171.read().decode()
while ord(x) != ord(ETX):
BCC = BCC ^ ord(x) # ETX itself is part of block check
x = IskraMT171.read().decode()
BCC = BCC ^ ord(x)
x = IskraMT171.read().decode() # x is now the Block Check Character
# last character is read, could close connection here
if (BCC != ord(x)): # received correctly?
datablock = ""
print("Result not OK, try again")
else:
print("No STX found, not handled.")
IskraMT171.close()
return datablock
except:
print("Some error reading data")
if (IskraMT171.isOpen()):
IskraMT171.close()
return ""
def meter_data(datablock, map, header):
""" takes a datablock as received from the meter and returns a list with requested meter data as set in map
if header != 0 a list with data type and units is returned """
line = []
## initialise line
for l in range(len(map)):
if (header == 1):
line.append(map[l][1])
elif (map[l][0] == "time"):
line.append(time.strftime("%d.%m.%Y %H:%M:%S"))
#print(line)
else:
line.append("")
datasets = datablock.split('\n')
for dataset in datasets:
if (dataset != ""):
x = dataset.split('(')
address = x[0]
x = x[1][:-2].split(' ') # the standard seems to have a '*' instead of ' ' here
value = x[0]
try:
unit = '['+x[1]+']'
except:
unit = ""
for l in range(len(map)):
if (map[l][0] == address):
if (header == 0):
line[l] = value
else:
line[l] = map[l][1] + unit
break;
return line
def output(filename, line):
f = open(filename, "a")
print(line, file=f)
f.close()
print(line)
map = [
# The structure of the meter_data() output can be set with this variable
# first string on each line is the cosim adress of the data you want to safe or "time" to insert the time
# the second string on each line is a description of the type of data belonging to the cosim address
# the order of the lines sets the order of the meter_data() output
# example
# header: ['meter ID', 'datum & tijd', 'verbruik totaal[kWh]', 'verbruik tarief1[kWh]', 'verbruik tarief2[kWh]', 'terug totaal[kWh]', 'terug tarief1[kWh]', 'terug tarief2[kWh]']
# data: ['12345678', '2013-02-08 10:08:41', '0054321', '0000000', '0054321', '0000000', '0000000', '0000000']
["1-0:0.0.0*255", "Meter ID"],
["time", "Datum & Zeit"],
["1-0:1.8.0*255", "Verbrauch"],
["1-0:1.8.1*255", ""],
["1-0:1.8.2*255", ""],
["1-0:2.8.0*255", "Einspeisung"],
["1-0:2.8.1*255", ""],
["1-0:2.8.2*255", ""]
]
example_datablock = """0-0:C.1.0*255(12345678)
1-0:0.0.0*255(12345678)
1-0:0.2.0*255(V1.0)
1-0:1.8.0*255(0054321 kWh)
1-0:1.8.1*255(0000000 kWh)
1-0:1.8.2*255(0054321 kWh)
1-0:2.8.0*255(0000000 kWh)
1-0:2.8.1*255(0000000 kWh)
1-0:2.8.2*255(0000000 kWh)
FF(00000000)
"""
#print(meter_data(example_datablock , map, 1))
#print(meter_data(example_datablock , map, 0))
file = "meterdata.txt"
previous_data = ""
data = read_datablock()
output(file, meter_data(data , map, 1)) # header
while (1):
if (data == ""):
print(time.strftime("%d.%m.%Y %H:%M:%S"), "No data received")
elif (previous_data != data):
output(file, meter_data(data , map, 0))
previous_data = data
time.sleep(5) # minimum waiting time is 3 seconds, less and the meter doesn't return data
data = read_datablock()
More information about the volkszaehler-dev
mailing list