comparison service/rfid/rfid.py @ 1194:ee9cbe5817a4

rfid reader service Ignore-this: 26df9a4be891c26722311cf89d1d7cf7 darcs-hash:80ff40afce46a1429309421b1db52aefd5b675a8
author drewp <drewp@bigasterisk.com>
date Thu, 03 Jan 2019 21:52:27 -0800
parents
children cebc0134254a
comparison
equal deleted inserted replaced
1193:08a6eb5edf3d 1194:ee9cbe5817a4
1 from docopt import docopt
2 from rdfdb.patch import Patch
3 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
4 from rdflib import Namespace, URIRef, Literal, Graph
5 from rdflib.parser import StringInputSource
6 from twisted.internet import reactor, task
7 import cyclone.web
8 from cyclone.httpclient import fetch
9 import logging, time
10 from MFRC522.SimpleMFRC522 import SimpleMFRC522
11 from logsetup import log, enableTwistedLog
12
13 ROOM = Namespace('http://projects.bigasterisk.com/room/')
14
15 ctx = ROOM['frontDoorWindowRfidCtx']
16
17 def rdfGraphBody(body, headers):
18 g = Graph()
19 g.parse(StringInputSource(body), format='nt')
20 return g
21
22 class OutputPage(cyclone.web.RequestHandler):
23 def put(self):
24 user = URIRef(self.request.headers['x-foaf-agent'])
25 arg = self.request.arguments
26 if arg.get('s') and arg.get('p'):
27 subj = URIRef(arg['s'][-1])
28 pred = URIRef(arg['p'][-1])
29 obj = URIRef(self.request.body)
30 stmt = (subj, pred, obj)
31 else:
32 g = rdfGraphBody(self.request.body, self.request.headers)
33 assert len(g) == 1, len(g)
34 stmt = g.triples((None, None, None)).next()
35 self._onStatement(user, stmt)
36 post = put
37
38 def _onStatement(self, user, stmt):
39 # write rfid to new key, etc.
40 if stmt[1] == ROOM['keyContents']:
41 return
42 log.warn("ignoring %s", stmt)
43
44 sensor = ROOM['frontDoorWindowRfid']
45
46 class ReadLoop(object):
47 def __init__(self, reader, masterGraph):
48 self.reader = reader
49 self.masterGraph = masterGraph
50 self.log = {} # cardIdUri : most recent seentime
51
52 self.pollPeriodSecs = .2
53 self.expireSecs = 2
54
55 task.LoopingCall(self.poll).start(self.pollPeriodSecs)
56
57 def poll(self):
58 now = time.time()
59
60 self.flushOldReads(now)
61
62 card_id, text = self.reader.read()
63 if card_id is None:
64 return
65
66 cardIdUri = URIRef('http://bigasterisk.com/rfidCard/%s' % card_id)
67 textLit = Literal(text.rstrip())
68
69 is_new = cardIdUri not in self.log
70 self.log[cardIdUri] = now
71 if is_new:
72 self.startCardRead(cardIdUri, textLit)
73
74 def flushOldReads(self, now):
75 for uri in self.log.keys():
76 if self.log[uri] < now - self.expireSecs:
77 self.endCardRead(uri)
78 del self.log[uri]
79
80 def startCardRead(self, cardUri, text):
81 p = Patch(addQuads=[(sensor, ROOM['reading'], cardUri, ctx),
82 (cardUri, ROOM['cardText'], text, ctx)], delQuads=[])
83 self.masterGraph.patch(p)
84 self._sendOneshot([(sensor, ROOM['startReading'], cardUri),
85 (cardUri, ROOM['cardText'], text)])
86
87 def endCardRead(self, cardUri):
88 delQuads = []
89 for spo in self.masterGraph._graph.triples((sensor, ROOM['reading'], cardUri)):
90 delQuads.append(spo + (ctx,))
91 for spo in self.masterGraph._graph.triples((cardUri, ROOM['cardText'], None)):
92 delQuads.append(spo + (ctx,))
93
94 self.masterGraph.patch(Patch(addQuads=[], delQuads=delQuads))
95
96 def _sendOneshot(self, oneshot):
97 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3())
98 for s,p,o in oneshot)).encode('utf8')
99 url = 'http://bang6:9071/oneShot'
100 d = fetch(method='POST',
101 url=url,
102 headers={'Content-Type': ['text/n3']},
103 postdata=body,
104 timeout=5)
105 def err(e):
106 log.info('oneshot post to %r failed: %s',
107 url, e.getErrorMessage())
108 d.addErrback(err)
109
110
111
112 if __name__ == '__main__':
113 arg = docopt("""
114 Usage: rfid.py [options]
115
116 -v Verbose
117 """)
118 log.setLevel(logging.INFO)
119 if arg['-v']:
120 enableTwistedLog()
121 log.setLevel(logging.DEBUG)
122
123 masterGraph = PatchableGraph()
124 reader = SimpleMFRC522()
125
126 loop = ReadLoop(reader, masterGraph)
127
128 port = 10012
129 reactor.listenTCP(port, cyclone.web.Application([
130 (r"/()", cyclone.web.StaticFileHandler,
131 {"path": ".", "default_filename": "index.html"}),
132 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}),
133 (r"/graph/events", CycloneGraphEventsHandler,
134 {'masterGraph': masterGraph}),
135 (r'/output', OutputPage),
136 ], masterGraph=masterGraph, debug=arg['-v']), interface='::')
137 log.warn('serving on %s', port)
138
139 reactor.run()