annotate service/bluetooth/bluetoothService.py @ 4:be855a111619

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