Mercurial > code > home > repos > homeauto
comparison service/usbReset/usbReset.py @ 846:5c6133c227d0
usb reset mess
Ignore-this: 66107d6e9c5740a91d11a6ece7efc433
darcs-hash:20120827055524-312f9-ffe0e119c519786ace0b3ff8765e9c2c7a7bdb81
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sun, 26 Aug 2012 22:55:24 -0700 |
parents | |
children | 022921fdafd0 |
comparison
equal
deleted
inserted
replaced
845:edd2486d6e2c | 846:5c6133c227d0 |
---|---|
1 #!bin/python | |
2 """ | |
3 resets usb ports and restarts other services. Must run as root for the usb part. | |
4 | |
5 Other systems that might be able to do conditional tests and commands like this: | |
6 https://github.com/azkaban/azkaban | |
7 nagios | |
8 | |
9 | |
10 | |
11 run this as root to reset a whole usb device. Ported from | |
12 http://marc.info/?l=linux-usb&m=121459435621262&w=2 | |
13 | |
14 how to learn what device to reset? lsusb or lsusb -t | |
15 | |
16 how to learn the ioctl number? cpp on this file: | |
17 | |
18 #include "/usr/include/linux/usbdevice_fs.h" | |
19 #include "/usr/include/asm-generic/ioctl.h" | |
20 USBDEVFS_RESET | |
21 | |
22 last line comes out like this: | |
23 (((0U) << (((0 +8)+8)+14)) | ((('U')) << (0 +8)) | (((20)) << 0) | ((0) << ((0 +8)+8))) | |
24 | |
25 this is a py expression: | |
26 (((0) << (((0 +8)+8)+14)) | ((ord('U')) << (0 +8)) | (((20)) << 0) | ((0) << ((0 +8)+8))) | |
27 | |
28 | |
29 """ | |
30 | |
31 from __future__ import division | |
32 | |
33 import cyclone.web, json, traceback, os, sys, time, logging | |
34 import os, fcntl, commands, socket, logging, time, xmlrpclib, subprocess | |
35 | |
36 from twisted.internet import reactor, task | |
37 from twisted.internet.defer import inlineCallbacks, returnValue | |
38 from twisted.web.client import getPage | |
39 sys.path.append("/my/proj/house/frontdoor") | |
40 from loggingserial import LoggingSerial | |
41 sys.path.append("/my/proj/homeauto/lib") | |
42 from cycloneerr import PrettyErrorHandler | |
43 from logsetup import log | |
44 | |
45 USBDEVFS_RESET = 21780 | |
46 | |
47 class Id(object): | |
48 ftdi = "0403:6001" | |
49 frontDoorHub0 = "8087:0024" # bus2 dev 2 | |
50 frontDoorHub1 = "0451:2046" # bus2 dev 3 | |
51 frontDoorHub2 = "1a40:0101" # bus2 dev 7 | |
52 frontDoorHub3 = "0409:0058" # bus2 dev 62 | |
53 frontDoorCam = "0ac8:307b" | |
54 | |
55 bedroomHub0 = "8087:0020" | |
56 bedroomHub1 = "05e3:0608" | |
57 bedroomHub2 = "058f:6254" | |
58 bedroomHub3 = "0409:005a" | |
59 bedroomCam = "046d:08aa" | |
60 bedroomSba = "04d8:000a" | |
61 bedroomArduino = "0403:6001" | |
62 | |
63 garageHub0 = "1d6b:0002" # bus2 dev1 | |
64 garageHub1 = "05e3:0604" # bus2 dev4 | |
65 garageArduino = "2341:0001" | |
66 garagePowerSerial = "0557:2008" | |
67 | |
68 blueHub = "1a40:0101" | |
69 | |
70 hostname = socket.gethostname() | |
71 | |
72 @inlineCallbacks | |
73 def getOk(url, timeout=1): | |
74 """can we get a successful status from this url in a short time?""" | |
75 log.debug("testing %s" % url) | |
76 try: | |
77 resp = yield getPage(url, timeout=timeout) | |
78 except Exception, e: | |
79 log.warn("getPage %s", e) | |
80 returnValue(False) | |
81 | |
82 returnValue(True) | |
83 | |
84 def hubDevice(usbId="1a40:0101"): | |
85 """ | |
86 what's the /dev path to the device with this usb id | |
87 """ | |
88 for line in commands.getoutput("lsusb").splitlines(): | |
89 if 'ID '+usbId in line: | |
90 words = line.split() | |
91 return "/dev/bus/usb/%s/%s" % (words[1], words[3].rstrip(':')) | |
92 raise ValueError("no usb device found with id %r" % usbId) | |
93 | |
94 def haveDevice(usbId): | |
95 try: | |
96 log.debug("checking for %s", usbId) | |
97 hubDevice(usbId) | |
98 return True | |
99 except ValueError: | |
100 return False | |
101 | |
102 def resetDevice(dev): | |
103 """ | |
104 send USBDEVFS_RESET to the given /dev address | |
105 """ | |
106 log.debug("resetting %s" % dev) | |
107 f=os.open(dev, os.O_WRONLY) | |
108 ret = fcntl.ioctl(f, USBDEVFS_RESET, 0) | |
109 if ret != 0: | |
110 raise ValueError("ioctl failed with %s" % ret) | |
111 time.sleep(3) | |
112 | |
113 def supervisorRestart(cmds, supervisor="http://localhost:9001"): | |
114 serv = xmlrpclib.ServerProxy(supervisor) | |
115 for c in cmds: | |
116 log.info("restarting %s", c) | |
117 try: | |
118 serv.supervisor.stopProcessGroup(c) | |
119 except xmlrpclib.ResponseError, e: | |
120 log.warn("supervisor.stopProcessGroup error %r, ignoring", e) | |
121 serv.supervisor.startProcess(c) | |
122 | |
123 def resetModules(modules): | |
124 log.info("reloading modules: %s", modules) | |
125 for m in modules: | |
126 subprocess.call(['modprobe', '-r', m]) | |
127 for m in modules: | |
128 subprocess.check_call(['modprobe', m]) | |
129 | |
130 | |
131 class Background(object): | |
132 def __init__(self, config, period): | |
133 self.config = config | |
134 self.period = period | |
135 self.lastPollTime = 0 | |
136 | |
137 def assertIsCurrent(self): | |
138 """raise an error if the poll data is not fresh""" | |
139 dt = time.time() - self.lastPollTime | |
140 if dt > self.period * 2: | |
141 raise ValueError("last poll time was too old: %.1f sec ago" % dt) | |
142 | |
143 @inlineCallbacks | |
144 def step(self): | |
145 now = time.time() | |
146 try: | |
147 if hostname == 'bang': | |
148 if (not haveDevice(Id.bedroomCam) or | |
149 not haveDevice(Id.bedroomArduino)): | |
150 if haveDevice(Id.bedroomHub3): | |
151 resetDevice(hubDevice(Id.bedroomHub3)) | |
152 else: | |
153 if haveDevice(Id.bedroomHub2): | |
154 resetDevice(hubDevice(Id.bedroomHub2)) | |
155 else: | |
156 if haveDevice(Id.bedroomHub1): | |
157 resetDevice(hubDevice(Id.bedroomHub1)) | |
158 else: | |
159 if haveDevice(Id.bedroomHub0): | |
160 resetDevice(hubDevice(Id.bedroomHub0)) | |
161 else: | |
162 raise ValueError( | |
163 "don't even have the first hub") | |
164 resetModules(['gspca_zc3xx']) | |
165 supervisorRestart(['webcam_9053']) | |
166 else: | |
167 log.debug("usb devices look ok") | |
168 | |
169 elif hostname == 'slash': | |
170 haveFrontHub0 = haveDevice(Id.frontDoorHub0) | |
171 haveFrontHub1 = haveDevice(Id.frontDoorHub1) | |
172 haveFrontHub2 = haveDevice(Id.frontDoorHub2) | |
173 haveFrontHub3 = haveDevice(Id.frontDoorHub3) | |
174 haveGarageHub0 = haveDevice(Id.garageHub0) | |
175 haveGarageHub1 = haveDevice(Id.garageHub1) | |
176 haveFrontDoorCam = haveDevice(Id.frontDoorCam) | |
177 haveV4lDevice = os.path.exists( | |
178 "/dev/v4l/by-id/usb-Vimicro_Corp._PC_Camera-video-index0") | |
179 haveFrontArduinoServe = (yield getOk('http://slash:9080/')) | |
180 haveFrontWebcamImage = (yield getOk( | |
181 "http://slash:9023/frontDoor", timeout=10)) | |
182 | |
183 log.info(str(vars())) | |
184 | |
185 if not haveDevice(Id.ftdi): | |
186 if haveFrontHub3: | |
187 resetDevice(Id.frontDoorHub3) | |
188 else: | |
189 if haveFrontHub2: | |
190 resetDevice(Id.frontDoorHub2) | |
191 else: | |
192 if haveFrontHub1: | |
193 resetDevice(Id.frontDoorHub1) | |
194 else: | |
195 if haveFrontHub0: | |
196 resetDevice(Id.frontDoorHub0) | |
197 else: | |
198 raise ValueError("don't have the first hub") | |
199 else: | |
200 log.debug("front door chain looks ok") | |
201 | |
202 if not haveDevice(Id.garagePowerSerial): | |
203 if haveGarageHub1: | |
204 resetDevice(Id.garageHub1) | |
205 else: | |
206 if haveGarageHub0: | |
207 resetDevice(Id.garageHub0) | |
208 else: | |
209 raise ValueError("don't have the first hub") | |
210 else: | |
211 log.debug("garage chain looks ok") | |
212 | |
213 if not haveDevice(Id.garageArduino): | |
214 if haveGarageHub1: | |
215 resetDevice(hubDevice(Id.garageHub1)) | |
216 else: | |
217 raise ValueError("don't even have the first hub") | |
218 resetModules(['gspca_zc3xx']) | |
219 supervisorRestart(['frontDoorArduino_9080']) | |
220 else: | |
221 if not haveFrontArduinoServe: | |
222 resetDevice(hubDevice(Id.frontDoorHub3)) | |
223 supervisorRestart(['frontDoorArduino_9080']) | |
224 time.sleep(10) | |
225 else: | |
226 log.debug("frontDoorArduino looks ok") | |
227 | |
228 if not haveFrontWebcamImage: | |
229 supervisorRestart(['webcam_frontDoor_9023']) | |
230 else: | |
231 log.debug("front webcam looks ok") | |
232 | |
233 elif hostname == 'dash': | |
234 if not os.path.exists("/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900gbcG-if00-port0"): | |
235 resetDevice("/dev/bus/usb/003/001") | |
236 | |
237 else: | |
238 raise NotImplementedError | |
239 | |
240 log.debug(" -- finished") | |
241 self.lastPollTime = now | |
242 | |
243 except Exception, e: | |
244 print "poll error", e | |
245 traceback.print_exc() | |
246 | |
247 class Index(PrettyErrorHandler, cyclone.web.RequestHandler): | |
248 def get(self): | |
249 self.settings.background.assertIsCurrent() | |
250 | |
251 self.set_header("Content-Type", "application/xhtml+xml") | |
252 self.write("usbreset is ok")#open("index.html").read()) | |
253 | |
254 if __name__ == '__main__': | |
255 config = { # to be read from a file | |
256 'servePort' : 9100, | |
257 'checkPeriod' : 30, | |
258 } | |
259 | |
260 from twisted.python import log as twlog | |
261 #twlog.startLogging(sys.stdout) | |
262 | |
263 log.setLevel(logging.INFO) | |
264 | |
265 p = Background(config, config['checkPeriod']) | |
266 task.LoopingCall(p.step).start(config['checkPeriod']) | |
267 | |
268 reactor.listenTCP(config['servePort'], cyclone.web.Application([ | |
269 (r"/", Index), | |
270 ], background=p)) | |
271 reactor.run() |