Mercurial > code > home > repos > homeauto
annotate service/rfid/rfid.py @ 1524:13b7e4de3824
whitespace
Ignore-this: c727f388f197a6fae88595fe6d455c7d
darcs-hash:971e4474b4dbd35a722be670f5599298fb5ec83f
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Wed, 05 Feb 2020 00:29:13 -0800 |
parents | 0da337780f22 |
children |
rev | line source |
---|---|
1194 | 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 | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
9 import logging, time, json, random, string |
1194 | 10 from MFRC522.SimpleMFRC522 import SimpleMFRC522 |
11 from logsetup import log, enableTwistedLog | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
12 import private |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
13 from greplin import scales |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
14 from greplin.scales.cyclonehandler import StatsHandler |
1194 | 15 |
16 ROOM = Namespace('http://projects.bigasterisk.com/room/') | |
17 | |
18 ctx = ROOM['frontDoorWindowRfidCtx'] | |
19 | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
20 cardOwner = { |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
21 URIRef('http://bigasterisk.com/rfidCard/93a7591a77'): |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
22 URIRef('http://bigasterisk.com/foaf.rdf#drewp'), |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
23 } |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
24 |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
25 STATS = scales.collection('/web', |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
26 scales.PmfStat('cardReadPoll'), |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
27 ) |
1194 | 28 def rdfGraphBody(body, headers): |
29 g = Graph() | |
30 g.parse(StringInputSource(body), format='nt') | |
31 return g | |
32 | |
33 class OutputPage(cyclone.web.RequestHandler): | |
34 def put(self): | |
35 user = URIRef(self.request.headers['x-foaf-agent']) | |
36 arg = self.request.arguments | |
37 if arg.get('s') and arg.get('p'): | |
38 subj = URIRef(arg['s'][-1]) | |
39 pred = URIRef(arg['p'][-1]) | |
40 obj = URIRef(self.request.body) | |
41 stmt = (subj, pred, obj) | |
42 else: | |
43 g = rdfGraphBody(self.request.body, self.request.headers) | |
44 assert len(g) == 1, len(g) | |
45 stmt = g.triples((None, None, None)).next() | |
46 self._onStatement(user, stmt) | |
47 post = put | |
1524 | 48 |
1194 | 49 def _onStatement(self, user, stmt): |
50 # write rfid to new key, etc. | |
51 if stmt[1] == ROOM['keyContents']: | |
52 return | |
53 log.warn("ignoring %s", stmt) | |
54 | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
55 def uidUri(card_id): |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
56 return URIRef('http://bigasterisk.com/rfidCard/%010x' % card_id) |
1524 | 57 |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
58 def uidArray(uri): |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
59 prefix, h = uri.rsplit('/', 1) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
60 if prefix != 'http://bigasterisk.com/rfidCard': |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
61 raise ValueError(uri) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
62 return [int(h[i * 2: i * 2 + 2], 16) for i in range(0, len(h), 2)] |
1524 | 63 |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
64 class Rewrite(cyclone.web.RequestHandler): |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
65 def post(self): |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
66 agent = URIRef(self.request.headers['x-foaf-agent']) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
67 body = json.loads(self.request.body) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
68 |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
69 _, uid = reader.read_id() |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
70 log.info('current card id: %r %r', _, uid) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
71 if uid is None: |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
72 self.set_status(404, "no card present") |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
73 # maybe retry a few more times since the card might be nearby |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
74 return |
1524 | 75 |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
76 text = ''.join(random.choice(string.uppercase) for n in range(32)) |
1524 | 77 log.info('%s rewrites %s to %s, to be owned by %s', |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
78 agent, uid, text, body['user']) |
1524 | 79 |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
80 #reader.KEY = private.rfid_key |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
81 reader.write(uid, text) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
82 log.info('done with write') |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
83 |
1524 | 84 |
1194 | 85 sensor = ROOM['frontDoorWindowRfid'] |
86 | |
87 class ReadLoop(object): | |
88 def __init__(self, reader, masterGraph): | |
89 self.reader = reader | |
90 self.masterGraph = masterGraph | |
91 self.log = {} # cardIdUri : most recent seentime | |
92 | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
93 self.pollPeriodSecs = .1 |
1194 | 94 self.expireSecs = 2 |
1524 | 95 |
1194 | 96 task.LoopingCall(self.poll).start(self.pollPeriodSecs) |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
97 |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
98 @STATS.cardReadPoll.time() |
1194 | 99 def poll(self): |
100 now = time.time() | |
101 | |
102 self.flushOldReads(now) | |
103 | |
104 card_id, text = self.reader.read() | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
105 if card_id is None or text == '': |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
106 # text=='' could be legit, but it's probably a card that's |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
107 # still being read. |
1194 | 108 return |
109 | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
110 cardIdUri = uidUri(card_id) |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
111 textLit = Literal(text.rstrip().decode('ascii', 'replace')) |
1194 | 112 |
113 is_new = cardIdUri not in self.log | |
114 self.log[cardIdUri] = now | |
115 if is_new: | |
116 self.startCardRead(cardIdUri, textLit) | |
1524 | 117 |
1194 | 118 def flushOldReads(self, now): |
119 for uri in self.log.keys(): | |
120 if self.log[uri] < now - self.expireSecs: | |
121 self.endCardRead(uri) | |
122 del self.log[uri] | |
123 | |
124 def startCardRead(self, cardUri, text): | |
125 p = Patch(addQuads=[(sensor, ROOM['reading'], cardUri, ctx), | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
126 (cardUri, ROOM['cardText'], text, ctx)], |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
127 delQuads=[]) |
1194 | 128 self.masterGraph.patch(p) |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
129 log.info('read card: id=%s %r', cardUri, str(text)) |
1194 | 130 self._sendOneshot([(sensor, ROOM['startReading'], cardUri), |
131 (cardUri, ROOM['cardText'], text)]) | |
132 | |
133 def endCardRead(self, cardUri): | |
134 delQuads = [] | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
135 for spo in self.masterGraph._graph.triples( |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
136 (sensor, ROOM['reading'], cardUri)): |
1194 | 137 delQuads.append(spo + (ctx,)) |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
138 for spo in self.masterGraph._graph.triples( |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
139 (cardUri, ROOM['cardText'], None)): |
1194 | 140 delQuads.append(spo + (ctx,)) |
1524 | 141 |
1194 | 142 self.masterGraph.patch(Patch(addQuads=[], delQuads=delQuads)) |
1524 | 143 |
1194 | 144 def _sendOneshot(self, oneshot): |
145 body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3()) | |
146 for s,p,o in oneshot)).encode('utf8') | |
147 url = 'http://bang6:9071/oneShot' | |
148 d = fetch(method='POST', | |
149 url=url, | |
150 headers={'Content-Type': ['text/n3']}, | |
151 postdata=body, | |
152 timeout=5) | |
153 def err(e): | |
154 log.info('oneshot post to %r failed: %s', | |
155 url, e.getErrorMessage()) | |
156 d.addErrback(err) | |
157 | |
1524 | 158 |
159 | |
1194 | 160 if __name__ == '__main__': |
161 arg = docopt(""" | |
162 Usage: rfid.py [options] | |
163 | |
164 -v Verbose | |
165 """) | |
166 log.setLevel(logging.INFO) | |
167 if arg['-v']: | |
168 enableTwistedLog() | |
169 log.setLevel(logging.DEBUG) | |
170 | |
171 masterGraph = PatchableGraph() | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
172 reader = SimpleMFRC522(gain=0x07) |
1194 | 173 |
174 loop = ReadLoop(reader, masterGraph) | |
175 | |
176 port = 10012 | |
177 reactor.listenTCP(port, cyclone.web.Application([ | |
178 (r"/()", cyclone.web.StaticFileHandler, | |
179 {"path": ".", "default_filename": "index.html"}), | |
1523
0da337780f22
dep updates; graph url renames; and other build updates
drewp <drewp@bigasterisk.com>
parents:
1264
diff
changeset
|
180 (r"/graph/rfid", CycloneGraphHandler, {'masterGraph': masterGraph}), |
0da337780f22
dep updates; graph url renames; and other build updates
drewp <drewp@bigasterisk.com>
parents:
1264
diff
changeset
|
181 (r"/graph/rfid/events", CycloneGraphEventsHandler, |
1194 | 182 {'masterGraph': masterGraph}), |
183 (r'/output', OutputPage), | |
1264
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
184 (r'/rewrite', Rewrite), |
c5b13d630d90
last version of rc522 reader; i moved onto pn532 now
drewp <drewp@bigasterisk.com>
parents:
1194
diff
changeset
|
185 (r'/stats/(.*)', StatsHandler, {'serverName': 'rfid'}), |
1194 | 186 ], masterGraph=masterGraph, debug=arg['-v']), interface='::') |
187 log.warn('serving on %s', port) | |
188 | |
189 reactor.run() |