changeset 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
files iec1107.py
diffstat 1 files changed, 156 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iec1107.py	Wed Nov 20 10:16:37 2013 +1030
@@ -0,0 +1,156 @@
+#!/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 --