diff iec1107.py @ 1:99f25c8ab92f

Make class version actually work, remove procedure. Rename as it doesn't get continuous results, just one shot.
author Daniel O'Connor <darius@dons.net.au>
date Wed, 20 Nov 2013 12:46:59 +1030
parents fd8520d969c4
children 8f1a773a3cd5
line wrap: on
line diff
--- 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 ??