Mercurial > code > home > repos > homeauto
changeset 389:bba6672a0ef8
rfid reader service
Ignore-this: 26df9a4be891c26722311cf89d1d7cf7
author | drewp@bigasterisk.com |
---|---|
date | Thu, 03 Jan 2019 21:52:27 -0800 |
parents | c146fa2bc7d4 |
children | e220d5c875b3 |
files | service/rfid/Dockerfile service/rfid/Dockerfile.pi service/rfid/index.html service/rfid/makefile service/rfid/requirements.txt service/rfid/rfid.py |
diffstat | 6 files changed, 210 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/Dockerfile Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,15 @@ +FROM bang6:5000/base_x86 + +WORKDIR /opt + + + +COPY requirements.txt . + +RUN pip install -r requirements.txt + +COPY *.py *.html *.js ./ + +EXPOSE 10012 + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/Dockerfile.pi Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,12 @@ +FROM bang6:5000/base_pi + +WORKDIR /opt + +COPY requirements.txt . + +RUN pip install -r requirements.txt + +COPY *.py *.html *.js ./ + +EXPOSE 10012 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/index.html Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,14 @@ +<!doctype html> +<html> + <head> + <title></title> + <meta charset="utf-8" /> + </head> + <body> + + Current read: graph.sensor.card graph.sensor.card.text + + Write new key: [random id] [Write] + + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/makefile Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,24 @@ +SERVICE=rfid + +build_image: + rm -rf tmp_ctx + mkdir -p tmp_ctx + cp -a Dockerfile ../../lib/*.py *.py *.txt *.html MFRC522-python tmp_ctx + docker build --network=host -t bang6:5000/$(SERVICE)_x86:latest tmp_ctx + docker push bang6:5000/$(SERVICE)_x86:latest + rm -rf tmp_ctx + + +build_image_pi: + rm -rf tmp_ctx + mkdir -p tmp_ctx + cp -a Dockerfile.pi ../../lib/*.py *.py *.txt *.html MFRC522-python tmp_ctx + docker build --file Dockerfile.pi --network=host -t bang6:5000/$(SERVICE)_pi:latest tmp_ctx + docker push bang6:5000/$(SERVICE)_pi:latest + rm -rf tmp_ctx + +shell: + docker run --rm -it --cap-add SYS_PTRACE --net=host bang6:5000/$(SERVICE)_x86:latest /bin/sh + +local_run: + docker run --rm -it --net=host bang6:5000/$(SERVICE)_x86:latest
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/requirements.txt Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,6 @@ +cyclone +rdflib-jsonld==0.4.0 +rdflib==4.2.2 +https://projects.bigasterisk.com/rdfdb/rdfdb-0.6.0.tar.gz +https://github.com/drewp/MFRC522-python/archive/drewp/m4.zip +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid/rfid.py Thu Jan 03 21:52:27 2019 -0800 @@ -0,0 +1,139 @@ +from docopt import docopt +from rdfdb.patch import Patch +from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler +from rdflib import Namespace, URIRef, Literal, Graph +from rdflib.parser import StringInputSource +from twisted.internet import reactor, task +import cyclone.web +from cyclone.httpclient import fetch +import logging, time +from MFRC522.SimpleMFRC522 import SimpleMFRC522 +from logsetup import log, enableTwistedLog + +ROOM = Namespace('http://projects.bigasterisk.com/room/') + +ctx = ROOM['frontDoorWindowRfidCtx'] + +def rdfGraphBody(body, headers): + g = Graph() + g.parse(StringInputSource(body), format='nt') + return g + +class OutputPage(cyclone.web.RequestHandler): + def put(self): + user = URIRef(self.request.headers['x-foaf-agent']) + arg = self.request.arguments + if arg.get('s') and arg.get('p'): + subj = URIRef(arg['s'][-1]) + pred = URIRef(arg['p'][-1]) + obj = URIRef(self.request.body) + stmt = (subj, pred, obj) + else: + g = rdfGraphBody(self.request.body, self.request.headers) + assert len(g) == 1, len(g) + stmt = g.triples((None, None, None)).next() + self._onStatement(user, stmt) + post = put + + def _onStatement(self, user, stmt): + # write rfid to new key, etc. + if stmt[1] == ROOM['keyContents']: + return + log.warn("ignoring %s", stmt) + +sensor = ROOM['frontDoorWindowRfid'] + +class ReadLoop(object): + def __init__(self, reader, masterGraph): + self.reader = reader + self.masterGraph = masterGraph + self.log = {} # cardIdUri : most recent seentime + + self.pollPeriodSecs = .2 + self.expireSecs = 2 + + task.LoopingCall(self.poll).start(self.pollPeriodSecs) + + def poll(self): + now = time.time() + + self.flushOldReads(now) + + card_id, text = self.reader.read() + if card_id is None: + return + + cardIdUri = URIRef('http://bigasterisk.com/rfidCard/%s' % card_id) + textLit = Literal(text.rstrip()) + + is_new = cardIdUri not in self.log + self.log[cardIdUri] = now + if is_new: + self.startCardRead(cardIdUri, textLit) + + def flushOldReads(self, now): + for uri in self.log.keys(): + if self.log[uri] < now - self.expireSecs: + self.endCardRead(uri) + del self.log[uri] + + def startCardRead(self, cardUri, text): + p = Patch(addQuads=[(sensor, ROOM['reading'], cardUri, ctx), + (cardUri, ROOM['cardText'], text, ctx)], delQuads=[]) + self.masterGraph.patch(p) + self._sendOneshot([(sensor, ROOM['startReading'], cardUri), + (cardUri, ROOM['cardText'], text)]) + + def endCardRead(self, cardUri): + delQuads = [] + for spo in self.masterGraph._graph.triples((sensor, ROOM['reading'], cardUri)): + delQuads.append(spo + (ctx,)) + for spo in self.masterGraph._graph.triples((cardUri, ROOM['cardText'], None)): + delQuads.append(spo + (ctx,)) + + self.masterGraph.patch(Patch(addQuads=[], delQuads=delQuads)) + + def _sendOneshot(self, oneshot): + body = (' '.join('%s %s %s .' % (s.n3(), p.n3(), o.n3()) + for s,p,o in oneshot)).encode('utf8') + url = 'http://bang6:9071/oneShot' + d = fetch(method='POST', + url=url, + headers={'Content-Type': ['text/n3']}, + postdata=body, + timeout=5) + def err(e): + log.info('oneshot post to %r failed: %s', + url, e.getErrorMessage()) + d.addErrback(err) + + + +if __name__ == '__main__': + arg = docopt(""" + Usage: rfid.py [options] + + -v Verbose + """) + log.setLevel(logging.INFO) + if arg['-v']: + enableTwistedLog() + log.setLevel(logging.DEBUG) + + masterGraph = PatchableGraph() + reader = SimpleMFRC522() + + loop = ReadLoop(reader, masterGraph) + + port = 10012 + reactor.listenTCP(port, cyclone.web.Application([ + (r"/()", cyclone.web.StaticFileHandler, + {"path": ".", "default_filename": "index.html"}), + (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}), + (r"/graph/events", CycloneGraphEventsHandler, + {'masterGraph': masterGraph}), + (r'/output', OutputPage), + ], masterGraph=masterGraph, debug=arg['-v']), interface='::') + log.warn('serving on %s', port) + + reactor.run()