comparison service/piNode/piNode.py @ 408:0787cd64ecf8

cmdline flag on piNode to pick hub host Ignore-this: e88b7bc860b040e6952ddf3723f26a23
author drewp@bigasterisk.com
date Tue, 12 Mar 2019 00:14:12 -0700
parents 61f1c529a9b7
children 1122016d16eb
comparison
equal deleted inserted replaced
407:864c8911ae73 408:0787cd64ecf8
34 ROOM = Namespace('http://projects.bigasterisk.com/room/') 34 ROOM = Namespace('http://projects.bigasterisk.com/room/')
35 HOST = Namespace('http://bigasterisk.com/ruler/host/') 35 HOST = Namespace('http://bigasterisk.com/ruler/host/')
36 36
37 hostname = socket.gethostname() 37 hostname = socket.gethostname()
38 CTX = ROOM['pi/%s' % hostname] 38 CTX = ROOM['pi/%s' % hostname]
39 etcd = etcd3.client(host='bang6', port=9022)
40 39
41 def patchRandid(): 40 def patchRandid():
42 """ 41 """
43 I'm concerned urandom is slow on raspberry pi, and I'm adding to 42 I'm concerned urandom is slow on raspberry pi, and I'm adding to
44 graphs a lot. Unclear what the ordered return values might do to 43 graphs a lot. Unclear what the ordered return values might do to
51 import rdflib.plugins.memory 50 import rdflib.plugins.memory
52 rdflib.plugins.memory.randid = randid 51 rdflib.plugins.memory.randid = randid
53 patchRandid() 52 patchRandid()
54 53
55 class Config(object): 54 class Config(object):
56 def __init__(self, masterGraph): 55 def __init__(self, masterGraph, hubHost):
56 self.etcd = etcd3.client(host=hubHost, port=9022)
57
57 self.masterGraph = masterGraph 58 self.masterGraph = masterGraph
59 self.hubHost = hubHost
58 self.configGraph = ConjunctiveGraph() 60 self.configGraph = ConjunctiveGraph()
59 self.boards = [] 61 self.boards = []
60 self.etcPrefix = 'pi/' 62 self.etcPrefix = 'pi/'
61 63
62 self.reread() 64 self.reread()
63 65
64 deferToThread(self.watchEtcd) 66 deferToThread(self.watchEtcd)
65 67
66 def watchEtcd(self): 68 def watchEtcd(self):
67 events, cancel = etcd.watch_prefix(self.etcPrefix) 69 events, cancel = self.etcd.watch_prefix(self.etcPrefix)
68 reactor.addSystemEventTrigger('before', 'shutdown', cancel) 70 reactor.addSystemEventTrigger('before', 'shutdown', cancel)
69 for ev in events: 71 for ev in events:
70 log.info('%s changed', ev.key) 72 log.info('%s changed', ev.key)
71 reactor.callFromThread(self.configChanged) 73 reactor.callFromThread(self.configChanged)
72 74
81 83
82 def reread(self): 84 def reread(self):
83 self.rereadLater = None 85 self.rereadLater = None
84 log.info('read config') 86 log.info('read config')
85 self.configGraph = ConjunctiveGraph() 87 self.configGraph = ConjunctiveGraph()
86 for v, md in etcd.get_prefix(self.etcPrefix): 88 for v, md in self.etcd.get_prefix(self.etcPrefix):
87 log.info(' read file %r', md.key) 89 log.info(' read file %r', md.key)
88 self.configGraph.parse(StringInputSource(v), format='n3') 90 self.configGraph.parse(StringInputSource(v), format='n3')
89 self.configGraph.bind('', ROOM) 91 self.configGraph.bind('', ROOM)
90 self.configGraph.bind('rdf', RDF) 92 self.configGraph.bind('rdf', RDF)
91 # config graph is too noisy; maybe make it a separate resource 93 # config graph is too noisy; maybe make it a separate resource
104 thisHost) 106 thisHost)
105 self.boards = [] 107 self.boards = []
106 return 108 return
107 109
108 log.info("found config for board %r" % thisBoard) 110 log.info("found config for board %r" % thisBoard)
109 self.boards = [Board(self.configGraph, self.masterGraph, thisBoard)] 111 self.boards = [Board(self.configGraph, self.masterGraph, thisBoard, self.hubHost)]
110 self.boards[0].startPolling() 112 self.boards[0].startPolling()
111 113
112 114
113 class Board(object): 115 class Board(object):
114 """similar to arduinoNode.Board but without the communications stuff""" 116 """similar to arduinoNode.Board but without the communications stuff"""
115 def __init__(self, graph, masterGraph, uri): 117 def __init__(self, graph, masterGraph, uri, hubHost):
116 self.graph, self.uri = graph, uri 118 self.graph, self.uri = graph, uri
119 self.hubHost = hubHost
117 self.masterGraph = masterGraph 120 self.masterGraph = masterGraph
118 self.masterGraph.setToGraph(self.staticStmts()) 121 self.masterGraph.setToGraph(self.staticStmts())
119 self.pi = pigpio.pi() 122 self.pi = pigpio.pi()
120 self._devs = devices.makeDevices(graph, self.uri, self.pi) 123 self._devs = devices.makeDevices(graph, self.uri, self.pi)
121 log.debug('found %s devices', len(self._devs)) 124 log.debug('found %s devices', len(self._devs))
179 self._statementsFromInputs[dev] = new 182 self._statementsFromInputs[dev] = new
180 183
181 def _sendOneshot(self, oneshot): 184 def _sendOneshot(self, oneshot):
182 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3()) 185 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3())
183 for s,p,o in oneshot)).encode('utf8') 186 for s,p,o in oneshot)).encode('utf8')
184 url = 'http://bang6:9071/oneShot' 187 url = 'http://%s:9071/oneShot' % self.hubHost
185 d = fetch(method='POST', 188 d = fetch(method='POST',
186 url=url, 189 url=url,
187 headers={'Content-Type': ['text/n3']}, 190 headers={'Content-Type': ['text/n3']},
188 postdata=body, 191 postdata=body,
189 timeout=5) 192 timeout=5)
277 280
278 def main(): 281 def main():
279 arg = docopt(""" 282 arg = docopt("""
280 Usage: piNode.py [options] 283 Usage: piNode.py [options]
281 284
282 -v Verbose 285 -v Verbose
286 --ow Just report onewire device URIs and readings, then exit.
287 --hub=HOST Hostname for etc3 and oneshot posts. [default: bang.vpn-home.bigasterisk.com]
283 """) 288 """)
284 log.setLevel(logging.WARN) 289 log.setLevel(logging.WARN)
285 if arg['-v']: 290 if arg['-v']:
286 from twisted.python import log as twlog 291 from twisted.python import log as twlog
287 twlog.startLogging(sys.stdout) 292 twlog.startLogging(sys.stdout)
288 293
289 log.setLevel(logging.DEBUG) 294 log.setLevel(logging.DEBUG)
290 295
296 if arg['--ow']:
297 log.setLevel(logging.INFO)
298 for stmt in devices.OneWire().poll():
299 print stmt
300 return
301
291 masterGraph = PatchableGraph() 302 masterGraph = PatchableGraph()
292 config = Config(masterGraph) 303 config = Config(masterGraph, arg['--hub'])
293 304
294 reactor.listenTCP(9059, cyclone.web.Application([ 305 reactor.listenTCP(9059, cyclone.web.Application([
295 (r"/()", cyclone.web.StaticFileHandler, { 306 (r"/()", cyclone.web.StaticFileHandler, {
296 "path": "static", "default_filename": "index.html"}), 307 "path": "static", "default_filename": "index.html"}),
297 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}), 308 (r'/static/(.*)', cyclone.web.StaticFileHandler, {"path": "static"}),