annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
1 #!/usr/bin/python
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
2
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
3 """
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
4 watch for bluetooth devices
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
5
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
6 this discoverer finds me if my treo has its screen on only, so I
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
7 have to wake up my own treo for a few seconds.
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
8
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
9 I can use 'hcitool cc <addr> && hcitool rssi <addr>' to wake it up and
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
10 get its signal strength, but that pattern crashes my treo easily. I
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
11 still don't have an access that wakes up the treo and then doesn't
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
12 crash it. Maybe I could pretend to be a headset or something.
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
13
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
14 depends on ubuntu package: python-bluez
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
15
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
16 """
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
17 from __future__ import absolute_import
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
18 import logging, time, datetime, restkit, jsonlib, cyclone.web, sys
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
19 from bluetooth import discover_devices, lookup_name
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
20 from twisted.internet import reactor, task
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
21 from twisted.internet.threads import deferToThread
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
22 from rdflib.Graph import Graph
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
23 from rdflib import Literal, Namespace, RDFS, URIRef
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
24 from pymongo import Connection
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
25 from dateutil import tz
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
26
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
27 sys.path.append("/my/proj/homeauto/lib")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
28 from cycloneerr import PrettyErrorHandler
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
29 from logsetup import log
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
30
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
31 mongo = Connection('bang', 27017)['visitor']['visitor']
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
32
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
33 ROOM = Namespace("http://projects.bigasterisk.com/room/")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
34
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
35 def getNearbyDevices():
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
36 addrs = discover_devices()
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
37
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
38 # this can be done during discover_devices, but my plan was to
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
39 # cache it more in here
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
40 names = dict((a, lookup_name(a)) for a in addrs)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
41 log.debug("discover found %r %r", addrs, names)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
42 return addrs, names
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
43
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
44 hub = restkit.Resource(
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
45 # PSHB not working yet; "http://bang:9030/"
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
46 "http://slash:9049/"
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
47 )
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
48
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
49 def mongoInsert(msg):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
50 try:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
51 js = jsonlib.dumps(msg)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
52 except UnicodeDecodeError:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
53 pass
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
54 else:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
55 if msg['name'] != 'THINKPAD_T43':
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
56 hub.post("visitorNet", payload=js) # sans datetime
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
57 msg['created'] = datetime.datetime.now(tz.gettz('UTC'))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
58 mongo.insert(msg, safe=True)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
59
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
60 def deviceUri(addr):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
61 return URIRef("http://bigasterisk.com/bluetooth/%s" % addr)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
62
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
63 class Poller(object):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
64 def __init__(self):
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
65 self.lastAddrs = set() # addresses
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
66 self.currentGraph = Graph()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
67 self.lastPollTime = 0
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
68
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
69 def poll(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
70 log.debug("get devices")
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
71 devs = deferToThread(getNearbyDevices)
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
72
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
73 devs.addCallback(self.compare)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
74 devs.addErrback(log.error)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
75 return devs
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
76
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
77 def compare(self, (addrs, names)):
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
78 self.lastPollTime = time.time()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
79
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
80 newGraph = Graph()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
81 addrs = set(addrs)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
82 for addr in addrs.difference(self.lastAddrs):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
83 self.recordAction('arrive', addr, names)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
84 for addr in self.lastAddrs.difference(addrs):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
85 self.recordAction('leave', addr, names)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
86 for addr in addrs:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
87 uri = deviceUri(addr)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
88 newGraph.add((ROOM['bluetooth'], ROOM['senses'], uri))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
89 if addr in names:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
90 newGraph.add((uri, RDFS.label, Literal(names[addr])))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
91 self.lastAddrs = addrs
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
92 self.currentGraph = newGraph
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
93
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
94 def recordAction(self, action, addr, names):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
95 doc = {"sensor" : "bluetooth",
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
96 "address" : addr,
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
97 "action" : action}
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
98 if addr in names:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
99 doc["name"] = names[addr]
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
100 log.info("action: %s", doc)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
101 mongoInsert(doc)
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
102
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
103 class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
104 def get(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
105 age = time.time() - self.settings.poller.lastPollTime
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
106 if age > self.settings.config['period'] + 30:
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
107 raise ValueError("poll data is stale. age=%s" % age)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
108
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
109 self.write("bluetooth watcher. ")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
110
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
111 if __name__ == '__main__':
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
112 config = {
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
113 "period" : 60,
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
114 }
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
115 log.setLevel(logging.INFO)
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
116 poller = Poller()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
117 reactor.listenTCP(9077, cyclone.web.Application([
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
118 (r'/', Index),
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
119 # graph, json, table, ...
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
120 ], poller=poller, config=config))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents: 807
diff changeset
121 task.LoopingCall(poller.poll).start(config['period'])
807
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
122 reactor.run()