Mercurial > code > home > repos > homeauto
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() |