comparison 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
comparison
equal deleted inserted replaced
0:fd8520d969c4 1:99f25c8ab92f
12 baudtable = {'0' : 300, '1' : 600, '2' : 1200, '3' : 2400, '4' : 4800, '5' : 9600, '6' : 19200} 12 baudtable = {'0' : 300, '1' : 600, '2' : 1200, '3' : 2400, '4' : 4800, '5' : 9600, '6' : 19200}
13 13
14 class Error(exceptions.BaseException): 14 class Error(exceptions.BaseException):
15 pass 15 pass
16 16
17 def readmeter(portname): 17 class IEC1107Reading(object):
18 s = serial.Serial(portname, baudrate = 300, bytesize = 7, parity = 'E', stopbits = 1) 18 def __init__(self, port, force300bps = True):
19 s.timeout = 1.5
20
21 # Send ident message
22 s.write('/?!\r\n')
23
24 rtn = s.readline()
25 if len(rtn) < 6 or rtn[0] != '/' or rtn[-1] != '\n' or rtn[-2] != '\r':
26 raise Error('Invalid line "%s"' % (rtn))
27
28 # ACK meter and ask for data
29 s.write('\x06000\x0d\x0a')
30 s.timeout = 2
31
32 lines = []
33 cksum = 0
34
35 line = s.readline()
36 if len(line) == 0 or line[0] != '\x02':
37 raise Error('No reply to query or invalid reply \"%s\"' % (line))
38 else:
39 cksum ^= reduce(lambda x, y: x ^ y, map(ord, line[1:]))
40 lines.append(line[1:].strip())
41 while True:
42 line = s.readline()
43 cksum ^= reduce(lambda x, y: x ^ y, map(ord, line))
44 line = line.strip()
45 if len(line) == 0:
46 raise Error('Timeout during message')
47 if line == '!':
48 break
49 lines.append(line)
50 fin = s.read(2)
51 if len(fin) != 2:
52 raise Error('Timeout reading trailer')
53 if fin[0] != '\x03':
54 raise Error('Trailer malformed, expected 0x03, got 0x%02x' % (ord(fin[0])))
55
56 cksum ^= ord(fin[0])
57 if cksum != ord(fin[1]):
58 raise Error('Checksum mismatch, expected 0x%02x, got 0x%02x' % (cksum, ord(fin[1])))
59 return lines
60
61
62 class IEC1107(object):
63 def __init__(self, port):
64 # Open port 19 # Open port
65 self.s = serial.Serial(port, baudrate=300, bytesize=7, parity='E', stopbits=1) 20 s = serial.Serial(port, baudrate = 300, bytesize = 7, parity = 'E', stopbits = 1)
66 self.s.timeout = 0.2 21 s.timeout = 2.5
67 22
68 # Send ident message 23 # Send ident message
69 self.s.write('/?!\r\n') 24 s.write('/?!\r\n')
70 self.s.flush() 25 rtn = s.readline()
71 rtn = self.s.readline() 26 if len(rtn) == 0:
27 raise Error('No reply to probe')
72 if len(rtn) < 6 or rtn[0] != '/' or rtn[-1] != '\n' or rtn[-2] != '\r': 28 if len(rtn) < 6 or rtn[0] != '/' or rtn[-1] != '\n' or rtn[-2] != '\r':
73 raise Error('Invalid line "%s"' % (rtn)) 29 raise Error('Invalid line "%s"' % (rtn))
30
74 rtn = rtn.strip() 31 rtn = rtn.strip()
75 self.mfg = rtn[1:4] 32 self.mfg = rtn[1:4]
76 33
77 if self.mfg[2].isupper(): 34 if self.mfg[2].isupper():
78 self.restime = 0.2 35 self.restime = 0.2
79 else: 36 else:
80 self.restime = 0.02 37 self.restime = 0.02
81 38
82 #self.baudid = rtn[4] 39 if force300bps:
83 self.baudid = '0' 40 self.baudid = '0'
41 else:
42 self.baudid = rtn[4]
84 if self.baudid not in baudtable: 43 if self.baudid not in baudtable:
85 raise Error('Invalid baud rate %c from "%s"' % (selfbaudid, rtn)) 44 raise Error('Invalid baud rate %c from "%s"' % (selfbaudid, rtn))
86 else: 45 else:
87 self.baud = baudtable[self.baudid] 46 self.baud = baudtable[self.baudid]
88 47
97 # Byte Meaning 56 # Byte Meaning
98 # 0 ACK (0x06) 57 # 0 ACK (0x06)
99 # 1 Protocol character ('0' = normal, '1' = secondary, '2' = HDLC protocol) 58 # 1 Protocol character ('0' = normal, '1' = secondary, '2' = HDLC protocol)
100 # 2 Baud rate ID ('0', '1', etc) 59 # 2 Baud rate ID ('0', '1', etc)
101 # 3 Mode control('0' = read data, '1' = device prog) 60 # 3 Mode control('0' = read data, '1' = device prog)
102 self.s.write('\x060%c0\x0d\x0a' % (self.baudid)) 61 s.write('\x060%c0\r\n' % (self.baudid))
103 self.s.flush()
104 62
105 time.sleep(self.restime) 63 time.sleep(self.restime)
106 self.s.setBaudrate(self.baud) 64 s.setBaudrate(self.baud)
107 65
108 self.s.timeout = 1 66 lines = []
67 cksum = 0
109 68
110 def getdata(self): 69 # Read STX
111 self.dat = '' 70 head = s.read(1)
112 while len(self.dat) == 0: 71 if len(head) == 0:
113 data = self.s.read(1000) 72 raise Error('No reply to query')
114 self.dat += data 73 if head != '\x02':
74 raise Error('Invalid reply header 0x%02x' % (ord(head)))
75
76 # Read result lines
77 while True:
78 line = s.readline()
79 cksum ^= reduce(lambda x, y: x ^ y, map(ord, line))
80 line = line.strip()
81 if len(line) == 0:
82 raise Error('Timeout during message')
83 if line == '!':
84 break
85 lines.append(line)
115 86
116 cksum = reduce(lambda x, y: x ^ y, map(ord,self.dat[1:-1])) 87 # Read trailer
117 if cksum != ord(self.dat[-1]): 88 fin = s.read(2)
118 raise Error('checksum mismatch, epected 0x%02x got 0x%02x' % (cksum, ord(self.dat[-1]))) 89 if len(fin) != 2:
119 return self.dat 90 raise Error('Timeout reading trailer')
120 91 if fin[0] != '\x03':
92 raise Error('Trailer malformed, expected 0x03, got 0x%02x' % (ord(fin[0])))
93
94 # Validate checksum
95 cksum ^= ord(fin[0])
96 if cksum != ord(fin[1]):
97 raise Error('Checksum mismatch, expected 0x%02x, got 0x%02x' % (cksum, ord(fin[1])))
98 self.reading = lines
99 del s
100
121 def main(): 101 def main():
122 d = IEC1107('/dev/cu.usbserial-AM01Z7UC') 102 if len(sys.argv) != 2:
103 print 'Bad usage'
104 print '\t%s portname' % (sys.argv[0])
105 sys.exit(1)
106
107 res = IEC1107Reading(sys.argv[1])
108 print res.reading
123 109
124 if __name__ == '__main__': 110 if __name__ == '__main__':
125 main() 111 main()
126
127 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{'
128
129 112
130 # Meter number is 1288004 113 # Meter number is 1288004
131 # 1.8.0 is import 114 # 1.8.0 is import
132 # 1.8.1 is ?? 115 # 1.8.1 is ??
133 # 1.8.2 is ?? 116 # 1.8.2 is ??