comparison service/arduinoNode/arduinoNode.py @ 456:12f9f1838fb5

arduinoNode: build updates, stats support, etc Ignore-this: 39386eb7644e3cf522e0f72a874eadba
author drewp@bigasterisk.com
date Sat, 20 Apr 2019 23:28:29 -0700
parents 13b2a61650c1
children 5c750342604d
comparison
equal deleted inserted replaced
455:7e09c0d0a86e 456:12f9f1838fb5
9 from twisted.internet import reactor, task 9 from twisted.internet import reactor, task
10 from twisted.internet.defer import inlineCallbacks 10 from twisted.internet.defer import inlineCallbacks
11 from twisted.internet.threads import deferToThread 11 from twisted.internet.threads import deferToThread
12 from docopt import docopt 12 from docopt import docopt
13 import etcd3 13 import etcd3
14 from greplin import scales
15 from greplin.scales.cyclonehandler import StatsHandler
14 16
15 import devices 17 import devices
16 import write_arduino_code 18 import write_arduino_code
17 import dotrender 19 import dotrender
18 import rdflib_patch 20 import rdflib_patch
39 41
40 ACTION_BASE = 10 # higher than any of the fixed command numbers 42 ACTION_BASE = 10 # higher than any of the fixed command numbers
41 43
42 hostname = socket.gethostname() 44 hostname = socket.gethostname()
43 CTX = ROOM['arduinosOn%s' % hostname] 45 CTX = ROOM['arduinosOn%s' % hostname]
44 etcd = etcd3.client(host='bang6') 46
47 STATS = scales.collection('/root',
48 )
49
50
51 etcd = etcd3.client(host='bang6', port=9022)
45 52
46 class Config(object): 53 class Config(object):
47 def __init__(self, masterGraph, slowMode=False): 54 def __init__(self, masterGraph, slowMode=False):
48 self.masterGraph = masterGraph 55 self.masterGraph = masterGraph
49 self.slowMode = slowMode 56 self.slowMode = slowMode
121 self.uri = uri 128 self.uri = uri
122 self.configGraph = configGraph 129 self.configGraph = configGraph
123 self.masterGraph = masterGraph 130 self.masterGraph = masterGraph
124 self.dev = dev 131 self.dev = dev
125 132
126 self.masterGraph.patch(Patch(addQuads=self.staticStmts())) 133 self.masterGraph.setToGraph(self.staticStmts())
127 134
128 # The order of this list needs to be consistent between the 135 # The order of this list needs to be consistent between the
129 # deployToArduino call and the poll call. 136 # deployToArduino call and the poll call.
130 self._devs = devices.makeDevices(configGraph, self.uri) 137 self._devs = devices.makeDevices(configGraph, self.uri)
131 self._devCommandNum = dict((dev.uri, ACTION_BASE + devIndex) 138 self._devCommandNum = dict((dev.uri, ACTION_BASE + devIndex)
179 if isinstance(new, dict): # new style 186 if isinstance(new, dict): # new style
180 oneshot = new['oneshot'] 187 oneshot = new['oneshot']
181 new = new['latest'] 188 new = new['latest']
182 else: 189 else:
183 oneshot = None 190 oneshot = None
184 prev = self._statementsFromInputs.get(i.uri, []) 191
185 if new or prev: 192 self._updateMasterWithNewPollStatements(i.uri, new)
186 self._statementsFromInputs[i.uri] = new 193
187 # it's important that quads from different devices
188 # don't clash, since that can lead to inconsistent
189 # patches (e.g.
190 # dev1 changes value from 1 to 2;
191 # dev2 changes value from 2 to 3;
192 # dev1 changes from 2 to 4 but this patch will
193 # fail since the '2' statement is gone)
194 self.masterGraph.patch(Patch.fromDiff(inContext(prev, i.uri),
195 inContext(new, i.uri)))
196 if oneshot: 194 if oneshot:
197 self._sendOneshot(oneshot) 195 self._sendOneshot(oneshot)
198 self._lastPollTime[i.uri] = now 196 self._lastPollTime[i.uri] = now
199 except: 197 except:
200 log.warn('while polling %r:', i.uri) 198 log.warn('while polling %r:', i.uri)
216 stmts = set() 214 stmts = set()
217 for v in self._statementsFromInputs.values(): 215 for v in self._statementsFromInputs.values():
218 stmts.update(v) 216 stmts.update(v)
219 self._influx.exportToInflux(stmts) 217 self._influx.exportToInflux(stmts)
220 218
219 def _updateMasterWithNewPollStatements(self, dev, new):
220 prev = self._statementsFromInputs.get(dev, set())
221
222 # it's important that quads from different devices
223 # don't clash, since that can lead to inconsistent
224 # patches (e.g.
225 # dev1 changes value from 1 to 2;
226 # dev2 changes value from 2 to 3;
227 # dev1 changes from 2 to 4 but this patch will
228 # fail since the '2' statement is gone)
229 self.masterGraph.patch(Patch.fromDiff(inContext(prev, dev),
230 inContext(new, dev)))
231 self._statementsFromInputs[dev] = new
232
221 def _sendOneshot(self, oneshot): 233 def _sendOneshot(self, oneshot):
222 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3()) 234 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3())
223 for s,p,o in oneshot)).encode('utf8') 235 for s,p,o in oneshot)).encode('utf8')
224 fetch(method='POST', 236 fetch(method='POST',
225 url='http://bang6:9071/oneShot', 237 url='http://bang6:9071/oneShot',
253 self.syncMasterGraphToHostStatements(dev) 265 self.syncMasterGraphToHostStatements(dev)
254 log.info("output and masterGraph sync complete") 266 log.info("output and masterGraph sync complete")
255 if unused: 267 if unused:
256 log.info("Board %s doesn't care about these statements:", self.uri) 268 log.info("Board %s doesn't care about these statements:", self.uri)
257 for s in unused: 269 for s in unused:
258 log.warn("%r", s) 270 log.info("%r", s)
259 271
260 def syncMasterGraphToHostStatements(self, dev): 272 def syncMasterGraphToHostStatements(self, dev):
261 hostStmtCtx = URIRef(dev.uri + '/host') 273 hostStmtCtx = URIRef(dev.uri + '/host')
262 newQuads = inContext(dev.hostStatements(), hostStmtCtx) 274 newQuads = inContext(dev.hostStatements(), hostStmtCtx)
263 p = self.masterGraph.patchSubgraph(hostStmtCtx, newQuads) 275 p = self.masterGraph.patchSubgraph(hostStmtCtx, newQuads)
412 424
413 reactor.listenTCP(9059, cyclone.web.Application([ 425 reactor.listenTCP(9059, cyclone.web.Application([
414 (r"/()", cyclone.web.StaticFileHandler, { 426 (r"/()", cyclone.web.StaticFileHandler, {
415 "path": "static", "default_filename": "index.html"}), 427 "path": "static", "default_filename": "index.html"}),
416 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}), 428 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}),
429 (r'/stats/(.*)', StatsHandler, {'serverName': 'arduinoNode'}),
417 (r'/boards', Boards), 430 (r'/boards', Boards),
418 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}), 431 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}),
419 (r"/graph/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}), 432 (r"/graph/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}),
420 (r'/output', OutputPage), 433 (r'/output', OutputPage),
421 (r'/arduinoCode', ArduinoCode), 434 (r'/arduinoCode', ArduinoCode),