# HG changeset patch
# User drewp phototransistor watching IR pulses on the power meter: last pulse was ; current power usage is watts (assuming kwh/blink) Recent raw IR sensor data: %(tb)s
" % {
+ "code": status_code,
+ "message": httplib.responses[status_code],
+ "tb" : cgi.escape(tb),
+ }
diff -r 867f59c83dba -r bebb8f7c5a3e service/bluetooth/bluetoothService.py
--- a/service/bluetooth/bluetoothService.py Sun Aug 07 21:50:21 2011 -0700
+++ b/service/bluetooth/bluetoothService.py Mon Aug 08 00:31:31 2011 -0700
@@ -16,10 +16,11 @@
"""
from __future__ import absolute_import
import logging, time, datetime, restkit, jsonlib, cyclone.web, sys
-from bluetooth import DeviceDiscoverer
-from twisted.internet import reactor, defer, task
+from bluetooth import discover_devices, lookup_name
+from twisted.internet import reactor, task
+from twisted.internet.threads import deferToThread
from rdflib.Graph import Graph
-from rdflib import Literal, Variable, Namespace
+from rdflib import Literal, Namespace, RDFS, URIRef
from pymongo import Connection
from dateutil import tz
@@ -31,61 +32,15 @@
ROOM = Namespace("http://projects.bigasterisk.com/room/")
-class Disco(DeviceDiscoverer):
- # it might be cool if this somehow returned
- # _bt.EVT_INQUIRY_RESULT_WITH_RSSI: results. see
- # /usr/share/pycentral/python-bluez/site-packages/bluetooth.py
- def device_discovered(self, address, device_class, name):
- log.debug("seeing: %s - %s (class 0x%X)" % (address, name, device_class))
- self.nearby.append((address, name))
-
- def inquiry_complete(self):
- pass
-
- def process_inquiry(self):
- # more async version of the normal method
- """
- Starts calling process_event, returning a deferred that fires
- when we're done.
- """
- self.done_inquiry = defer.Deferred()
-
- if self.is_inquiring or len(self.names_to_find) > 0:
- self.keep_processing()
- else:
- self.done_inquiry.callback(None)
-
- return self.done_inquiry
+def getNearbyDevices():
+ addrs = discover_devices()
- def keep_processing(self):
- # this one still blocks "a little bit"
- if self.is_inquiring or len(self.names_to_find) > 0:
- reactor.callLater(0, self.keep_processing)
- log.debug("process_event()")
- self.process_event() # <-- blocks here
- else:
- self.done_inquiry.callback(None)
+ # this can be done during discover_devices, but my plan was to
+ # cache it more in here
+ names = dict((a, lookup_name(a)) for a in addrs)
+ log.debug("discover found %r %r", addrs, names)
+ return addrs, names
- def nearbyDevices(self):
- """deferred to list of (addr,name) pairs"""
- self.nearby = []
- self.find_devices()
- d = self.process_inquiry()
- d.addCallback(lambda result: self.nearby)
- return d
-
-def devicesFromAddress(address):
- for row in graph.query(
- "SELECT ?dev { ?dev rm:bluetoothAddress ?addr }",
- initNs=dict(rm=ROOM),
- initBindings={Variable("?addr") : Literal(address)}):
- (dev,) = row
- yield dev
-
-graph = Graph()
-graph.parse("phones.n3", format="n3")
-
-d = Disco()
hub = restkit.Resource(
# PSHB not working yet; "http://bang:9030/"
"http://slash:9049/"
@@ -102,74 +57,66 @@
msg['created'] = datetime.datetime.now(tz.gettz('UTC'))
mongo.insert(msg, safe=True)
+def deviceUri(addr):
+ return URIRef("http://bigasterisk.com/bluetooth/%s" % addr)
+
class Poller(object):
def __init__(self):
- self.lastDevs = set() # addresses
- self.lastNameForAddress = {}
+ self.lastAddrs = set() # addresses
self.currentGraph = Graph()
self.lastPollTime = 0
def poll(self):
log.debug("get devices")
- devs = d.nearbyDevices()
+ devs = deferToThread(getNearbyDevices)
devs.addCallback(self.compare)
devs.addErrback(log.error)
return devs
- def compare(self, newDevs):
+ def compare(self, (addrs, names)):
self.lastPollTime = time.time()
- log.debug("got: %r", newDevs)
- lostDevs = self.lastDevs.copy()
- prevDevs = self.lastDevs.copy()
- self.lastDevs.clear()
- stmts = []
-
- for address, name in newDevs:
- stmts.append((ROOM['bluetooth'],
- ROOM['senses'],
- Literal(str(address))))
- if address not in prevDevs:
- matches = 0
- for dev in devicesFromAddress(address):
- log.info("found %s" % dev)
- matches += 1
- if not matches:
- log.info("no matches for %s (%s)" % (name, address))
- print "%s %s %s" % (time.time(), name, address)
-
- self.lastNameForAddress[address] = name
- print 'mongoInsert', ({"sensor" : "bluetooth",
- "address" : address,
- "name" : name,
- "action" : "arrive"})
+ newGraph = Graph()
+ addrs = set(addrs)
+ for addr in addrs.difference(self.lastAddrs):
+ self.recordAction('arrive', addr, names)
+ for addr in self.lastAddrs.difference(addrs):
+ self.recordAction('leave', addr, names)
+ for addr in addrs:
+ uri = deviceUri(addr)
+ newGraph.add((ROOM['bluetooth'], ROOM['senses'], uri))
+ if addr in names:
+ newGraph.add((uri, RDFS.label, Literal(names[addr])))
+ self.lastAddrs = addrs
+ self.currentGraph = newGraph
- lostDevs.discard(address)
- self.lastDevs.add(address)
-
- for address in lostDevs:
- print 'mongoInsert', ({"sensor" : "bluetooth",
- "address" : address,
- "name" : self.lastNameForAddress[address],
- "action" : "leave"})
-
- for dev in devicesFromAddress(address):
- log.info("lost %s" % dev)
+ def recordAction(self, action, addr, names):
+ doc = {"sensor" : "bluetooth",
+ "address" : addr,
+ "action" : action}
+ if addr in names:
+ doc["name"] = names[addr]
+ log.info("action: %s", doc)
+ mongoInsert(doc)
class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
def get(self):
age = time.time() - self.settings.poller.lastPollTime
- if age > 60 + 30:
+ if age > self.settings.config['period'] + 30:
raise ValueError("poll data is stale. age=%s" % age)
self.write("bluetooth watcher. ")
if __name__ == '__main__':
- log.setLevel(logging.DEBUG)
+ config = {
+ "period" : 60,
+ }
+ log.setLevel(logging.INFO)
poller = Poller()
reactor.listenTCP(9077, cyclone.web.Application([
(r'/', Index),
- ], poller=poller))
- task.LoopingCall(poller.poll).start(1)
+ # graph, json, table, ...
+ ], poller=poller, config=config))
+ task.LoopingCall(poller.poll).start(config['period'])
reactor.run()
diff -r 867f59c83dba -r bebb8f7c5a3e service/garageArduino/garageArduino.py
--- a/service/garageArduino/garageArduino.py Sun Aug 07 21:50:21 2011 -0700
+++ b/service/garageArduino/garageArduino.py Mon Aug 08 00:31:31 2011 -0700
@@ -93,8 +93,12 @@
"""
def get(self):
self.set_header("Content-Type", "application/javascript")
- self.settings.poller.assertIsCurrent()
- self.write(json.dumps({"irLevels" : [[t1, lev1], [t2,lev2], ]}))
+ pts = []
+ for i in range(60):
+ level = self.settings.arduino.lastLevel()
+ pts.append((round(time.time(), 3), level))
+
+ self.write(json.dumps({"irLevels" : pts}))
class HousePowerThreshold(PrettyErrorHandler, cyclone.web.RequestHandler):
"""
@@ -116,8 +120,8 @@
(r"/graph", GraphPage),
(r"/frontDoorMotion", FrontDoorMotion),
(r'/housePower', HousePower),
- (r'/housepower/raw', HousePowerRaw),
- (r'/housepower/threshold', HousePowerThreshold),
+ (r'/housePower/raw', HousePowerRaw),
+ (r'/housePower/threshold', HousePowerThreshold),
]
settings = {"arduino" : ard, "poller" : poller}
cyclone.web.Application.__init__(self, handlers, **settings)
diff -r 867f59c83dba -r bebb8f7c5a3e service/garageArduino/index.html
--- a/service/garageArduino/index.html Sun Aug 07 21:50:21 2011 -0700
+++ b/service/garageArduino/index.html Mon Aug 08 00:31:31 2011 -0700
@@ -12,7 +12,6 @@
}
/* ]]> */
-
@@ -24,9 +23,13 @@