Mercurial > code > home > repos > homeauto
view service/usbReset/usbReset.py @ 121:e367cdd15a24
don't start webcam on bang for now
Ignore-this: aee803f7eb13fea271b42d3426e2275f
author | drewp@bigasterisk.com |
---|---|
date | Sun, 22 Sep 2013 00:34:07 -0700 |
parents | 855deb1509a5 |
children |
line wrap: on
line source
#!bin/python """ resets usb ports and restarts other services. Must run as root for the usb part. Other systems that might be able to do conditional tests and commands like this: https://github.com/azkaban/azkaban nagios run this as root to reset a whole usb device. Ported from http://marc.info/?l=linux-usb&m=121459435621262&w=2 how to learn what device to reset? lsusb or lsusb -t how to learn the ioctl number? cpp on this file: #include "/usr/include/linux/usbdevice_fs.h" #include "/usr/include/asm-generic/ioctl.h" USBDEVFS_RESET last line comes out like this: (((0U) << (((0 +8)+8)+14)) | ((('U')) << (0 +8)) | (((20)) << 0) | ((0) << ((0 +8)+8))) this is a py expression: (((0) << (((0 +8)+8)+14)) | ((ord('U')) << (0 +8)) | (((20)) << 0) | ((0) << ((0 +8)+8))) ---------------- also this other usb reset: http://davidjb.com/blog/2012/06/restartreset-usb-in-ubuntu-12-04-without-rebooting """ from __future__ import division import cyclone.web, json, traceback, os, sys, time, logging, re import os, fcntl, commands, socket, logging, time, xmlrpclib, subprocess from twisted.internet import reactor, task from twisted.internet.defer import inlineCallbacks, returnValue, Deferred from twisted.web.client import getPage sys.path.append("/my/proj/house/frontdoor") from loggingserial import LoggingSerial sys.path.append("/my/proj/homeauto/lib") from cycloneerr import PrettyErrorHandler from logsetup import log USBDEVFS_RESET = 21780 class Id(object): ftdi = "0403:6001" frontDoorHub0 = "8087:0024" # bus2 dev 2 frontDoorHub1 = "0451:2046" # bus2 dev 3 frontDoorHub2 = "1a40:0101" # bus2 dev 7 frontDoorHub3 = "0409:0058" # bus2 dev 62 frontDoorCam = "0ac8:307b" bedroomHub0 = "8087:0020" bedroomHub1 = "05e3:0608" bedroomHub2 = "058f:6254" bedroomHub3 = "0409:005a" bedroomCam = "046d:08aa" bedroomSba = "04d8:000a" bedroomArduino = "0403:6001" garageHub0 = "1d6b:0002" # bus2 dev1 garageHub1 = "05e3:0604" # bus2 dev4 garageArduino = "2341:0001" garagePowerSerial = "0557:2008" blueHub = "1a40:0101" hostname = socket.gethostname() @inlineCallbacks def getOk(url, timeout=1): """can we get a successful status from this url in a short time?""" log.debug("testing %s" % url) try: resp = yield getPage(url, timeout=timeout) except Exception, e: log.warn("getPage %s", e) returnValue(False) returnValue(True) def hubDevice(usbId="1a40:0101"): """ what's the /dev path to the device with this usb id """ for line in commands.getoutput("lsusb").splitlines(): if 'ID '+usbId in line: words = line.split() return "/dev/bus/usb/%s/%s" % (words[1], words[3].rstrip(':')) raise ValueError("no usb device found with id %r" % usbId) def haveDevice(usbId): try: log.debug("checking for %s", usbId) dev = hubDevice(usbId) # sometimes the dev will exist but fail to open open(dev, "r") return True except (ValueError, IOError): return False def resetDevice(dev): """ send USBDEVFS_RESET to the given /dev address """ d = Deferred() log.debug("resetting %s" % dev) f=os.open(dev, os.O_WRONLY) ret = fcntl.ioctl(f, USBDEVFS_RESET, 0) if ret != 0: raise ValueError("ioctl failed with %s" % ret) reactor.callLater(3, d.callback, None) return d def supervisorRestart(cmds, supervisor="http://localhost:9001"): serv = xmlrpclib.ServerProxy(supervisor) for c in cmds: log.info("restarting %s", c) try: serv.supervisor.stopProcessGroup(c) except xmlrpclib.ResponseError, e: log.warn("supervisor.stopProcessGroup error %r, ignoring", e) serv.supervisor.startProcess(c) def resetModules(modules): log.info("reloading modules: %s", modules) for m in modules: subprocess.call(['modprobe', '-r', m]) for m in modules: subprocess.check_call(['modprobe', m]) class Background(object): def __init__(self, config, period): self.config = config self.period = period self.lastPollTime = 0 def assertIsCurrent(self): """raise an error if the poll data is not fresh""" dt = time.time() - self.lastPollTime if dt > self.period * 2: raise ValueError("last poll time was too old: %.1f sec ago" % dt) @inlineCallbacks def step(self): now = time.time() try: if hostname == 'bang': if (not haveDevice(Id.bedroomCam) or not haveDevice(Id.bedroomArduino)): if haveDevice(Id.bedroomHub3): yield resetDevice(hubDevice(Id.bedroomHub3)) else: if haveDevice(Id.bedroomHub2): yield resetDevice(hubDevice(Id.bedroomHub2)) else: if haveDevice(Id.bedroomHub1): yield resetDevice(hubDevice(Id.bedroomHub1)) else: if haveDevice(Id.bedroomHub0): yield resetDevice(hubDevice(Id.bedroomHub0)) else: raise ValueError( "don't even have the first hub") resetModules(['gspca_zc3xx']) #supervisorRestart(['webcam_9053']) else: log.debug("usb devices look ok") elif hostname == 'slash': haveFrontHub0 = haveDevice(Id.frontDoorHub0) haveFrontHub1 = haveDevice(Id.frontDoorHub1) haveFrontHub2 = haveDevice(Id.frontDoorHub2) haveFrontHub3 = haveDevice(Id.frontDoorHub3) haveGarageHub0 = haveDevice(Id.garageHub0) haveGarageHub1 = haveDevice(Id.garageHub1) haveFrontDoorCam = haveDevice(Id.frontDoorCam) haveV4lDevice = os.path.exists( "/dev/v4l/by-id/usb-Vimicro_Corp._PC_Camera-video-index0") haveFrontArduinoServe = (yield getOk('http://slash:9080/')) haveFrontWebcamImage = (yield getOk( "http://slash:9023/frontDoor", timeout=10)) log.info(str(vars())) if not haveDevice(Id.ftdi): if haveFrontHub3: yield resetDevice(hubDevice(Id.frontDoorHub3)) else: if haveFrontHub2: yield resetDevice(hubDevice(Id.frontDoorHub2)) else: if haveFrontHub1: yield resetDevice(hubDevice(Id.frontDoorHub1)) else: if haveFrontHub0: yield resetDevice(hubDevice(Id.frontDoorHub0)) else: raise ValueError("don't have the first hub") else: log.debug("front door chain looks ok") if not haveDevice(Id.garagePowerSerial): if haveGarageHub1: yield resetDevice(hubDevice(Id.garageHub1)) else: if haveGarageHub0: yield resetDevice(hubDevice(Id.garageHub0)) else: raise ValueError("don't have the first hub") else: log.debug("garage chain looks ok") if not haveDevice(Id.garageArduino): if haveGarageHub1: yield resetDevice(hubDevice(Id.garageHub1)) else: raise ValueError("don't even have the first hub") resetModules(['gspca_zc3xx']) supervisorRestart(['frontDoorArduino_9080']) else: if not haveFrontArduinoServe: yield resetDevice(hubDevice(Id.frontDoorHub3)) supervisorRestart(['frontDoorArduino_9080']) time.sleep(10) else: log.debug("frontDoorArduino looks ok") if not haveFrontWebcamImage: supervisorRestart(['webcam_frontDoor_9023']) else: log.debug("front webcam looks ok") elif hostname == 'dash': if not os.path.exists("/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900gbcG-if00-port0"): yield resetDevice(hubDevice("/dev/bus/usb/003/001")) else: raise NotImplementedError log.debug(" -- finished") self.lastPollTime = now except Exception, e: print "poll error", e traceback.print_exc() class Index(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): self.settings.background.assertIsCurrent() self.set_header("Content-Type", "application/xhtml+xml") self.write(open("index.html").read()) class Devices(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): out = [] for line in commands.getoutput("lsusb").splitlines(): words = line.split(None, 6) for name, usbId in Id.__dict__.items(): if usbId == words[5]: break else: name = "?" out.append(dict(dev="/dev/bus/usb/%s/%s" % (words[1], words[3].rstrip(':')), name=name, usbId=words[5], usbName=words[6] if len(words) > 6 else "")) self.set_header("Content-Type", "application/json") self.write(json.dumps({'devices':out})) class Reset(PrettyErrorHandler, cyclone.web.RequestHandler): @inlineCallbacks def post(self): dev = self.get_argument('dev') assert re.match("^[a-z0-9/]+$", dev), dev yield resetDevice(dev) self.set_header("Content-Type", "text/plain") self.write("ok") if __name__ == '__main__': config = { # to be read from a file 'servePort' : 9100, 'checkPeriod' : 30, } from twisted.python import log as twlog #twlog.startLogging(sys.stdout) log.setLevel(logging.DEBUG) p = Background(config, config['checkPeriod']) task.LoopingCall(p.step).start(config['checkPeriod']) reactor.listenTCP(config['servePort'], cyclone.web.Application([ (r"/", Index), (r"/devices", Devices), (r"/devices/reset", Reset), ], background=p, static_path="static")) reactor.run()