changeset 80:855deb1509a5

updated device tree. web ui for resetting things Ignore-this: 7a2fe227320ca328cc46ef1f30b77c15
author drewp@bigasterisk.com
date Wed, 29 May 2013 00:43:51 -0700
parents a2df988e2087
children ef639d892e77
files service/usbReset/index.html service/usbReset/usbReset.py
diffstat 2 files changed, 151 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/usbReset/index.html	Wed May 29 00:43:51 2013 -0700
@@ -0,0 +1,95 @@
+<?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="static/jquery-1.8.3.min.js"></script>
+    <script src="static/knockout-2.2.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>
\ No newline at end of file
--- a/service/usbReset/usbReset.py	Wed May 29 00:43:33 2013 -0700
+++ b/service/usbReset/usbReset.py	Wed May 29 00:43:51 2013 -0700
@@ -25,16 +25,21 @@
 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
+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
+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        
@@ -105,12 +110,14 @@
     """
     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)
-    time.sleep(3)
+    reactor.callLater(3, d.callback, None)
+    return d
 
 def supervisorRestart(cmds, supervisor="http://localhost:9001"):
     serv = xmlrpclib.ServerProxy(supervisor)
@@ -150,16 +157,16 @@
                 if (not haveDevice(Id.bedroomCam) or
                     not haveDevice(Id.bedroomArduino)):
                     if haveDevice(Id.bedroomHub3):
-                        resetDevice(hubDevice(Id.bedroomHub3))
+                        yield resetDevice(hubDevice(Id.bedroomHub3))
                     else:
                         if haveDevice(Id.bedroomHub2):
-                            resetDevice(hubDevice(Id.bedroomHub2))
+                            yield resetDevice(hubDevice(Id.bedroomHub2))
                         else:
                             if haveDevice(Id.bedroomHub1):
-                                resetDevice(hubDevice(Id.bedroomHub1))
+                                yield resetDevice(hubDevice(Id.bedroomHub1))
                             else:
                                 if haveDevice(Id.bedroomHub0):
-                                    resetDevice(hubDevice(Id.bedroomHub0))
+                                    yield resetDevice(hubDevice(Id.bedroomHub0))
                                 else:
                                     raise ValueError(
                                         "don't even have the first hub")
@@ -186,16 +193,16 @@
 
                 if not haveDevice(Id.ftdi):
                     if haveFrontHub3:
-                        resetDevice(hubDevice(Id.frontDoorHub3))
+                        yield resetDevice(hubDevice(Id.frontDoorHub3))
                     else:
                         if haveFrontHub2:
-                            resetDevice(hubDevice(Id.frontDoorHub2))
+                            yield resetDevice(hubDevice(Id.frontDoorHub2))
                         else:
                             if haveFrontHub1:
-                                resetDevice(hubDevice(Id.frontDoorHub1))
+                                yield resetDevice(hubDevice(Id.frontDoorHub1))
                             else:
                                 if haveFrontHub0:
-                                    resetDevice(hubDevice(Id.frontDoorHub0))
+                                    yield resetDevice(hubDevice(Id.frontDoorHub0))
                                 else:
                                     raise ValueError("don't have the first hub")
                 else:
@@ -203,10 +210,10 @@
 
                 if not haveDevice(Id.garagePowerSerial):
                     if haveGarageHub1:
-                        resetDevice(hubDevice(Id.garageHub1))
+                        yield resetDevice(hubDevice(Id.garageHub1))
                     else:
                         if haveGarageHub0:
-                            resetDevice(hubDevice(Id.garageHub0))
+                            yield resetDevice(hubDevice(Id.garageHub0))
                         else:
                             raise ValueError("don't have the first hub")
                 else:
@@ -214,14 +221,14 @@
                     
                 if not haveDevice(Id.garageArduino):
                     if haveGarageHub1:
-                        resetDevice(hubDevice(Id.garageHub1))
+                        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:
-                        resetDevice(hubDevice(Id.frontDoorHub3))
+                        yield resetDevice(hubDevice(Id.frontDoorHub3))
                         supervisorRestart(['frontDoorArduino_9080'])
                         time.sleep(10)
                     else:
@@ -234,7 +241,7 @@
 
             elif hostname == 'dash':
                 if not os.path.exists("/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900gbcG-if00-port0"):
-                    resetDevice(hubDevice("/dev/bus/usb/003/001"))
+                    yield resetDevice(hubDevice("/dev/bus/usb/003/001"))
 
             else:
                 raise NotImplementedError
@@ -251,7 +258,35 @@
         self.settings.background.assertIsCurrent()
         
         self.set_header("Content-Type", "application/xhtml+xml")
-        self.write("usbreset is ok")#open("index.html").read())
+        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
@@ -262,12 +297,14 @@
     from twisted.python import log as twlog
     #twlog.startLogging(sys.stdout)
 
-    log.setLevel(logging.INFO)
+    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),
-        ], background=p))
+        (r"/devices", Devices),
+        (r"/devices/reset", Reset),
+        ], background=p, static_path="static"))
     reactor.run()