annotate service/bluetooth/bluetoothService.py @ 807:4713bb87e34e

moved from proj/room Ignore-this: bb65f6f4b41c2687c00eef9cdb8ff730 darcs-hash:20110808031510-312f9-a009d540c5a76ce231387581cb9e2d43efe4b3ae.gz
author drewp <drewp@bigasterisk.com>
date Sun, 07 Aug 2011 20:15:10 -0700
parents
children be855a111619
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
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
19 from bluetooth import DeviceDiscoverer
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
20 from twisted.internet import reactor, defer, task
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
21 from rdflib.Graph import Graph
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
22 from rdflib import Literal, Variable, Namespace
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
23 from pymongo import Connection
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
24 from dateutil import tz
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
25
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
26 sys.path.append("/my/proj/homeauto/lib")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
27 from cycloneerr import PrettyErrorHandler
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
28 from logsetup import log
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
29
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
30 mongo = Connection('bang', 27017)['visitor']['visitor']
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
31
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
32 ROOM = Namespace("http://projects.bigasterisk.com/room/")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
33
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
34 class Disco(DeviceDiscoverer):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
35 # it might be cool if this somehow returned
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
36 # _bt.EVT_INQUIRY_RESULT_WITH_RSSI: results. see
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
37 # /usr/share/pycentral/python-bluez/site-packages/bluetooth.py
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
38 def device_discovered(self, address, device_class, name):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
39 log.debug("seeing: %s - %s (class 0x%X)" % (address, name, device_class))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
40 self.nearby.append((address, name))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
41
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
42 def inquiry_complete(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
43 pass
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
44
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
45 def process_inquiry(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
46 # more async version of the normal method
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 Starts calling process_event, returning a deferred that fires
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
49 when we're done.
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
50 """
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
51 self.done_inquiry = defer.Deferred()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
52
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
53 if self.is_inquiring or len(self.names_to_find) > 0:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
54 self.keep_processing()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
55 else:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
56 self.done_inquiry.callback(None)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
57
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
58 return self.done_inquiry
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
59
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
60 def keep_processing(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
61 # this one still blocks "a little bit"
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
62 if self.is_inquiring or len(self.names_to_find) > 0:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
63 reactor.callLater(0, self.keep_processing)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
64 log.debug("process_event()")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
65 self.process_event() # <-- blocks here
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
66 else:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
67 self.done_inquiry.callback(None)
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 nearbyDevices(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
70 """deferred to list of (addr,name) pairs"""
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
71 self.nearby = []
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
72 self.find_devices()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
73 d = self.process_inquiry()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
74 d.addCallback(lambda result: self.nearby)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
75 return d
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
76
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
77 def devicesFromAddress(address):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
78 for row in graph.query(
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
79 "SELECT ?dev { ?dev rm:bluetoothAddress ?addr }",
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
80 initNs=dict(rm=ROOM),
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
81 initBindings={Variable("?addr") : Literal(address)}):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
82 (dev,) = row
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
83 yield dev
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
84
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
85 graph = Graph()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
86 graph.parse("phones.n3", format="n3")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
87
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
88 d = Disco()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
89 hub = restkit.Resource(
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
90 # PSHB not working yet; "http://bang:9030/"
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
91 "http://slash:9049/"
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
92 )
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
93
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
94 def mongoInsert(msg):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
95 try:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
96 js = jsonlib.dumps(msg)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
97 except UnicodeDecodeError:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
98 pass
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
99 else:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
100 if msg['name'] != 'THINKPAD_T43':
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
101 hub.post("visitorNet", payload=js) # sans datetime
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
102 msg['created'] = datetime.datetime.now(tz.gettz('UTC'))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
103 mongo.insert(msg, safe=True)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
104
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
105 class Poller(object):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
106 def __init__(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
107 self.lastDevs = set() # addresses
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
108 self.lastNameForAddress = {}
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
109 self.currentGraph = Graph()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
110 self.lastPollTime = 0
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
111
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
112 def poll(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
113 log.debug("get devices")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
114 devs = d.nearbyDevices()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
115
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
116 devs.addCallback(self.compare)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
117 devs.addErrback(log.error)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
118 return devs
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
119
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
120 def compare(self, newDevs):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
121 self.lastPollTime = time.time()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
122 log.debug("got: %r", newDevs)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
123 lostDevs = self.lastDevs.copy()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
124 prevDevs = self.lastDevs.copy()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
125 self.lastDevs.clear()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
126 stmts = []
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
127
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
128 for address, name in newDevs:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
129 stmts.append((ROOM['bluetooth'],
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
130 ROOM['senses'],
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
131 Literal(str(address))))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
132 if address not in prevDevs:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
133 matches = 0
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
134 for dev in devicesFromAddress(address):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
135 log.info("found %s" % dev)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
136 matches += 1
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
137 if not matches:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
138 log.info("no matches for %s (%s)" % (name, address))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
139
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
140 print "%s %s %s" % (time.time(), name, address)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
141
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
142 self.lastNameForAddress[address] = name
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
143 print 'mongoInsert', ({"sensor" : "bluetooth",
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
144 "address" : address,
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
145 "name" : name,
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
146 "action" : "arrive"})
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
147
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
148 lostDevs.discard(address)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
149 self.lastDevs.add(address)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
150
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
151 for address in lostDevs:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
152 print 'mongoInsert', ({"sensor" : "bluetooth",
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
153 "address" : address,
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
154 "name" : self.lastNameForAddress[address],
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
155 "action" : "leave"})
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
156
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
157 for dev in devicesFromAddress(address):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
158 log.info("lost %s" % dev)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
159
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
160 class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
161 def get(self):
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
162 age = time.time() - self.settings.poller.lastPollTime
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
163 if age > 60 + 30:
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
164 raise ValueError("poll data is stale. age=%s" % age)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
165
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
166 self.write("bluetooth watcher. ")
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
167
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
168 if __name__ == '__main__':
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
169 log.setLevel(logging.DEBUG)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
170 poller = Poller()
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
171 reactor.listenTCP(9077, cyclone.web.Application([
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
172 (r'/', Index),
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
173 ], poller=poller))
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
174 task.LoopingCall(poller.poll).start(1)
4713bb87e34e moved from proj/room
drewp <drewp@bigasterisk.com>
parents:
diff changeset
175 reactor.run()