source: powerbar/npm2000.py@ 386

Last change on this file since 386 was 360, checked in by Rick van der Zwet, 13 years ago

Allow port cycle for hard-reboot of UNIT.

  • Property svn:executable set to *
File size: 8.9 KB
Line 
1#!/usr/bin/env python
2# NPM 4000 powerbar managment script, to be used instead of the windows
3# application.
4#
5# XXX: Not all features are ported yet (like amp monitoring)
6# XXX: Some dirty poking around with hex representations and numeric representations of ports
7# XXX: Make proper classes for use
8# XXX: Documentation
9#
10# TODO: Make it work for the NPM2000 series, which are using a different codes to address individual ports.
11#
12#
13# Licence: BSD
14# Version: $Id: npm4000.py 750 2009-09-27 14:34:55Z rick $
15# Rick van der Zwet <info@rickvanderzwet.nl>
16
17import socket, time
18import getopt, sys
19
20MAX_BUFFER = 100
21# NPM4000
22#MAX_PORTS = 24
23# NPM2000
24MAX_PORTS = 8
25
26# Wait a little while to allow device to turn off
27CYCLE_WAIT = 1
28
29# XOR all the 8bit values to get a checksum
30def checksum(s):
31 crc = 0
32 for p in range(0, len(s),2):
33 crc ^= int(s[p:p+2], 16)
34 return "%02X" % crc
35
36inet_addr = '192.168.0.178'
37inet_port = 4001
38
39passwd = 0x12345678
40addr_code = 0xFFFF
41
42verbose = False
43
44cmd2code = { 'login' : (0x5507, 1),
45 'portOn' : (0xB204, 2),
46 'portOff' : (0xC204, 2),
47 'allPortsOff' : (0xC103, 6),
48 'allPortsOn' : (0xB104, 15),
49 'status' : (0xD103, 2),
50 'knownError' : (0xFFFF, 1),
51 }
52
53# Socket used troughout the code
54s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
55
56def getCode(type):
57 return(cmd2code[type][0])
58
59def getTimeout(type):
60 return(cmd2code[type][1])
61
62def dprint(msg):
63 if verbose:
64 print time.strftime('[%Y-%m-%d %H:%M:%S]'), msg
65
66def getPortNumber(name):
67 port_char = name[0]
68 port_number = int(name[1])
69 number = -1
70 if port_char == 'A':
71 number = port_number
72 elif port_char == 'B':
73 number = port_number + 8
74 elif port_char == 'C':
75 number = port_number + 16
76 else:
77 raise ValueError, "Port %s not defined" % name
78
79 return(number)
80
81def getPortName(number):
82 if MAX_PORTS == 8:
83 name = "%i" % number
84 else:
85 if number <= 8:
86 name = "%Ai" % number
87 elif number <= 16:
88 name = "B%i" % (number - 8)
89 elif number <= 24:
90 name = "C%i" % (number - 16)
91 else:
92 raise ValueError, "Port %i not defined" % number
93 return(name)
94
95def getPortHex(number):
96 return(int(getPortName(number),16))
97
98def generateCommand(type,arg=None):
99 if arg == None:
100 command = "%04X%04X" % (getCode(type), addr_code)
101 else:
102 command = "%04X%04X%02X" % (getCode(type), addr_code, arg)
103 command += checksum(command)
104 return (command)
105
106
107def sendCommand(type, arg=None):
108 cmd = generateCommand(type,arg)
109 timeout = getTimeout(type)
110 dprint('Send: ' + cmd + ' (%s)' % (type))
111 s.send(cmd)
112 s.settimeout(timeout)
113 try:
114 retval = s.recv(MAX_BUFFER)
115 dprint('Recv: ' + retval)
116 except socket.timeout:
117 retval = None
118 print 'Recv: ERR timeout (wrong command, bad connection)'
119 #XXX: XOR Checking for data correctness
120 return(retval)
121
122def doCommand(type, arg=None):
123 sendCommand('login', passwd)
124 retval = sendCommand(type, arg)
125 #XXX: Check if command returned succesfull D128FF
126 return(retval)
127
128
129def getPortState(port, raw_status):
130 """Port configuration is put into 24 bits, every port has one bit
131 representing the statewith a awkward order:
132 A8,A7,A6,A5,A4,A3,A2,A1,B8,..,B1,C8,..,C1"""
133 # Portion of retval we are interested in
134 ports_state = int(raw_status[8:14],16)
135 port_bit_location = -1
136 if port <= 8:
137 port_bit_location = (1 << 15 << port)
138 elif port <= 16:
139 port_bit_location = (1 << 7 << (port - 8))
140 elif port <= 24:
141 port_bit_location = (1 << (port - 16 - 1))
142
143 if port_bit_location & ports_state:
144 return True
145 else:
146 return False
147
148def getPortStatus(i):
149 raw_status = doCommand('status')
150 print "Port %02i [%s]:" % (i, getPortName(i)),
151 if getPortState(i,raw_status):
152 print "1"
153 else:
154 print "0"
155 return(retval)
156
157def getStatusAll():
158 raw_status= doCommand('status')
159 for i in range(1,MAX_PORTS+1):
160 print "Port %02i [%s]:" % (i, getPortName(i)),
161 if getPortState(i,raw_status):
162 print "1"
163 else:
164 print "0"
165
166def togglePort(port):
167 raw_status= doCommand('status')
168 if getPortState(port,raw_status):
169 doCommand('portOff',port)
170 else:
171 doCommand('portOn', port)
172
173def cyclePort(port):
174 raw_status= doCommand('status')
175 if getPortState(port,raw_status):
176 doCommand('portOff',port)
177 time.sleep(CYCLE_WAIT)
178 doCommand('portOn',port)
179 else:
180 doCommand('portOn', port)
181 time.sleep(CYCLE_WAIT)
182 doCommand('portOff',port)
183
184
185def runTest():
186 print "TEST: Start will all port Offline"
187 doCommand('allPortsOff')
188
189 print "TEST: All On and Off again, in mass execution"
190 doCommand('allPortsOn',0x01)
191 doCommand('allPortsOff')
192
193 print "TEST: Enable and disable ports one by one"
194 for i in range(1,MAX_PORTS+1):
195 print getPortName(i)
196 doCommand('portOn', getPortHex(i))
197 doCommand('portOff', getPortHex(i))
198
199 print "TEST: Send known error"
200 doCommand('knownError')
201
202
203def usage():
204 print """
205Usage %s arguments
206Version: $Id: npm4000.py 750 2009-09-27 14:34:55Z rick $
207
208Arguments:
209 [-h|--help] Reading right know
210 [-v|--verbose] Print extra communication output
211 --host= IP adress of FQDN hostname [%s]
212 --port= Port to connect to [%s]
213 --password= Password to use in hex notation [0x1234568]
214 --addresscode= Internal device number in hex notation [0xFFFF]
215 [-s|--status] Current port configuration
216 [-t <port>|--toggle=<port>] Toggle port(s)
217 [-o <port>|--on=<port>] Turn on port(s)
218 [-f <port>|--off=<port>] Turn off port(s)
219
220Note: <port> has different notations:
221 Numeric value of port 1,2,3,4,5,..
222 Actual value of port A1,..,A8,B1,..,B8,C1,..,C8
223 All ports all
224 """ % (sys.argv[0], inet_addr, inet_port)
225
226def main():
227 global verbose, addr_code, inet_addr, inet_port, passwd, s
228 try:
229 opts, args = getopt.getopt(sys.argv[1:],
230 "c:hf:s:t:o:v", ["cycle=", "help","verbose","host=", "port=", "password=", "addresscode=","toggle=","off=", "on=", "status="])
231 except getopt.GetoptError, err:
232 # print help information and exit:
233 print str(err) # will print something like "option -a not recognized"
234 usage()
235 sys.exit(2)
236
237 opt_port = None
238 opt_action = None
239 for o, a in opts:
240 if o in ("-v", "--verbose"):
241 verbose = True
242 elif o in ("-h", "--help"):
243 usage()
244 sys.exit()
245 elif o in ("--addresscode"):
246 addr_code = int(a,16)
247 elif o in ("--host"):
248 inet_addr = a
249 elif o in ("--password"):
250 passwd = int(a,16)
251 elif o in ("--port"):
252 inet_port = a
253 elif o in ("-s", "--status"):
254 opt_action = "status"
255 opt_port = a
256 elif o in ("-t","--toggle"):
257 opt_action = "toggle"
258 opt_port = a
259 elif o in ("-c","--cycle"):
260 opt_action = "cycle"
261 opt_port = a
262 elif o in ("-f","--off"):
263 opt_action = "off"
264 opt_port = a
265 elif o in ("-o","--on"):
266 opt_action = "on"
267 opt_port = a
268 else:
269 assert False, "unhandled option"
270
271 if (opt_port == None or opt_action == None):
272 usage()
273 sys.exit(2)
274
275 dprint ('action: ' + opt_action + ' port: ' + opt_port)
276
277 s.connect((inet_addr, inet_port))
278
279 # Status needs real integers, hack
280 if opt_action == "status":
281 if opt_port == "all":
282 getStatusAll()
283 else:
284 print "XXX: Implement"
285 sys.exit(0)
286
287 # Resolve port to proper number
288 if opt_port == "all":
289 None # Blank resolution, as it is done elsewhere
290 elif opt_port[0] in ("A","B","C"):
291 opt_port = int(opt_port,16)
292 dprint('Hexcode of port: %i' % opt_port)
293 else:
294 # Dirty hack to have conversion and checking at the same time
295 opt_port = getPortHex(int(opt_port))
296 dprint('Hexcode of port: %i' % opt_port)
297
298 if opt_action == "toggle":
299 if opt_port == "all":
300 for i in range(1,MAX_PORTS+1):
301 togglePort(getPortHex(i))
302 else:
303 togglePort(opt_port)
304 elif opt_action == "cycle":
305 if opt_port == "all":
306 for i in range(1,MAX_PORTS+1):
307 cyclePort(getPortHex(i))
308 else:
309 cyclePort(opt_port)
310 elif opt_action == "on":
311 if opt_port == "all":
312 doCommand("allPortsOn",0x01)
313 else:
314 doCommand("portOn", opt_port)
315 elif opt_action == "off":
316 if opt_port == "all":
317 doCommand("allPortsOff");
318 else:
319 doCommand("portOff", opt_port)
320
321
322if __name__ == "__main__":
323 main()
Note: See TracBrowser for help on using the repository browser.