Mercurial > code > home > repos > homeauto
annotate service/piNode/piNode.py @ 1444:4afb1830bb5e
use rx version 3.x
Ignore-this: 4232f8e780d35a8d0642e86521eb2801
darcs-hash:747608892b607f78260f4772a4ff2b24c7392f73
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Tue, 24 Sep 2019 14:04:02 -0700 |
parents | 99540f1a11f7 |
children | 9d074317e16a |
rev | line source |
---|---|
1439 | 1 import logging, socket, json, time, pkg_resources |
987 | 2 import cyclone.web |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
3 from rdflib import Namespace, URIRef, Literal, Graph, RDF, ConjunctiveGraph |
989
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
4 from rdflib.parser import StringInputSource |
1439 | 5 from twisted.internet import reactor |
6 from twisted.internet.defer import inlineCallbacks, maybeDeferred, returnValue | |
1152 | 7 from twisted.internet.threads import deferToThread |
987 | 8 from docopt import docopt |
1439 | 9 import etcd3 |
1269
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
10 from greplin import scales |
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
11 from greplin.scales.cyclonehandler import StatsHandler |
1439 | 12 import pigpio |
13 import treq | |
1136
1e43ec4a5f23
build and import updates for rdfdb, etc
drewp <drewp@bigasterisk.com>
parents:
1130
diff
changeset
|
14 |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
15 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler |
1392
83043957c809
pinode devs can now poll in parallel (within one poll step). doesn't help much.
drewp <drewp@bigasterisk.com>
parents:
1356
diff
changeset
|
16 from cycloneerr import PrettyErrorHandler |
1443
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
17 from standardservice.logsetup import log, verboseLogging |
1143
d1bc88f67969
RgbPixelsAnimation and docker build updates
drewp <drewp@bigasterisk.com>
parents:
1136
diff
changeset
|
18 from rdfdb.rdflibpatch import inContext |
d1bc88f67969
RgbPixelsAnimation and docker build updates
drewp <drewp@bigasterisk.com>
parents:
1136
diff
changeset
|
19 from rdfdb.patch import Patch |
1443
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
20 from rdflib_pi_opt import patchRandid |
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
21 from export_to_influxdb import InfluxExporter |
987 | 22 |
23 import devices | |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
24 |
987 | 25 ROOM = Namespace('http://projects.bigasterisk.com/room/') |
26 HOST = Namespace('http://bigasterisk.com/ruler/host/') | |
27 | |
28 hostname = socket.gethostname() | |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
29 CTX = ROOM['pi/%s' % hostname] |
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
30 |
1269
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
31 STATS = scales.collection('/root', |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
32 scales.PmfStat('configReread'), |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
33 scales.IntStat('pollException'), |
1428
56e07d3f0930
frontdoor configs; move device class timing to greplin stats
drewp <drewp@bigasterisk.com>
parents:
1427
diff
changeset
|
34 scales.PmfStat('pollAll'), |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
35 scales.PmfStat('sendOneshot'), |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
36 scales.PmfStat('outputStatements'), |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
37 |
1269
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
38 ) |
1063 | 39 |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
40 class Config(object): |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
41 def __init__(self, masterGraph, hubHost): |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
42 self.etcd = etcd3.client(host=hubHost, port=9022) |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
43 |
1152 | 44 self.masterGraph = masterGraph |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
45 self.hubHost = hubHost |
1152 | 46 self.configGraph = ConjunctiveGraph() |
47 self.boards = [] | |
48 self.etcPrefix = 'pi/' | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
49 self.rereadLater = None |
1152 | 50 |
51 self.reread() | |
52 | |
53 deferToThread(self.watchEtcd) | |
54 | |
55 def watchEtcd(self): | |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
56 events, cancel = self.etcd.watch_prefix(self.etcPrefix) |
1152 | 57 reactor.addSystemEventTrigger('before', 'shutdown', cancel) |
58 for ev in events: | |
59 log.info('%s changed', ev.key) | |
60 reactor.callFromThread(self.configChanged) | |
61 | |
62 def configChanged(self): | |
63 self.cancelRead() | |
64 self.rereadLater = reactor.callLater(.1, self.reread) | |
65 | |
66 def cancelRead(self): | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
67 if self.rereadLater: |
1152 | 68 self.rereadLater.cancel() |
69 self.rereadLater = None | |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
70 |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
71 @STATS.configReread.time() |
1152 | 72 def reread(self): |
73 self.rereadLater = None | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
74 log.info('read config') |
1152 | 75 self.configGraph = ConjunctiveGraph() |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
76 for v, md in self.etcd.get_prefix(self.etcPrefix): |
1152 | 77 log.info(' read file %r', md.key) |
78 self.configGraph.parse(StringInputSource(v), format='n3') | |
79 self.configGraph.bind('', ROOM) | |
80 self.configGraph.bind('rdf', RDF) | |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
81 # config graph is too noisy; maybe make it a separate resource |
1152 | 82 #masterGraph.patch(Patch(addGraph=self.configGraph)) |
83 self.setupBoards() | |
1427 | 84 |
85 def setupBoards(self): | |
1152 | 86 thisHost = Literal(hostname) |
87 for row in self.configGraph.query( | |
88 'SELECT ?board WHERE { ?board a :PiBoard; :hostname ?h }', | |
89 initBindings=dict(h=thisHost)): | |
90 thisBoard = row.board | |
91 break | |
92 else: | |
93 log.warn("config had no board for :hostname %s. Waiting for config update." % | |
94 thisHost) | |
95 self.boards = [] | |
96 return | |
97 | |
98 log.info("found config for board %r" % thisBoard) | |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
99 self.boards = [Board(self.configGraph, self.masterGraph, thisBoard, self.hubHost)] |
1152 | 100 |
987 | 101 |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
102 class DeviceRunner(object): |
1444 | 103 def __init__(self, dev, masterGraph, sendOneshot, influx): |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
104 self.dev = dev |
1444 | 105 self.masterGraph = masterGraph |
106 self.sendOneshot = sendOneshot | |
107 self.influx = influx | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
108 self.period = getattr(self.dev, 'pollPeriod', .05) |
1444 | 109 self.latestStatementsFromInputs = set() |
110 self.lastPollTime = None | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
111 |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
112 reactor.callLater(0, self.poll) |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
113 |
1444 | 114 def syncMasterGraphToHostStatements(self): |
115 hostStmtCtx = URIRef(self.dev.uri + '/host') | |
116 newQuads = inContext(self.dev.hostStatements(), hostStmtCtx) | |
117 p = self.masterGraph.patchSubgraph(hostStmtCtx, newQuads) | |
118 if p: | |
119 log.debug("patch master with these host stmts %s", p) | |
120 | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
121 @inlineCallbacks |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
122 def poll(self): |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
123 now = time.time() |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
124 try: |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
125 with self.dev.stats.poll.time(): |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
126 new = yield maybeDeferred(self.dev.poll) |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
127 finally: |
1444 | 128 reactor.callLater(max(0, self.period - (time.time() - now)), self.poll) |
129 | |
130 if isinstance(new, dict): # new style | |
131 oneshot = set(new['oneshot']) | |
132 new = set(new['latest']) | |
133 else: | |
134 oneshot = set() | |
135 new = set(new) | |
136 | |
137 prev = self.latestStatementsFromInputs | |
138 # it's important that quads from different devices | |
139 # don't clash, since that can lead to inconsistent | |
140 # patches (e.g. | |
141 # dev1 changes value from 1 to 2; | |
142 # dev2 changes value from 2 to 3; | |
143 # dev1 changes from 2 to 4 but this patch will | |
144 # fail since the '2' statement is gone) | |
145 self.masterGraph.patch(Patch.fromDiff(inContext(prev, self.dev.uri), | |
146 inContext(new, self.dev.uri))) | |
147 self.latestStatementsFromInputs = new | |
148 | |
149 self.syncMasterGraphToHostStatements() # needed? | |
150 | |
151 if oneshot: | |
152 self.sendOneshot(oneshot) | |
153 self.lastPollTime = now | |
154 | |
155 if self.latestStatementsFromInputs: | |
156 self.influx.exportToInflux(set.union(set(self.latestStatementsFromInputs))) | |
157 | |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
158 returnValue(new) |
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
159 |
1444 | 160 def filterIncomingStatements(self, stmts): |
161 wanted = set() | |
162 unwanted = set(stmts) | |
163 for pat in self.dev.outputPatterns(): | |
164 if [term is None for term in pat] != [False, False, True]: | |
165 raise NotImplementedError | |
166 for stmt in stmts: | |
167 if stmt[:2] == pat[:2]: | |
168 wanted.add(stmt) | |
169 unwanted.discard(stmt) | |
170 return wanted, unwanted | |
171 | |
172 def onPutStatements(self, stmts): | |
173 log.info("output goes to action handler for %s" % self.dev.uri) | |
174 with self.dev.stats.output.time(): | |
175 self.dev.sendOutput(stmts) | |
176 self.syncMasterGraphToHostStatements() | |
177 | |
987 | 178 class Board(object): |
179 """similar to arduinoNode.Board but without the communications stuff""" | |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
180 def __init__(self, graph, masterGraph, uri, hubHost): |
987 | 181 self.graph, self.uri = graph, uri |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
182 self.hubHost = hubHost |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
183 self.masterGraph = masterGraph |
1439 | 184 |
1154
5da3a85b59e4
more robust about not accumulating old stmts
drewp <drewp@bigasterisk.com>
parents:
1152
diff
changeset
|
185 self.masterGraph.setToGraph(self.staticStmts()) |
987 | 186 self.pi = pigpio.pi() |
1444 | 187 |
1098
b5906f6fce3f
save data to influxdb, not graphite
drewp <drewp@bigasterisk.com>
parents:
1076
diff
changeset
|
188 self._influx = InfluxExporter(self.graph) |
1444 | 189 self._runners = [DeviceRunner(d, self.masterGraph, self.sendOneshot, self._influx) |
190 for d in devices.makeDevices(graph, self.uri, self.pi)] | |
191 log.debug('found %s devices', len(self._runners)) | |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
192 |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
193 @STATS.sendOneshot.time() |
1444 | 194 def sendOneshot(self, oneshot): |
1056
d2007482aec5
start sending oneshot events from some devices
drewp <drewp@bigasterisk.com>
parents:
1048
diff
changeset
|
195 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3()) |
d2007482aec5
start sending oneshot events from some devices
drewp <drewp@bigasterisk.com>
parents:
1048
diff
changeset
|
196 for s,p,o in oneshot)).encode('utf8') |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
197 url = 'http://%s:9071/oneShot' % self.hubHost |
1444 | 198 d = treq.post( |
199 url=url.encode('ascii'), | |
200 headers={b'Content-Type': [b'text/n3']}, | |
201 data=body, | |
1076
d0ca77a3faf4
rewrite oneShotPost to ease debugging. add try-block around polling
drewp <drewp@bigasterisk.com>
parents:
1074
diff
changeset
|
202 timeout=5) |
d0ca77a3faf4
rewrite oneShotPost to ease debugging. add try-block around polling
drewp <drewp@bigasterisk.com>
parents:
1074
diff
changeset
|
203 def err(e): |
d0ca77a3faf4
rewrite oneShotPost to ease debugging. add try-block around polling
drewp <drewp@bigasterisk.com>
parents:
1074
diff
changeset
|
204 log.info('oneshot post to %r failed: %s', |
d0ca77a3faf4
rewrite oneShotPost to ease debugging. add try-block around polling
drewp <drewp@bigasterisk.com>
parents:
1074
diff
changeset
|
205 url, e.getErrorMessage()) |
d0ca77a3faf4
rewrite oneShotPost to ease debugging. add try-block around polling
drewp <drewp@bigasterisk.com>
parents:
1074
diff
changeset
|
206 d.addErrback(err) |
1056
d2007482aec5
start sending oneshot events from some devices
drewp <drewp@bigasterisk.com>
parents:
1048
diff
changeset
|
207 |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
208 @STATS.outputStatements.time() |
1444 | 209 def outputStatements(self, stmts: set): |
210 if not stmts: | |
211 return | |
212 for devRunner in self._runners: | |
213 wanted, unwanted = devRunner.filterIncomingStatements(stmts) | |
214 log.info(f'\ndev {devRunner.dev.uri}:n wanted {wanted}. unwanted {unwanted}') | |
215 if len(wanted) == len(stmts): | |
216 devRunner.onPutStatements(stmts) | |
217 break | |
218 elif len(unwanted) == len(stmts): | |
219 continue | |
220 else: | |
221 raise NotImplementedError(f'dev {devRunner.dev.uri} wanted only {wanted}') | |
222 else: | |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
223 log.info("Board %s doesn't care about these statements:", self.uri) |
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
224 for s in unused: |
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
225 log.warn("%r", s) |
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
226 |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
227 def staticStmts(self): |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
228 return [(HOST[hostname], ROOM['connectedTo'], self.uri, CTX)] |
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
229 |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
230 def description(self): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
231 """for web page""" |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
232 return { |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
233 'uri': self.uri, |
1444 | 234 'devices': [d.dev.description() for d in self._runners], |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
235 'graph': 'http://sticker:9059/graph', #todo |
1431
af2d0249a2cc
wip for pytype support and separate device run loops on piNode
drewp <drewp@bigasterisk.com>
parents:
1430
diff
changeset
|
236 } |
1427 | 237 |
989
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
238 def rdfGraphBody(body, headers): |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
239 g = Graph() |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
240 g.parse(StringInputSource(body), format='nt') |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
241 return g |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
242 |
1394
b27d0f9a00ef
pinode use prettyerrorhandler
drewp <drewp@bigasterisk.com>
parents:
1392
diff
changeset
|
243 class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler): |
987 | 244 def put(self): |
989
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
245 arg = self.request.arguments |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
246 if arg.get('s') and arg.get('p'): |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
247 subj = URIRef(arg['s'][-1]) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
248 pred = URIRef(arg['p'][-1]) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
249 turtleLiteral = self.request.body |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
250 try: |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
251 obj = Literal(float(turtleLiteral)) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
252 except ValueError: |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
253 obj = Literal(turtleLiteral) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
254 stmt = (subj, pred, obj) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
255 else: |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
256 g = rdfGraphBody(self.request.body, self.request.headers) |
065fc9e07c10
piNode allow nt graphs as the body of a PUT /output
drewp <drewp@bigasterisk.com>
parents:
988
diff
changeset
|
257 assert len(g) == 1, len(g) |
1439 | 258 stmt = next(g.triples((None, None, None))) |
987 | 259 |
1152 | 260 for b in self.settings.config.boards: |
1439 | 261 b.outputStatements({stmt}) |
987 | 262 |
1394
b27d0f9a00ef
pinode use prettyerrorhandler
drewp <drewp@bigasterisk.com>
parents:
1392
diff
changeset
|
263 class Boards(PrettyErrorHandler, cyclone.web.RequestHandler): |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
264 def get(self): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
265 self.set_header('Content-type', 'application/json') |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
266 self.write(json.dumps({ |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
267 'host': hostname, |
1152 | 268 'boards': [b.description() for b in self.settings.config.boards] |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
269 }, indent=2)) |
1427 | 270 |
987 | 271 def main(): |
272 arg = docopt(""" | |
273 Usage: piNode.py [options] | |
274 | |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
275 -v Verbose |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
276 --ow Just report onewire device URIs and readings, then exit. |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
277 --hub=HOST Hostname for etc3 and oneshot posts. [default: bang.vpn-home.bigasterisk.com] |
987 | 278 """) |
1443
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
279 verboseLogging(arg['-v']) |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
280 |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
281 if arg['--ow']: |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
282 log.setLevel(logging.INFO) |
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
283 for stmt in devices.OneWire().poll(): |
1439 | 284 print(stmt) |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
285 return |
1427 | 286 |
1443
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
287 patchRandid() |
99540f1a11f7
move bnode id optimization to its own file. more logging cleanups
drewp <drewp@bigasterisk.com>
parents:
1442
diff
changeset
|
288 |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
289 masterGraph = PatchableGraph() |
1211
8512001ae0a1
cmdline flag on piNode to pick hub host
drewp <drewp@bigasterisk.com>
parents:
1187
diff
changeset
|
290 config = Config(masterGraph, arg['--hub']) |
1427 | 291 |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
292 static = pkg_resources.resource_filename('homeauto_anynode', 'static/') |
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
293 |
987 | 294 reactor.listenTCP(9059, cyclone.web.Application([ |
1430
445e24e8c8bb
lib upgrades; fix a static http server path
drewp <drewp@bigasterisk.com>
parents:
1428
diff
changeset
|
295 (r"/(|output-widgets.html)", cyclone.web.StaticFileHandler, { |
1355
f2159312b0e7
update build and deps to use invoke and to use new lib layout, plus more stats collection
drewp <drewp@bigasterisk.com>
parents:
1269
diff
changeset
|
296 "path": static, "default_filename": "index.html"}), |
1356 | 297 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": static}), |
1269
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
298 (r'/stats/(.*)', StatsHandler, {'serverName': 'piNode'}), |
1038
ffe6a00c6cef
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
drewp <drewp@bigasterisk.com>
parents:
1035
diff
changeset
|
299 (r'/boards', Boards), |
1031
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
300 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}), |
9328df09f679
piNode uses new graph SSE code
drewp <drewp@bigasterisk.com>
parents:
1030
diff
changeset
|
301 (r"/graph/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}), |
987 | 302 (r'/output', OutputPage), |
1269
73b6ed12bae6
stats handler, events output fix, build updaets
drewp <drewp@bigasterisk.com>
parents:
1211
diff
changeset
|
303 ], config=config, debug=arg['-v']), interface='::') |
1063 | 304 log.warn('serving on 9059') |
987 | 305 reactor.run() |
306 | |
307 main() |