comparison service/arduinoNode/arduinoNode.py @ 233:4ebb5cc30002

server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code. Ignore-this: cf7d20d54e134e8ff33a9ee405610846
author drewp@bigasterisk.com
date Sat, 30 Jan 2016 06:40:00 -0800
parents 0aa54404df19
children 141079644c45
comparison
equal deleted inserted replaced
232:4e91f3ec460b 233:4ebb5cc30002
39 ROOM = Namespace('http://projects.bigasterisk.com/room/') 39 ROOM = Namespace('http://projects.bigasterisk.com/room/')
40 HOST = Namespace('http://bigasterisk.com/ruler/host/') 40 HOST = Namespace('http://bigasterisk.com/ruler/host/')
41 41
42 ACTION_BASE = 10 # higher than any of the fixed command numbers 42 ACTION_BASE = 10 # higher than any of the fixed command numbers
43 43
44 CTX = ROOM['arduinosOn%s' % socket.gethostname()] 44 hostname = socket.gethostname()
45 CTX = ROOM['arduinosOn%s' % hostname]
45 46
46 class Config(object): 47 class Config(object):
47 def __init__(self, masterGraph): 48 def __init__(self, masterGraph):
48 self.graph = ConjunctiveGraph() 49 self.graph = ConjunctiveGraph()
49 log.info('read config') 50 log.info('read config')
72 self.uri = uri 73 self.uri = uri
73 self.configGraph = configGraph 74 self.configGraph = configGraph
74 self.masterGraph = masterGraph 75 self.masterGraph = masterGraph
75 self.dev = dev 76 self.dev = dev
76 77
77 self.masterGraph.patch(Patch(addQuads=[ 78 self.masterGraph.patch(Patch(addQuads=self.staticStmts()))
78 (HOST[socket.gethostname()], ROOM['connectedTo'], self.uri, CTX), 79
79 ]))
80
81 # The order of this list needs to be consistent between the 80 # The order of this list needs to be consistent between the
82 # deployToArduino call and the poll call. 81 # deployToArduino call and the poll call.
83 self._devs = devices.makeDevices(configGraph, self.uri) 82 self._devs = devices.makeDevices(configGraph, self.uri)
84 self._devCommandNum = dict((dev.uri, ACTION_BASE + devIndex) 83 self._devCommandNum = dict((dev.uri, ACTION_BASE + devIndex)
85 for devIndex, dev in enumerate(self._devs)) 84 for devIndex, dev in enumerate(self._devs))
96 return { 95 return {
97 'uri': self.uri, 96 'uri': self.uri,
98 'dev': self.dev, 97 'dev': self.dev,
99 'baudrate': self.baudrate, 98 'baudrate': self.baudrate,
100 'devices': [d.description() for d in self._devs], 99 'devices': [d.description() for d in self._devs],
101 'graph': 'http://%s6:9059/graph' % socket.gethostname(), #todo
102 } 100 }
103 101
104 def open(self): 102 def open(self):
105 self.ser = LoggingSerial(port=self.dev, baudrate=self.baudrate, 103 self.ser = LoggingSerial(port=self.dev, baudrate=self.baudrate,
106 timeout=2) 104 timeout=2)
141 self._exportToGraphite() 139 self._exportToGraphite()
142 140
143 def _exportToGraphite(self): 141 def _exportToGraphite(self):
144 # note this is writing way too often- graphite is storing at a lower res 142 # note this is writing way too often- graphite is storing at a lower res
145 now = time.time() 143 now = time.time()
144 # 20 sec is not precise; just trying to reduce wifi traffic
145 if getattr(self, 'lastGraphiteExport', 0) + 20 > now:
146 return
147 self.lastGraphiteExport = now
148 log.debug('graphite export:')
146 # objects of these statements are suitable as graphite values. 149 # objects of these statements are suitable as graphite values.
147 graphitePredicates = {ROOM['temperatureF']} 150 graphitePredicates = {ROOM['temperatureF']}
151 # bug: one sensor can have temp and humid- this will be ambiguous
148 for s, graphiteName in self.configGraph.subject_objects(ROOM['graphiteName']): 152 for s, graphiteName in self.configGraph.subject_objects(ROOM['graphiteName']):
149 for group in self._statementsFromInputs.values(): 153 for group in self._statementsFromInputs.values():
150 for stmt in group: 154 for stmt in group:
151 if stmt[0] == s and stmt[1] in graphitePredicates: 155 if stmt[0] == s and stmt[1] in graphitePredicates:
156 log.debug(' sending %s -> %s', stmt[0], graphiteName)
152 self._carbon.send(graphiteName, stmt[2].toPython(), now) 157 self._carbon.send(graphiteName, stmt[2].toPython(), now)
153 158
154 def outputStatements(self, stmts): 159 def outputStatements(self, stmts):
155 unused = set(stmts) 160 unused = set(stmts)
156 for dev in self._devs: 161 for dev in self._devs:
157 stmtsForDev = [] 162 stmtsForDev = []
158 for pat in dev.outputPatterns(): 163 for pat in dev.outputPatterns():
174 # we're not currently tracking that, but the usual is 179 # we're not currently tracking that, but the usual is
175 # to change them in response to sendOutput so this 180 # to change them in response to sendOutput so this
176 # should be good enough. The right answer is to give 181 # should be good enough. The right answer is to give
177 # each dev the masterGraph for it to write to. 182 # each dev the masterGraph for it to write to.
178 self.syncMasterGraphToHostStatements(dev) 183 self.syncMasterGraphToHostStatements(dev)
179 log.info("success") 184 log.info("output and masterGraph sync complete")
180 if unused: 185 if unused:
181 log.info("Board %s doesn't care about these statements:", self.uri) 186 log.info("Board %s doesn't care about these statements:", self.uri)
182 for s in unused: 187 for s in unused:
183 log.info("%r", s) 188 log.warn("%r", s)
184 189
185 def syncMasterGraphToHostStatements(self, dev): 190 def syncMasterGraphToHostStatements(self, dev):
186 hostStmtCtx = URIRef(dev.uri + '/host') 191 hostStmtCtx = URIRef(dev.uri + '/host')
187 newQuads = inContext(dev.hostStatements(), hostStmtCtx) 192 newQuads = inContext(dev.hostStatements(), hostStmtCtx)
188 self.masterGraph.patchSubgraph(hostStmtCtx, newQuads) 193 p = self.masterGraph.patchSubgraph(hostStmtCtx, newQuads)
189 194 log.debug("patch master with these host stmts %s", p)
195
196 def staticStmts(self):
197 return [(HOST[hostname], ROOM['connectedTo'], self.uri, CTX)]
198
190 def generateArduinoCode(self): 199 def generateArduinoCode(self):
191 code = write_arduino_code.writeCode(self.baudrate, self._devs, self._devCommandNum) 200 code = write_arduino_code.writeCode(self.baudrate, self._devs,
201 self._devCommandNum)
192 code = write_arduino_code.indent(code) 202 code = write_arduino_code.indent(code)
193 cksum = hashlib.sha1(code).hexdigest() 203 cksum = hashlib.sha1(code).hexdigest()
194 code = code.replace('CODE_CHECKSUM', cksum) 204 code = code.replace('CODE_CHECKSUM', cksum)
195 return code, cksum 205 return code, cksum
196 206
298 b.outputStatements([stmt]) 308 b.outputStatements([stmt])
299 309
300 310
301 class Boards(cyclone.web.RequestHandler): 311 class Boards(cyclone.web.RequestHandler):
302 def get(self): 312 def get(self):
303
304 self.set_header('Content-type', 'application/json') 313 self.set_header('Content-type', 'application/json')
305 self.write(json.dumps({ 314 self.write(json.dumps({
306 'host': socket.gethostname(), 315 'host': hostname,
307 'boards': [b.description() for b in self.settings.boards] 316 'boards': [b.description() for b in self.settings.boards]
308 }, indent=2)) 317 }, indent=2))
309 318
310 def currentSerialDevices(): 319 def currentSerialDevices():
311 log.info('find connected boards') 320 log.info('find connected boards')
342 log.info('open boards') 351 log.info('open boards')
343 for b in boards: 352 for b in boards:
344 b.startPolling() 353 b.startPolling()
345 354
346 355
347 app = cyclone.web.Application([ 356 reactor.listenTCP(9059, cyclone.web.Application([
348 (r"/()", cyclone.web.StaticFileHandler, { 357 (r"/()", cyclone.web.StaticFileHandler, {
349 "path": "static", "default_filename": "index.html"}), 358 "path": "static", "default_filename": "index.html"}),
350 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}), 359 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}),
351 (r'/boards', Boards), 360 (r'/boards', Boards),
352 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}), 361 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}),
353 (r"/graph/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}), 362 (r"/graph/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}),
354 (r'/output', OutputPage), 363 (r'/output', OutputPage),
355 (r'/arduinoCode', ArduinoCode), 364 (r'/arduinoCode', ArduinoCode),
356 (r'/dot', Dot), 365 (r'/dot', Dot),
357 ], config=config, boards=boards) 366 ], config=config, boards=boards), interface='::')
358 reactor.listenTCP(9059, app, interface='::')
359 reactor.run() 367 reactor.run()
360 368
361 main() 369 main()