Mercurial > code > home > repos > homeauto
view service/bluetooth/bluetoothService.py @ 2:3a119010b960
moved from proj/room
Ignore-this: bb65f6f4b41c2687c00eef9cdb8ff730
author | drewp@bigasterisk.com |
---|---|
date | Sun, 07 Aug 2011 20:15:10 -0700 |
parents | |
children | be855a111619 |
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 DeviceDiscoverer from twisted.internet import reactor, defer, task from rdflib.Graph import Graph from rdflib import Literal, Variable, Namespace 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/") 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 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) 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/" ) 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) class Poller(object): def __init__(self): self.lastDevs = set() # addresses self.lastNameForAddress = {} self.currentGraph = Graph() self.lastPollTime = 0 def poll(self): log.debug("get devices") devs = d.nearbyDevices() devs.addCallback(self.compare) devs.addErrback(log.error) return devs def compare(self, newDevs): 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"}) 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) class Index(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): age = time.time() - self.settings.poller.lastPollTime if age > 60 + 30: raise ValueError("poll data is stale. age=%s" % age) self.write("bluetooth watcher. ") if __name__ == '__main__': log.setLevel(logging.DEBUG) poller = Poller() reactor.listenTCP(9077, cyclone.web.Application([ (r'/', Index), ], poller=poller)) task.LoopingCall(poller.poll).start(1) reactor.run()