Mercurial > code > home > repos > homeauto
changeset 1305:965397a2648a
rm old complicated usb bus checker and resetter that caught some error modes and reset the right parts of the usb tree
Ignore-this: 1003481c29f8bb01b3758bf6f6241d65
darcs-hash:78af0ceedceca9a96255b825a26003a75f6b5991
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sun, 21 Apr 2019 03:04:42 -0700 |
parents | b686b989cf61 |
children | 2ffffcc7d0a4 |
files | service/usbReset/index.html service/usbReset/usbReset.py |
diffstat | 2 files changed, 0 insertions(+), 405 deletions(-) [+] |
line wrap: on
line diff
--- a/service/usbReset/index.html Sun Apr 21 03:01:36 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" -"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <title>usbreset</title> - <style> - body { - font-family: helvetica; - font-size: 12px; - } - table { - border-collapse: collapse; - } - td, th { - border: 1px solid #ccc; - padding: 3px 15px; - } - tr:nth-child(even) { background: #f8f8f8; } - tr:nth-child(odd) { background: #eee; } - </style> - </head> - <body> - - <table> - <thead> - <tr> - <th>dev</th> - <th>usbId</th> - <th>name</th> - <th>usbName</th> - </tr> - </thead> - <tbody data-bind="foreach: devices"> - <tr> - <td> - <span data-bind="text: dev"/> - <button data-bind="click: reset">Reset</button> - </td> - <td data-bind="text: usbId"></td> - <td data-bind="text: name"></td> - <td data-bind="text: usbName"></td> - </tr> - </tbody> - </table> - <pre id="error"></pre> - <script src="//bigasterisk.com/lib/jquery-2.0.3.min.js"></script> - <script src="//bigasterisk.com/lib/knockout-2.3.0.js"></script> - <script type="text/javascript"> - // <![CDATA[ - $(function () { - var model = { - devices: ko.observable(), - }; - - ko.applyBindings(model); - - $("#error").ajaxSend(function () { - $(this).text(""); - }).ajaxError(function (ev, xhr, settings, error) { - $(this).text(xhr.responseText); - }); - - function reloadDevices() { - - $.getJSON("devices", function (ret) { - ret.devices.forEach(function (dev) { - dev.reset = function (row, ev) { - var target = $(ev.target); - target.text("..."); - $.ajax({ - type: "POST", - url: "devices/reset", - data: {dev: dev.dev}, - success: function () { - target.text("ok"); - // resetting hubs can renumber the deeper devices - reloadDevices(); - }, - error: function () { - target.text("failed"); - }, - }); - }; - }); - model.devices(ret.devices); - }); - } - reloadDevices(); - - }); -// ]]> -</script> - </body> -</html>
--- a/service/usbReset/usbReset.py Sun Apr 21 03:01:36 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -#!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()