-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathdeltaInv.py
executable file
·139 lines (124 loc) · 6.07 KB
/
deltaInv.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import crc,struct,sys
from crc import CRC16
from struct import *
class DeltaInverter:
inverterNum=0;
#Known Commands
##StrValue, Format, divisor, units
cmds = {'\x10\x01': ('DC Cur1',0,10.0,'A'),
'\x10\x02': ('DC Volts1',0,1,'V'),
'\x10\x03': ('DC Pwr1',0,1,'W'),
'\x10\x04': ('DC Cur2',0,10.0,'A'),
'\x10\x05': ('DC Volts2',0,1,'V'),
'\x10\x06': ('DC Pwr2',0,1,'W'),
'\x10\x07': ('AC Current',0,10.0,'A'),
'\x10\x08': ('AC Volts',0,1,'V'),
'\x10\x09': ('AC Power',0,1,'W'),
'\x11\x07': ('AC I Avg',0,10.0,'A'),
'\x11\x08': ('AC V Avg',0,1,'V'),
'\x11\x09': ('AC P Avg',0,1,'W'),
'\x13\x03': ('Day Wh',0,1,'Wh'),
'\x13\x04': ('Uptime',0,1,'min'),
'\x00\x00': ('Inverter Type',9,0,''),
'\x00\x01': ('Serial',1,0,''),
'\x00\x08': ('Part',1,0,''),
'\x00\x40': ('FW Version',10,0,''),
'\x20\x05': ('AC Temp',0,1,'o'),
'\x21\x08': ('DC Temp',0,1,'o')
};
#Constructor takes inverter number (incase you have more than 1)
def __init__(self,inverter=1):
self.inverterNum=inverter
self.crcCalc = CRC16()
#private to do the binary packing of the protocol
def __buildCmd(self, cmd):
l = len(cmd)
crc = self.crcCalc.calcString( struct.pack('BBB%ds'%l,5,self.inverterNum,l,cmd))
lo = crc & (0xff);
high = (crc>>8) & 0xff;
return struct.pack('BBBB%dsBBB' %len(cmd),2,5,self.inverterNum,len(cmd),cmd,lo,high,3);
#retrieves the instruction for the given human readable command
def __findCmd(self,strValue):
for k,v in self.cmds.iteritems():
if(v[0]==strValue):
return k
#unpacks the given command into an {Instruction} {Value} {Units} string
def __unpackFormatted(self,cmd):
if not self.isValidResponse(cmd):
return "Invalid Response"
cmdcontents = cmd[1:-3]
lendata = ord(cmdcontents[2])-2
try:
stringName,fmt,divisor,unit = self.cmds[cmdcontents[3:5]]
if fmt==0: ##General Numbers
resp,invNum,size,instruction,value = struct.unpack('>BBB2sH',cmdcontents)
value = value / divisor
elif fmt==1: ##ascii string
resp,invNum,size,instruction,value = struct.unpack('>BBB2s%ds' %lendata,cmdcontents)
elif fmt==9: ##Model
resp,invNum,size,instruction,typeof,model,value = struct.unpack('>BBB2sBB%ds' % (lendata-2),cmdcontents)
return self.cmds[instruction][0]+": Type:" + str(typeof) + " Model:" +value
elif fmt==10: ##FWVersion #
resp,invNum,size,instruction,ver,major,minor = struct.unpack('>BBB2sBBB',cmdcontents)
return self.cmds[instruction][0]+": " + str(ver) +"." + str(major)+ "."+ str(minor)
else:
resp,invNum,size,instruction,value = struct.unpack('>BBB2s%ds' % lendata,cmdcontents)
return self.cmds[instruction][0] + ": " + str(value) + " "+unit
except:
return "Error parsing string, perhaps unknown instruction"
#Returns the packed command to be sent over serail,
#Command includes STX, inverter number, CRC, ETX
def getCmdStringFor(self,cmd):
return self.__buildCmd(self.__findCmd(cmd))
#Returns a formatted human readble form of a response
def getFormattedResponse(self,cmd):
return self.__unpackFormatted(cmd)
#Returns a raw value from a response
def getValueFromResponse(self,cmd):
return self.__unpackData(cmd)
#prints out hex values of a command string and the related instruction
def debugRequestString(self,cmdString):
cmd = cmdString[4:6]
strCmd = self.cmds[cmd][0]
inverter = ord(cmdString[2])
print "%s on inverter %d:" % (strCmd,inverter)
for ch in cmdString:
sys.stdout.write("%02X " % ord(ch))
print ""
#checks for a valid STX, ETX and CRC
def isValidResponse(self,cmd):
if ord(cmd[1])<> 0x06 or ord(cmd[0])!=0x02 or ord(cmd[len(cmd)-1])!=0x03:
return False
cmdcontents = cmd[1:-3]
crc = self.crcCalc.calcString(cmdcontents)
lo = crc & (0xff)
high = (crc>>8) & 0xff
crcByte = len(cmd)-3
if ord(cmd[crcByte])!=lo or ord(cmd[crcByte+1])!=high:
return False
return True
#Returns a raw value from a response
def __unpackData(self,cmd):
if not self.isValidResponse(cmd):
return "Invalid Response"
cmdcontents = cmd[1:-3]
lendata = ord(cmdcontents[2])-2
try:
stringName,fmt,divisor,unit = self.cmds[cmdcontents[3:5]]
if fmt==0: ##General Numbers
resp,invNum,size,instruction,value = struct.unpack('>BBB2sH',cmdcontents)
value = value / divisor
elif fmt==1: ##ascii string
resp,invNum,size,instruction,value = struct.unpack('>BBB2s%ds' %lendata,cmdcontents)
# return self.cmds[instruction][0] + ": " + str(value) + " "+unit
elif fmt==9: ##Model
resp,invNum,size,instruction,typeof,model,value = struct.unpack('>BBB2sBB%ds' % (lendata-2),cmdcontents)
return ": Type:" + str(typeof) + " Model:" +value
elif fmt==10: ##FWVersion #
resp,invNum,size,instruction,ver,major,minor = struct.unpack('>BBB2sBBB',cmdcontents)
return str(ver) +"." + str(major)+ "."+ str(minor)
else:
resp,invNum,size,instruction,value = struct.unpack('>BBB2s%ds' % lendata,cmdcontents)
return str(value)
except:
return "Error parsing string, perhaps unknown instruction"