[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