Mercurial > code > home > repos > homeauto
comparison service/frontDoorLock/front_door_lock.py @ 1366:5836e88a0287
py3 and new build
Ignore-this: 69cf69e5d43adfa65b3f62c5c0af2014
darcs-hash:a82563e9bfce399590ffd2229d997b490c0b038d
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Wed, 01 May 2019 00:30:54 -0700 |
parents | e6c6574f3d24 |
children | 2d8a5532f1b5 |
comparison
equal
deleted
inserted
replaced
1365:e6c6574f3d24 | 1366:5836e88a0287 |
---|---|
4 | 4 |
5 put :frontDoorLock :state ?s to this /output to request a change. | 5 put :frontDoorLock :state ?s to this /output to request a change. |
6 | 6 |
7 reasoning can infer :frontDoorLock :putState ?s to do that put request. | 7 reasoning can infer :frontDoorLock :putState ?s to do that put request. |
8 """ | 8 """ |
9 import time, json | |
10 | |
9 from docopt import docopt | 11 from docopt import docopt |
10 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler | |
11 from rdflib import Namespace, URIRef, Literal, Graph | 12 from rdflib import Namespace, URIRef, Literal, Graph |
12 from rdflib.parser import StringInputSource | 13 from rdflib.parser import StringInputSource |
13 from twisted.internet import reactor, task | 14 from twisted.internet import reactor, task |
14 import cyclone.web | 15 import cyclone.web |
15 import logging, time, json | 16 |
16 from mqtt_client import MqttClient | 17 from mqtt_client import MqttClient |
17 from logsetup import log, enableTwistedLog | 18 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler |
19 from standardservice.logsetup import log, verboseLogging | |
18 | 20 |
19 ROOM = Namespace('http://projects.bigasterisk.com/room/') | 21 ROOM = Namespace('http://projects.bigasterisk.com/room/') |
20 | 22 |
21 ctx = ROOM['frontDoorControl'] | 23 ctx = ROOM['frontDoorControl'] |
22 | 24 |
23 def rdfGraphBody(body, headers): | 25 def rdfGraphBody(body, headers): |
24 g = Graph() | 26 g = Graph() |
25 g.parse(StringInputSource(body), format='nt') | 27 g.parse(StringInputSource(body), format='nt') |
26 return g | 28 return g |
27 | 29 |
28 def mqttMessageFromState(state): | 30 def mqttMessageFromState(state: URIRef): |
29 return { | 31 return { |
30 ROOM['locked']: b'OFF', | 32 ROOM['locked']: b'OFF', |
31 ROOM['unlocked']: b'ON', | 33 ROOM['unlocked']: b'ON', |
32 }[state] | 34 }[state] |
33 | 35 |
34 def stateFromMqtt(msg): | 36 def stateFromMqtt(msg: bytes): |
35 return { | 37 return { |
36 'OFF': ROOM['locked'], | 38 b'OFF': ROOM['locked'], |
37 'ON': ROOM['unlocked'], | 39 b'ON': ROOM['unlocked'], |
38 }[msg.decode('ascii')] | 40 }[bytes(msg)] |
39 | 41 |
40 class OutputPage(cyclone.web.RequestHandler): | 42 class OutputPage(cyclone.web.RequestHandler): |
41 def put(self): | 43 def put(self): |
42 try: | 44 try: |
43 user = URIRef(self.request.headers['x-foaf-agent']) | 45 # what happened to the case-insens dict? |
46 h = dict((k.lower(), v) for k,v in self.request.headers.items()) | |
47 user = URIRef(h['x-foaf-agent']) | |
44 except KeyError: | 48 except KeyError: |
45 log.warn('request without x-foaf-agent: %s', self.request.headers) | 49 log.warn('request without x-foaf-agent: %s', h) |
46 self.set_status(403, 'need x-foaf-agent') | 50 self.set_status(403, 'need x-foaf-agent') |
47 return | 51 return |
48 arg = self.request.arguments | 52 arg = self.request.arguments |
49 if arg.get('s') and arg.get('p'): | 53 if arg.get('s') and arg.get('p'): |
50 subj = URIRef(arg['s'][-1]) | 54 subj = URIRef(arg['s'][-1]) |
51 pred = URIRef(arg['p'][-1]) | 55 pred = URIRef(arg['p'][-1]) |
52 obj = URIRef(self.request.body) | 56 obj = URIRef(self.request.body.strip().decode('ascii')) |
53 stmt = (subj, pred, obj) | 57 stmt = (subj, pred, obj) |
54 else: | 58 else: |
55 g = rdfGraphBody(self.request.body, self.request.headers) | 59 g = rdfGraphBody(self.request.body, self.request.headers) |
56 assert len(g) == 1, len(g) | 60 assert len(g) == 1, len(g) |
57 stmt = g.triples((None, None, None)).next() | 61 stmt = next(g.triples((None, None, None))) |
58 self._onStatement(user, stmt) | 62 self._onStatement(user, stmt) |
59 post = put | 63 post = put |
60 | 64 |
61 def _onStatement(self, user, stmt): | 65 def _onStatement(self, user, stmt): |
62 log.info('put statement %r', stmt) | 66 log.info('put statement %r', stmt) |
64 if stmt[2] == ROOM['unlocked']: | 68 if stmt[2] == ROOM['unlocked']: |
65 log.info('unlock for %r', user) | 69 log.info('unlock for %r', user) |
66 self.settings.autoLock.onUnlockedStmt() | 70 self.settings.autoLock.onUnlockedStmt() |
67 if stmt[2] == ROOM['locked']: | 71 if stmt[2] == ROOM['locked']: |
68 self.settings.autoLock.onLockedStmt() | 72 self.settings.autoLock.onLockedStmt() |
69 self.settings.mqtt.publish("frontdoor/switch/strike/command", | 73 self.settings.mqtt.publish(b"frontdoor/switch/strike/command", |
70 mqttMessageFromState(stmt[2])) | 74 mqttMessageFromState(stmt[2])) |
71 return | 75 return |
72 log.warn("ignoring %s", stmt) | 76 log.warn("ignoring %s", stmt) |
73 | 77 |
74 | 78 |
81 self.subj = ROOM['frontDoorLock'] | 85 self.subj = ROOM['frontDoorLock'] |
82 task.LoopingCall(self.pollCheck).start(1) | 86 task.LoopingCall(self.pollCheck).start(1) |
83 | 87 |
84 def relock(self): | 88 def relock(self): |
85 log.info('autolock is up: requesting lock') | 89 log.info('autolock is up: requesting lock') |
86 self.mqtt.publish("frontdoor/switch/strike/command", | 90 self.mqtt.publish(b"frontdoor/switch/strike/command", |
87 mqttMessageFromState(ROOM['locked'])) | 91 mqttMessageFromState(ROOM['locked'])) |
88 | 92 |
89 def reportTimes(self, unlockedFor): | 93 def reportTimes(self, unlockedFor): |
90 g = self.masterGraph | 94 g = self.masterGraph |
91 lockIn = self.autoLockSec - int(unlockedFor) | 95 lockIn = self.autoLockSec - int(unlockedFor) |
142 def post(self): | 146 def post(self): |
143 body = json.loads(self.request.body) | 147 body = json.loads(self.request.body) |
144 log.info('POST bluetoothButton %r', body) | 148 log.info('POST bluetoothButton %r', body) |
145 if body['addr'] == 'zz:zz:zz:zz:zz:zz' and body['key'] == 'top': | 149 if body['addr'] == 'zz:zz:zz:zz:zz:zz' and body['key'] == 'top': |
146 log.info('unlock for %r', body['addr']) | 150 log.info('unlock for %r', body['addr']) |
147 self.settings.mqtt.publish("frontdoor/switch/strike/command", 'ON') | 151 self.settings.mqtt.publish( |
152 b"frontdoor/switch/strike/command", b'ON') | |
148 | 153 |
149 | 154 |
150 if __name__ == '__main__': | 155 if __name__ == '__main__': |
151 arg = docopt(""" | 156 arg = docopt(""" |
152 Usage: front_door_lock.py [options] | 157 Usage: front_door_lock.py [options] |
153 | 158 |
154 -v Verbose | 159 -v Verbose |
155 """) | 160 """) |
156 log.setLevel(logging.INFO) | 161 verboseLogging(arg['-v']) |
157 if arg['-v']: | |
158 enableTwistedLog() | |
159 log.setLevel(logging.DEBUG) | |
160 | 162 |
161 masterGraph = PatchableGraph() | 163 masterGraph = PatchableGraph() |
162 mqtt = MqttClient(brokerPort=10010) | 164 mqtt = MqttClient(brokerPort=10010) |
163 autoclose = AutoLock(masterGraph, mqtt) | 165 autoclose = AutoLock(masterGraph, mqtt) |
164 | 166 |
165 def toGraph(payload): | 167 def toGraph(payload): |
166 log.info('mqtt->graph %r', payload) | 168 log.info('mqtt->graph %r', payload) |
167 masterGraph.patchObject(ctx, ROOM['frontDoorLock'], ROOM['state'], | 169 masterGraph.patchObject(ctx, ROOM['frontDoorLock'], ROOM['state'], |
168 stateFromMqtt(payload)) | 170 stateFromMqtt(payload)) |
169 | 171 |
170 mqtt.subscribe("frontdoor/switch/strike/state").subscribe(on_next=toGraph) | 172 mqtt.subscribe(b"frontdoor/switch/strike/state").subscribe(on_next=toGraph) |
171 port = 10011 | 173 port = 10011 |
172 reactor.listenTCP(port, cyclone.web.Application( | 174 reactor.listenTCP(port, cyclone.web.Application( |
173 [ | 175 [ |
174 (r"/()", cyclone.web.StaticFileHandler, | 176 (r"/()", cyclone.web.StaticFileHandler, |
175 {"path": ".", "default_filename": "index.html"}), | 177 {"path": ".", "default_filename": "index.html"}), |