# HG changeset patch # User Daniel O'Connor # Date 1384913819 -37800 # Node ID 99f25c8ab92f3611bd2fd305392d9bfb6810a35c # Parent fd8520d969c403e9286c1afa6dcaf82b209e3ec5 Make class version actually work, remove procedure. Rename as it doesn't get continuous results, just one shot. diff -r fd8520d969c4 -r 99f25c8ab92f iec1107.py --- a/iec1107.py Wed Nov 20 10:16:37 2013 +1030 +++ b/iec1107.py Wed Nov 20 12:46:59 2013 +1030 @@ -14,63 +14,20 @@ 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): +class IEC1107Reading(object): + def __init__(self, port, force300bps = True): # Open port - self.s = serial.Serial(port, baudrate=300, bytesize=7, parity='E', stopbits=1) - self.s.timeout = 0.2 + s = serial.Serial(port, baudrate = 300, bytesize = 7, parity = 'E', stopbits = 1) + s.timeout = 2.5 # Send ident message - self.s.write('/?!\r\n') - self.s.flush() - rtn = self.s.readline() + s.write('/?!\r\n') + rtn = s.readline() + if len(rtn) == 0: + raise Error('No reply to probe') 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] @@ -79,8 +36,10 @@ else: self.restime = 0.02 - #self.baudid = rtn[4] - self.baudid = '0' + if force300bps: + self.baudid = '0' + else: + self.baudid = rtn[4] if self.baudid not in baudtable: raise Error('Invalid baud rate %c from "%s"' % (selfbaudid, rtn)) else: @@ -99,34 +58,58 @@ # 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() + s.write('\x060%c0\r\n' % (self.baudid)) time.sleep(self.restime) - self.s.setBaudrate(self.baud) + s.setBaudrate(self.baud) + + lines = [] + cksum = 0 - self.s.timeout = 1 + # Read STX + head = s.read(1) + if len(head) == 0: + raise Error('No reply to query') + if head != '\x02': + raise Error('Invalid reply header 0x%02x' % (ord(head))) + + # Read result lines + 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) - def getdata(self): - self.dat = '' - while len(self.dat) == 0: - data = self.s.read(1000) - self.dat += data + # Read trailer + 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 = 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 - + # Validate checksum + cksum ^= ord(fin[0]) + if cksum != ord(fin[1]): + raise Error('Checksum mismatch, expected 0x%02x, got 0x%02x' % (cksum, ord(fin[1]))) + self.reading = lines + del s + def main(): - d = IEC1107('/dev/cu.usbserial-AM01Z7UC') + if len(sys.argv) != 2: + print 'Bad usage' + print '\t%s portname' % (sys.argv[0]) + sys.exit(1) + + res = IEC1107Reading(sys.argv[1]) + print res.reading 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 ??