Mercurial > ~darius > hgwebdir.cgi > iec1107
view iec1107.py @ 0:fd8520d969c4
Initial commit, only readmeter function works
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Wed, 20 Nov 2013 10:16:37 +1030 |
parents | |
children | 99f25c8ab92f |
line wrap: on
line source
#!/usr/bin/env python # # http://www.domoticaforum.eu/viewtopic.php?f=71&t=7489 # import exceptions import serial import sys import time baudtable = {'0' : 300, '1' : 600, '2' : 1200, '3' : 2400, '4' : 4800, '5' : 9600, '6' : 19200} class Error(exceptions.BaseException): pass def readmeter(portname): s = serial.Serial(portname, baudrate = 300, bytesize = 7, parity = 'E', stopbits = 1) s.timeout = 1.5 # Send ident message s.write('/?!\r\n') rtn = s.readline() if len(rtn) < 6 or rtn[0] != '/' or rtn[-1] != '\n' or rtn[-2] != '\r': raise Error('Invalid line "%s"' % (rtn)) # ACK meter and ask for data s.write('\x06000\x0d\x0a') s.timeout = 2 lines = [] cksum = 0 line = s.readline() if len(line) == 0 or line[0] != '\x02': raise Error('No reply to query or invalid reply \"%s\"' % (line)) else: cksum ^= reduce(lambda x, y: x ^ y, map(ord, line[1:])) lines.append(line[1:].strip()) while True: line = s.readline() cksum ^= reduce(lambda x, y: x ^ y, map(ord, line)) line = line.strip() if len(line) == 0: raise Error('Timeout during message') if line == '!': break lines.append(line) fin = s.read(2) if len(fin) != 2: raise Error('Timeout reading trailer') if fin[0] != '\x03': raise Error('Trailer malformed, expected 0x03, got 0x%02x' % (ord(fin[0]))) cksum ^= ord(fin[0]) if cksum != ord(fin[1]): raise Error('Checksum mismatch, expected 0x%02x, got 0x%02x' % (cksum, ord(fin[1]))) return lines class IEC1107(object): def __init__(self, port): # Open port self.s = serial.Serial(port, baudrate=300, bytesize=7, parity='E', stopbits=1) self.s.timeout = 0.2 # Send ident message self.s.write('/?!\r\n') self.s.flush() rtn = self.s.readline() if len(rtn) < 6 or rtn[0] != '/' or rtn[-1] != '\n' or rtn[-2] != '\r': raise Error('Invalid line "%s"' % (rtn)) rtn = rtn.strip() self.mfg = rtn[1:4] if self.mfg[2].isupper(): self.restime = 0.2 else: self.restime = 0.02 #self.baudid = rtn[4] self.baudid = '0' if self.baudid not in baudtable: raise Error('Invalid baud rate %c from "%s"' % (selfbaudid, rtn)) else: self.baud = baudtable[self.baudid] if rtn[5] == '/': self.mode = rtn[6] self.mfg = rtn[7:] else: self.mode = None self.mfg = rtn[5:] # Send ACK/option message # Byte Meaning # 0 ACK (0x06) # 1 Protocol character ('0' = normal, '1' = secondary, '2' = HDLC protocol) # 2 Baud rate ID ('0', '1', etc) # 3 Mode control('0' = read data, '1' = device prog) self.s.write('\x060%c0\x0d\x0a' % (self.baudid)) self.s.flush() time.sleep(self.restime) self.s.setBaudrate(self.baud) self.s.timeout = 1 def getdata(self): self.dat = '' while len(self.dat) == 0: data = self.s.read(1000) self.dat += data cksum = reduce(lambda x, y: x ^ y, map(ord,self.dat[1:-1])) if cksum != ord(self.dat[-1]): raise Error('checksum mismatch, epected 0x%02x got 0x%02x' % (cksum, ord(self.dat[-1]))) return self.dat def main(): d = IEC1107('/dev/cu.usbserial-AM01Z7UC') if __name__ == '__main__': main() s = '\x02C.1(12880041.0(22:25 18-11-13)\r\n1.8.1(0000000597*Wh)\r\n1.8.2(0000000000*Wh)\r\n1.8.3(0000264238*Wh)\r\n1.8.0(0000264835*Wh)\r\n2.8.0(0000511354*Wh)\r\n!\r\n\x03{' # Meter number is 1288004 # 1.8.0 is import # 1.8.1 is ?? # 1.8.2 is ?? # 1.8.3 is ?? # 2.8.0 is export # C.1(12880041.0(22:25 18-11-13) # 1.8.1(0000000597*Wh) # 1.8.2(0000000000*Wh) # 1.8.3(0000264238*Wh) # 1.8.0(0000264835*Wh) # 2.8.0(0000511354*Wh) # ==> /?!<0D><0A> # <== /ACE5SMLCD # ==> <06>050<0D><0A> # <== -- STX -- # <== C.1(12880041.0(22:48 18-11-13) # <== 1.8.1(0000000597*Wh) # <== 1.8.2(0000000000*Wh) # <== 1.8.3(0000264460*Wh) # <== 1.8.0(0000265057*Wh) # <== 2.8.0(0000511354*Wh) # <== ! # <== -- ETX -- # <== -- BCC --