Mercurial > code > home > repos > homeauto
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 |
rev | line source |
---|---|
807 | 1 #!/usr/bin/python |
2 | |
3 """ | |
4 watch for bluetooth devices | |
5 | |
6 this discoverer finds me if my treo has its screen on only, so I | |
7 have to wake up my own treo for a few seconds. | |
8 | |
9 I can use 'hcitool cc <addr> && hcitool rssi <addr>' to wake it up and | |
10 get its signal strength, but that pattern crashes my treo easily. I | |
11 still don't have an access that wakes up the treo and then doesn't | |
12 crash it. Maybe I could pretend to be a headset or something. | |
13 | |
14 depends on ubuntu package: python-bluez | |
15 | |
16 """ | |
17 from __future__ import absolute_import | |
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 | 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 | 24 from pymongo import Connection |
25 from dateutil import tz | |
26 | |
27 sys.path.append("/my/proj/homeauto/lib") | |
28 from cycloneerr import PrettyErrorHandler | |
29 from logsetup import log | |
30 | |
31 mongo = Connection('bang', 27017)['visitor']['visitor'] | |
32 | |
33 ROOM = Namespace("http://projects.bigasterisk.com/room/") | |
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 | 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 | 43 |
44 hub = restkit.Resource( | |
45 # PSHB not working yet; "http://bang:9030/" | |
46 "http://slash:9049/" | |
47 ) | |
48 | |
49 def mongoInsert(msg): | |
50 try: | |
51 js = jsonlib.dumps(msg) | |
52 except UnicodeDecodeError: | |
53 pass | |
54 else: | |
55 if msg['name'] != 'THINKPAD_T43': | |
56 hub.post("visitorNet", payload=js) # sans datetime | |
57 msg['created'] = datetime.datetime.now(tz.gettz('UTC')) | |
58 mongo.insert(msg, safe=True) | |
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 | 63 class Poller(object): |
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 | 66 self.currentGraph = Graph() |
67 self.lastPollTime = 0 | |
68 | |
69 def poll(self): | |
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 | 72 |
73 devs.addCallback(self.compare) | |
74 devs.addErrback(log.error) | |
75 return devs | |
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 | 78 self.lastPollTime = time.time() |
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 | 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 | 102 |
103 class Index(PrettyErrorHandler, cyclone.web.RequestHandler): | |
104 def get(self): | |
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 | 107 raise ValueError("poll data is stale. age=%s" % age) |
108 | |
109 self.write("bluetooth watcher. ") | |
110 | |
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 | 116 poller = Poller() |
117 reactor.listenTCP(9077, cyclone.web.Application([ | |
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 | 122 reactor.run() |