Mercurial > code > home > repos > homeauto
view service/bluetooth/bluetoothService.py @ 809:bebb8f7c5a3e
move a bunch of services into this tree, give them all web status pages
Ignore-this: a11e90f9d2cd9470565c743f54943c4b
darcs-hash:20110808073131-312f9-a7f420d66388cedae458276d672a27a9249f1e2f.gz
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Mon, 08 Aug 2011 00:31:31 -0700 |
parents | 4713bb87e34e |
children | f299b71f88f7 |
line wrap: on
line source
#!/usr/bin/python """ watch for bluetooth devices this discoverer finds me if my treo has its screen on only, so I have to wake up my own treo for a few seconds. I can use 'hcitool cc <addr> && hcitool rssi <addr>' to wake it up and get its signal strength, but that pattern crashes my treo easily. I still don't have an access that wakes up the treo and then doesn't crash it. Maybe I could pretend to be a headset or something. depends on ubuntu package: python-bluez """ from __future__ import absolute_import import logging, time, datetime, restkit, jsonlib, cyclone.web, sys 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, Namespace, RDFS, URIRef from pymongo import Connection from dateutil import tz sys.path.append("/my/proj/homeauto/lib") from cycloneerr import PrettyErrorHandler from logsetup import log mongo = Connection('bang', 27017)['visitor']['visitor'] ROOM = Namespace("http://projects.bigasterisk.com/room/") def getNearbyDevices(): addrs = discover_devices() # 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 hub = restkit.Resource( # PSHB not working yet; "http://bang:9030/" "http://slash:9049/" ) def mongoInsert(msg): try: js = jsonlib.dumps(msg) except UnicodeDecodeError: pass else: if msg['name'] != 'THINKPAD_T43': hub.post("visitorNet", payload=js) # sans datetime 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.lastAddrs = set() # addresses self.currentGraph = Graph() self.lastPollTime = 0 def poll(self): log.debug("get devices") devs = deferToThread(getNearbyDevices) devs.addCallback(self.compare) devs.addErrback(log.error) return devs def compare(self, (addrs, names)): self.lastPollTime = time.time() 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 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 > self.settings.config['period'] + 30: raise ValueError("poll data is stale. age=%s" % age) self.write("bluetooth watcher. ") if __name__ == '__main__': config = { "period" : 60, } log.setLevel(logging.INFO) poller = Poller() reactor.listenTCP(9077, cyclone.web.Application([ (r'/', Index), # graph, json, table, ... ], poller=poller, config=config)) task.LoopingCall(poller.poll).start(config['period']) reactor.run()