changeset 509:c9cadfcb4fdc

rm old (2010) code for talking to arduino/firmata with a web ui and some activitystreams stuff Ignore-this: 3227955154a42eb5b67b49dd1f15890c
author drewp@bigasterisk.com
date Sun, 21 Apr 2019 23:26:45 -0700
parents 43bb3e69821d
children b1337ad3ec2d
files service/theaterArduino/index.html service/theaterArduino/theaterArduino.py service/theaterArduino/watchpins.html service/theaterArduino/watchpins.py
diffstat 4 files changed, 0 insertions(+), 649 deletions(-) [+]
line wrap: on
line diff
--- a/service/theaterArduino/index.html	Sun Apr 21 03:30:59 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +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></title>
-  </head>
-  <body>
-
-    <h1>pyduino web interface</h1>
-
-    <p>Use GET or PUT on the resources below. The value is a "0" or "1"
-    string. PUT "output" to /pin/d2/mode (etc) to make it writable.</p>
-
-    <div>
-      pin/d2 : <input type="checkbox" name="d2" value="set" id="d2"/> 
-      <span class="mode"> <input type="radio" name="d2-mode" value="input" id="d2-input"/> <label for="d2-input">input</label> 
-      <input type="radio" name="d2-mode" value="output" id="d2-output"/> <label for="d2-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d3 : <input type="checkbox" name="d3" value="set" id="d3"/> 
-      <span class="mode"> <input type="radio" name="d3-mode" value="input" id="d3-input"/> <label for="d3-input">input</label> 
-      <input type="radio" name="d3-mode" value="output" id="d3-output"/> <label for="d3-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d4 : <input type="checkbox" name="d4" value="set" id="d4"/> 
-      <span class="mode"> <input type="radio" name="d4-mode" value="input" id="d4-input"/> <label for="d4-input">input</label> 
-      <input type="radio" name="d4-mode" value="output" id="d4-output"/> <label for="d4-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d5 : <input type="checkbox" name="d5" value="set" id="d5"/> 
-      <span class="mode"> <input type="radio" name="d5-mode" value="input" id="d5-input"/> <label for="d5-input">input</label> 
-      <input type="radio" name="d5-mode" value="output" id="d5-output"/> <label for="d5-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d6 : <input type="checkbox" name="d6" value="set" id="d6"/> 
-      <span class="mode"> <input type="radio" name="d6-mode" value="input" id="d6-input"/> <label for="d6-input">input</label> 
-      <input type="radio" name="d6-mode" value="output" id="d6-output"/> <label for="d6-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d7 : <input type="checkbox" name="d7" value="set" id="d7"/> 
-      <span class="mode"> <input type="radio" name="d7-mode" value="input" id="d7-input"/> <label for="d7-input">input</label> 
-      <input type="radio" name="d7-mode" value="output" id="d7-output"/> <label for="d7-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d8 : <input type="checkbox" name="d8" value="set" id="d8"/> 
-      <span class="mode"> <input type="radio" name="d8-mode" value="input" id="d8-input"/> <label for="d8-input">input</label> 
-      <input type="radio" name="d8-mode" value="output" id="d8-output"/> <label for="d8-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d9 : <input type="checkbox" name="d9" value="set" id="d9"/> 
-      <span class="mode"> <input type="radio" name="d9-mode" value="input" id="d9-input"/> <label for="d9-input">input</label> 
-      <input type="radio" name="d9-mode" value="output" id="d9-output"/> <label for="d9-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d10 : <input type="checkbox" name="d10" value="set" id="d10"/> 
-      <span class="mode"> <input type="radio" name="d10-mode" value="input" id="d10-input"/> <label for="d10-input">input</label> 
-      <input type="radio" name="d10-mode" value="output" id="d10-output"/> <label for="d10-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d11 : <input type="checkbox" name="d11" value="set" id="d11"/> 
-      <span class="mode"> <input type="radio" name="d11-mode" value="input" id="d11-input"/> <label for="d11-input">input</label> 
-      <input type="radio" name="d11-mode" value="output" id="d11-output"/> <label for="d11-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d12 : <input type="checkbox" name="d12" value="set" id="d12"/> 
-      <span class="mode"> <input type="radio" name="d12-mode" value="input" id="d12-input"/> <label for="d12-input">input</label> 
-      <input type="radio" name="d12-mode" value="output" id="d12-output"/> <label for="d12-output">output</label> </span>
-    </div>
-
-    <div>
-      pin/d13 : <input type="checkbox" name="d13" value="set" id="d13"/> 
-      <span class="mode"> <input type="radio" name="d13-mode" value="input" id="d13-input"/> <label for="d13-input">input</label> 
-      <input type="radio" name="d13-mode" value="output" id="d13-output"/> <label for="d13-output">output</label> </span>
-    </div>
-
-    <div><button id="refresh">Refresh</button> <input type="checkbox" name="autoRefresh" id="autoRefresh"/> <label for="autoRefresh">Auto refresh</label></div>
-
-
-    <div id="ajaxError"/>
-
-    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
-    <script type="text/javascript">
-    // <![CDATA[
-    $(function() { 
-	$("#ajaxError").ajaxError(function (ev, xhr) {
-	    $(this).text("Error: " + xhr.responseText);
-	});
-
-	function refresh() {
-	    $(".mode input").css('opacity', .2);
-	    $("input[value=set]").css('opacity', .2)
-		.each(function (i, inp) {
-		    var id = $(inp).attr('name');
-		    $.ajax({
-			url: "pin/" + id,
-			type: "GET",
-			success: function (data, textStatus, xhr) {
-			    $(inp).css('opacity', 1).val(data == "1" ? ["set"] : []);
-			},
-		    });
-		    $.ajax({
-			url: "pin/" + id + "/mode",
-			type: "GET",
-			success: function (data, textStatus, xhr) {
-			    var match = $("#" + id + "-" + data);
-			    match.parent().find("input").css('opacity', 1);
-			    match.click();
-			}
-		    });
-		});
-	}
-
-	function refreshLoop() {
-  	    if ($("#autoRefresh").is(":checked")) {
-	        refresh();
-	        setTimeout(function() { refreshLoop(); }, 
-                  500); // refresh is async, so these could pile up
-	    }
-	}
-
-	$("#autoRefresh").click(refreshLoop);
-	$("#refresh").click(refresh);
-
-	$(".mode input").removeAttr('disabled').change(function () {
-	    var id = $(this).attr('id').replace(/-.*/, "");
-	    $.ajax({
-		type: "PUT",
-		contentType: "text/plain",
-		url: "pin/" + id + "/mode",
-		data: $(this).val(),
-	    });
-	});
-
-	$("input[value=set]").change(function () {
-	    var id = $(this).attr('id');
-	    $.ajax({
-		type: "PUT",
-		contentType: "text/plain",
-		url: "pin/"+id,
-		data: $("#"+id+":checked").val() ? "1" : "0",
-	    });
-	});
-	refresh();
-    });
-    // ]]>
-</script>
-
-  </body>
-</html>
--- a/service/theaterArduino/theaterArduino.py	Sun Apr 21 03:30:59 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-"""
-arduino example sketches, 'StandardFirmata'.
-
-####easy_install http://github.com/lupeke/python-firmata/tarball/master
-
-Now using http://code.google.com/p/pyduino, modified to run at 57600
-baud like my arduino's code does. pyduino is better than the lupeke
-one in that you can read your settings off the output pins
-
-Note that there are some startup delays and you may not hear about
-input changes for a few seconds.
-"""
-from __future__ import division
-import sys, cyclone.web, time, simplejson, os
-from twisted.web.client import getPage
-from twisted.internet import reactor, task
-
-sys.path.append("/my/proj/homeauto/lib")
-from cycloneerr import PrettyErrorHandler
-from logsetup import log
-
-sys.path.append("pyduino-read-only")
-import pyduino 
-
-def _num(name):
-    if name.startswith('d'):
-        return int(name[1:])
-    raise ValueError(name)
-                         
-class pin(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self, name):
-        self.set_header("Content-Type", "text/plain")
-        arduino = self.settings.arduino
-        arduino.iterate()
-        self.write(str(int(arduino.digital[_num(name)].read())))
-
-    def put(self, name):
-        t1 = time.time()
-        self.settings.arduino.digital[_num(name)].write(int(self.request.body))
-        log.debug("arduino write in %.1f ms" % (1000 * (time.time() - t1)))
-        
-
-class pinMode(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self, name):
-        self.set_header("Content-Type", "text/plain")
-        mode = self.settings.arduino.digital[_num(name)].get_mode()
-        self.write({pyduino.DIGITAL_INPUT : "input",
-                    pyduino.DIGITAL_OUTPUT : "output"}[mode])
-    
-    def put(self, name):
-        mode = {
-            "input" : pyduino.DIGITAL_INPUT,
-            "output" : pyduino.DIGITAL_OUTPUT}[self.request.body.strip()]
-        self.settings.arduino.digital[_num(name)].set_mode(mode)
-
-class Pid(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        self.set_header("Content-Type", "text/plain")
-        self.write(str(os.getpid()))
-
-class index(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        """
-        this is a suitable status check; it does a round-trip to arduino
-        """
-        # this would be a good ping() call for pyduino
-        self.settings.arduino.sp.write(chr(pyduino.REPORT_VERSION))
-        self.settings.arduino.iterate()
-        
-        self.set_header("Content-Type", "application/xhtml+xml")
-        self.write(open('index.html').read())
-    
-class Application(cyclone.web.Application):
-    def __init__(self, arduino):
-        handlers = [
-            (r"/", index),
-            (r'/pin/(.*)/mode', pinMode),
-            (r'/pin/(.*)', pin),
-            (r'/pid', Pid),
-            # web refresh could benefit a lot from a json resource that
-            # gives all the state
-        ]
-        settings = {"arduino" : arduino,}
-        cyclone.web.Application.__init__(self, handlers, **settings)
-
-class WatchPins(object):
-    def __init__(self, arduino, conf):
-        self.arduino, self.conf = arduino, conf
-        self.lastState = {}
-        self.pins = conf['watchPins']
-        if self.pins == 'allInput':
-            self.watchAllInputs()
-        for pin in self.pins:
-            arduino.digital_ports[pin >> 3].set_active(1)
-            arduino.digital[pin].set_mode(pyduino.DIGITAL_INPUT)
-
-    def watchAllInputs(self):
-        raise NotImplementedError("this needs to be updated whenever the modes change")
-        self.pins = [p for p in range(2, 13+1) if
-                     self.arduino.digital[p].get_mode() ==
-                     pyduino.DIGITAL_INPUT]
-
-    def reportPostError(self, fail, pin, value, url):
-        log.error("failed to send pin %s update (now %s) to %r: %r" % (pin, value, url, fail)) 
-        
-    def poll(self):
-        try:
-            self._poll()
-        except Exception, e:
-            log.error("during poll:", exc_info=1)
-
-    def _poll(self):
-        # this can IndexError for a port number being out of
-        # range. I'm not sure how- maybe error data coming in the
-        # port?
-        arduino.iterate()
-        for pin in self.pins:
-            current = arduino.digital[pin].read()
-            if current != self.lastState.get(pin, None):
-                d = getPage(
-                    self.conf['post'],
-                    method="POST",
-                    postdata=simplejson.dumps(dict(board=self.conf['boardName'], pin=pin, level=int(current))),
-                    headers={'Content-Type' : 'application/json'})
-                d.addErrback(self.reportPostError, pin, current, self.conf['post'])
-
-                self.lastState[pin] = current
-
-if __name__ == '__main__':
-
-    config = { # to be read from a file
-        'arduinoPort': '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900cepU-if00-port0',
-        'servePort' : 9056,
-        'pollFrequency' : 20,
-        'post' : 'http://bang:9069/pinChange',
-        'boardName' : 'theater', # gets sent with updates
-        'watchPins' : [9, 10], # or 'allInput' (not yet working)
-        # todo: need options to preset inputs/outputs at startup
-        }
-
-    arduino = pyduino.Arduino(config['arduinoPort'])
-    wp = WatchPins(arduino, config)
-    task.LoopingCall(wp.poll).start(1/config['pollFrequency'])
-    reactor.listenTCP(config['servePort'], Application(arduino))
-    reactor.run()
--- a/service/theaterArduino/watchpins.html	Sun Apr 21 03:30:59 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-<html>
-  <head>
-  </head>
-  <body>
-    theater motion sensor history:
-    <div id="chart_div" style="width: 900px; height: 250px;"></div>
-max age: <input type="range" name="maxAge" min="10" max="300" value="180">
-    <div id="status"></div>
-    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
-    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
-    <script type="text/javascript">
-      google.load("visualization", "1", {packages:["corechart"]});
-
-var latestData = null;
-var chart = null;
-
-      function loop() {
-          getNewPoints();
-          setTimeout(function () { webkitRequestAnimationFrame(loop); }, 1200);
-      }
-      google.setOnLoadCallback(function () {
-          chart = new google.visualization.LineChart(document.getElementById('chart_div'))
-          loop();
-      });
-
-      function getValue(subj, pred, trig) {
-          var groups = trig.match('<'+subj+'> <'+pred+'> "(.*?)"');
-          if (groups == null) {
-            return null;
-          }
-          return groups[1];
-      }
-
-      function getNewPoints() {
-          $("#status").text("get graph...");
-          $.ajax({
-              url: "graph",
-              success: function(data) {
-                  $("#status").text("");
-                  var pointsJson = getValue(
-                      "http://projects.bigasterisk.com/device/theaterDoorOutsideMotion",
-                      "http://projects.bigasterisk.com/room/history",
-                      data);
-                  var realPoints = [];
-                  if (pointsJson != null) {
-                    realPoints = JSON.parse(pointsJson);
-                  }
-                  var steppedPoints = new google.visualization.DataTable();
-                  steppedPoints.addColumn('number', 't');
-                  steppedPoints.addColumn('number', 'value');
-
-                  var prev = null;
-                  realPoints.forEach(function(r) {
-                      if (prev) {
-                          steppedPoints.addRows([[r[0], prev[1]]]);
-                      }
-                      steppedPoints.addRows([[r[0], r[1]]]);
-                      prev = r;
-                  });
-                  latestData = steppedPoints;
-                  redraw();
-              }
-          });
-      }
-      $("input[name=maxAge]").change(redraw);
-
-      function redraw() {
-          // https://developers.google.com/chart/interactive/docs/gallery/linechart#Configuration_Options
-          var options = {
-                      title: 'theaterDoorOutsideMotion',
-                      legend: {
-                          position: "none",
-                      },
-                      lineWidth: .5,
-                      hAxis: {
-                          title: "seconds ago",
-                          viewWindow: {
-                              min: -$("input[name=maxAge]").val(),
-                              max: 0
-                          },
-                          gridlines: { count: -1 }
-                      },
-                      vAxis: {
-                          baseline: -999,
-                          title: "motion sensed",
-                          viewWindow: {
-                              min: -.5,
-                              max: 1.5,
-                          }
-                      }
-                  };
-                  
-                  chart.draw(latestData, options);
-          }
-
-    </script>
-  </body>
-</html>
--- a/service/theaterArduino/watchpins.py	Sun Apr 21 03:30:59 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-"""
-listener to the POST messages sent by theaterArduino.py when a pin changes.
-records interesting events to mongodb, sends further messages.
-
-Will also serve activity stream.
-"""
-import sys, os, datetime, cyclone.web, simplejson, time
-from twisted.internet import reactor
-from twisted.internet.error import ConnectError
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twisted.web.client import getPage
-from dateutil.tz import tzutc
-from pymongo import Connection
-from rdflib import Namespace, Literal, Graph
-from rdflib.parser import StringInputSource
-sys.path.append("/my/site/magma")
-from activitystream import ActivityStream
-from stategraph import StateGraph
-     
-sys.path.append("/my/proj/homeauto/lib")
-from cycloneerr import PrettyErrorHandler
-from logsetup import log
-
-DEV = Namespace("http://projects.bigasterisk.com/device/")
-ROOM = Namespace("http://projects.bigasterisk.com/room/")
-zeroTime = datetime.datetime.fromtimestamp(0, tzutc())
-
-class PinChange(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def post(self):
-        # there should be per-pin debounce settings so we don't log
-        # all the noise of a transition change
-        
-        msg = simplejson.loads(self.request.body)
-        msg['t'] = datetime.datetime.now(tzutc())
-        msg['name'] = {9: 'downstairsDoorOpen', 
-                       10: 'downstairsDoorMotion',
-                       }[msg['pin']]
-        log.info("pinchange post %r", msg)
-        self.settings.mongo.insert(msg)
-
-        history = self.settings.history
-        if msg['pin'] == 10:
-            history['motionHistory'] = (history.get('motionHistory', []) + [(msg['t'], msg['level'])])[-50:]
-            if msg['level'] == 1:
-                if history.get('prevMotion', 0) == 0:
-                    history['motionStart'] = msg['t']
-
-            history['prevMotion'] = msg['level']
-                
-
-class InputChange(PrettyErrorHandler, cyclone.web.RequestHandler):
-    """
-    several other inputs post to here to get their events recorded,
-    too. This file shouldn't be in theaterArduino. See bedroomArduino,
-    frontDoorArduino, garageArduino.
-    """
-    def post(self):
-        msg = simplejson.loads(self.request.body)
-        msg['t'] = datetime.datetime.now(tzutc())
-        log.info(msg)
-        self.settings.mongo.insert(msg)
-
-        # trigger to entrancemusic? rdf graph change PSHB?
-
-class GraphHandler(PrettyErrorHandler, cyclone.web.RequestHandler):
-    """
-    fetch the pins from drv right now (so we don't have stale data),
-    and return an rdf graph describing what we know about the world
-    """
-    @inlineCallbacks
-    def get(self):
-        g = StateGraph(ctx=DEV['houseSensors'])
-
-        frontDoorDefer = getPage("http://slash:9080/door", timeout=2) # head start?
-
-        doorOpen = int((yield getPage("http://bang:9056/pin/d9", timeout=1)))
-        g.add((DEV['theaterDoorOpen'], ROOM['state'],
-               ROOM['open'] if doorOpen else ROOM['closed']))
-
-        for s in self.motionStatements(
-                currentMotion=int((yield getPage("http://bang:9056/pin/d10",
-                                                 timeout=1)))):
-            g.add(s)
-        
-        try:
-            for s in (yield self.getBedroomStatements()):
-                g.add(s)
-        except ConnectError, e:
-            g.add((ROOM['bedroomStatementFetch'], ROOM['error'],
-                   Literal("getBedroomStatements: %s" % e)))
-
-        try:
-            frontDoor = yield frontDoorDefer
-            g.add((DEV['frontDoorOpen'], ROOM['state'],
-               ROOM[frontDoor] if frontDoor in ['open', 'closed'] else
-               ROOM['error']))
-        except Exception, e:
-            g.add((DEV['frontDoorOpen'], ROOM['error'], Literal(str(e))))
-
-        self.set_header('Content-type', 'application/x-trig')
-        self.write(g.asTrig())
-
-    def motionStatements(self, currentMotion):
-        uri = DEV['theaterDoorOutsideMotion']
-
-        yield (uri, ROOM['state'], ROOM['motion'] if currentMotion else ROOM['noMotion'])
-
-        now = datetime.datetime.now(tzutc())
-        if currentMotion:
-            try:
-                dt = now - self.settings.history['motionStart']
-                yield (uri, ROOM['motionDurationSec'], Literal(dt.total_seconds()))
-                if dt > datetime.timedelta(seconds=4):
-                    yield (uri, ROOM['state'], ROOM['sustainedMotion'])
-            except KeyError:
-                pass
-
-        # this is history without the db, which means the window is
-        # limited and it could reset any time
-        if 'motionHistory' in self.settings.history:
-            yield ((uri, ROOM['history'],
-                   Literal(simplejson.dumps(
-                       [(round((t - now).total_seconds(), ndigits=2), v)
-                        for t,v in self.settings.history['motionHistory']]))))
-        
-    @inlineCallbacks
-    def getBedroomStatements(self):
-        trig = yield getPage("http://bang:9088/graph", timeout=1)
-        stmts = set()
-        for line in trig.splitlines():
-            if "http://projects.bigasterisk.com/device/bedroomMotion" in line:
-                g = Graph()
-                g.parse(StringInputSource(line+"\n"), format="nt")
-                for s in g:
-                    stmts.add(s)
-        returnValue(stmts)
-        
-class Activity(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        a = ActivityStream()
-        self.settings.mongo.ensure_index('t')
-        remaining = {'downstairsDoorMotion':10, 'downstairsDoorOpen':10,
-                     'frontDoorMotion':30, 'frontDoor':50, 'bedroomMotion': 10}
-        recent = {}
-        toAdd = []
-        for row in list(self.settings.mongo.find(sort=[('t', -1)],
-                                                     limit=10000)):
-            try:
-                r = remaining[row['name']]
-                if r < 1:
-                    continue
-                remaining[row['name']] = r - 1
-            except KeyError:
-                pass
-            
-            # lots todo
-            if row['name'] == 'downstairsDoorMotion':
-                if row['level'] == 0:
-                    continue
-                kw = dict(
-                    actorUri="http://...",
-                    actorName="downstairs door",
-                    verbUri="...",
-                    verbEnglish="sees",
-                    objectUri="...",
-                    objectName="backyard motion",
-                    objectIcon="/magma/static/backyardMotion.png")
-            elif row['name'] == 'downstairsDoorOpen':
-                kw = dict(actorUri="http://bigasterisk.com/foaf/someone",
-                       actorName="someone",
-                       verbUri="op",
-                       verbEnglish="opens" if row['level'] else "closes",
-                       objectUri="...",
-                       objectName="downstairs door",
-                       objectIcon="/magma/static/downstairsDoor.png")
-            elif row['name'] == 'frontDoor':
-                kw = dict(actorUri="http://bigasterisk.com/foaf/someone",
-                       actorName="someone",
-                       verbUri="op",
-                       verbEnglish="opens" if row['state']=='open' else "closes",
-                       objectUri="...",
-                       objectName="front door",
-                       objectIcon="/magma/static/frontDoor.png")
-            elif row['name'] == 'frontDoorMotion':
-                if row['state'] == False:
-                    continue
-                if 'frontDoorMotion' in recent:
-                    pass#if row['t'
-                kw = dict(
-                    actorUri="http://...",
-                    actorName="front door",
-                    verbUri="...",
-                    verbEnglish="sees",
-                    objectUri="...",
-                    objectName="front yard motion",
-                    objectIcon="/magma/static/frontYardMotion.png")
-                recent['frontDoorMotion'] = kw
-            elif row['name'] == 'bedroomMotion':
-                if not row['state']:
-                    continue
-                kw = dict(
-                    actorUri="http://...",
-                    actorName="bedroom",
-                    verbUri="...",
-                    verbEnglish="sees",
-                    objectUri="...",
-                    objectName="bedroom motion",
-                    objectIcon="/magma/static/bedroomMotion.png")
-                recent['bedroomMotion'] = kw
-            else:
-                raise NotImplementedError(row)
-                    
-            kw.update({'published' : row['t'],
-                       'entryUriComponents' : ('sensor', row['board'])})
-            toAdd.append(kw)
-
-        toAdd.reverse()
-        for kw in toAdd:
-            a.addEntry(**kw)
-            
-        self.set_header("Content-type", "application/atom+xml")
-        self.write(a.makeAtom())
-
-class Application(cyclone.web.Application):
-    def __init__(self):
-        handlers = [
-            (r'/()', cyclone.web.StaticFileHandler,
-             {"path" : ".", "default_filename" : "watchpins.html"}),
-            (r'/pinChange', PinChange),
-            (r'/inputChange', InputChange),
-            (r'/activity', Activity),
-            (r'/graph', GraphHandler),
-        ]
-        settings = {
-            'mongo' : Connection('bang', 27017,
-                                 tz_aware=True)['house']['sensor'],
-            'history' : {
-            },
-        }
-        cyclone.web.Application.__init__(self, handlers, **settings)
-
-if __name__ == '__main__':
-    #from twisted.python import log as twlog
-    #twlog.startLogging(sys.stdout)
-    reactor.listenTCP(9069, Application())
-    reactor.run()