comparison service/frontDoorLock/front_door_lock.py @ 379:67cebf7a14de

frontdoor autolock. logging improvements. use simpler mqtt interface. Ignore-this: e2bf5262a89ebb898108a634679fdec7
author drewp@bigasterisk.com
date Wed, 12 Dec 2018 01:11:54 -0800
parents 5b690bfc31b2
children d495d4382a07
comparison
equal deleted inserted replaced
378:b90d9321d2ce 379:67cebf7a14de
1 from docopt import docopt 1 from docopt import docopt
2 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler 2 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
3 from rdflib import Namespace, URIRef, Literal, Graph 3 from rdflib import Namespace, URIRef, Literal, Graph
4 from rdflib.parser import StringInputSource 4 from rdflib.parser import StringInputSource
5 from twisted.internet import reactor 5 from twisted.internet import reactor, task
6 import cyclone.web 6 import cyclone.web
7 import sys, logging 7 import sys, logging, time
8 from mqtt_client import MqttClient 8 from mqtt_client import MqttClient
9 from logsetup import log, enableTwistedLog
9 10
10 ROOM = Namespace('http://projects.bigasterisk.com/room/') 11 ROOM = Namespace('http://projects.bigasterisk.com/room/')
11
12 logging.basicConfig()
13 log = logging.getLogger()
14 12
15 ctx = ROOM['frontDoorControl'] 13 ctx = ROOM['frontDoorControl']
16 14
17 def rdfGraphBody(body, headers): 15 def rdfGraphBody(body, headers):
18 g = Graph() 16 g = Graph()
42 else: 40 else:
43 g = rdfGraphBody(self.request.body, self.request.headers) 41 g = rdfGraphBody(self.request.body, self.request.headers)
44 assert len(g) == 1, len(g) 42 assert len(g) == 1, len(g)
45 stmt = g.triples((None, None, None)).next() 43 stmt = g.triples((None, None, None)).next()
46 self._onStatement(stmt) 44 self._onStatement(stmt)
47 45 post = put
46
48 def _onStatement(self, stmt): 47 def _onStatement(self, stmt):
49 if stmt[0:2] == (ROOM['frontDoorLock'], ROOM['state']): 48 if stmt[0:2] == (ROOM['frontDoorLock'], ROOM['state']):
50 self.settings.mqtt.publish("frontdoor/switch/strike/command", 49 self.settings.mqtt.publish("frontdoor/switch/strike/command",
51 mqttMessageFromState(stmt[2])) 50 mqttMessageFromState(stmt[2]))
52 self.settings.masterGraph.patchObject(ctx,
53 stmt[0], stmt[1], stmt[2])
54 return 51 return
55 log.warn("ignoring %s", stmt) 52 log.warn("ignoring %s", stmt)
53
54
55 class AutoLock(object):
56 def __init__(self, masterGraph, mqtt):
57 self.masterGraph = masterGraph
58 self.mqtt = mqtt
59 self.timeUnlocked = None
60 self.autoLockSec = 5
61 self.subj = ROOM['frontDoorLock']
62 task.LoopingCall(self.check).start(1)
63
64 def check(self):
65 now = time.time()
66 state = self.masterGraph._graph.value(self.subj, ROOM['state'])
67 if state == ROOM['unlocked']:
68 if self.timeUnlocked is None:
69 self.timeUnlocked = now
70 unlockedFor = now - self.timeUnlocked
71 self.masterGraph.patchObject(ctx, self.subj, ROOM['unlockedForSec'],
72 Literal(int(unlockedFor)))
73 self.masterGraph.patchObject(ctx, self.subj, ROOM['autoLockInSec'],
74 Literal(self.autoLockSec - int(unlockedFor)))
75 if unlockedFor > self.autoLockSec:
76 self.mqtt.publish("frontdoor/switch/strike/command",
77 mqttMessageFromState(ROOM['locked']))
78 else:
79 self.timeUnlocked = None
80 self.masterGraph.patchObject(ctx, self.subj, ROOM['unlockedForSec'], None)
81 self.masterGraph.patchObject(ctx, self.subj, ROOM['autoLockInSec'], None)
82
56 83
57 if __name__ == '__main__': 84 if __name__ == '__main__':
58 arg = docopt(""" 85 arg = docopt("""
59 Usage: front_door_lock.py [options] 86 Usage: front_door_lock.py [options]
60 87
61 -v Verbose 88 -v Verbose
62 """) 89 """)
63 log.setLevel(logging.WARN) 90 log.setLevel(logging.INFO)
64 if arg['-v']: 91 if arg['-v']:
65 from twisted.python import log as twlog 92 enableTwistedLog()
66 twlog.startLogging(sys.stdout)
67 log.setLevel(logging.DEBUG) 93 log.setLevel(logging.DEBUG)
68 94
69 masterGraph = PatchableGraph() 95 masterGraph = PatchableGraph()
70 mqtt = MqttClient(brokerPort=10010) 96 mqtt = MqttClient(brokerPort=10010)
97 autoclose = AutoLock(masterGraph, mqtt)
71 98
72 def toGraph(payload): 99 def toGraph(payload):
73 log.debug('toGraph %r', payload) 100 log.info('mqtt->graph %r', payload)
74 masterGraph.patchObject(ctx, ROOM['frontDoorLock'], ROOM['state'], 101 masterGraph.patchObject(ctx, ROOM['frontDoorLock'], ROOM['state'],
75 stateFromMqtt(payload)) 102 stateFromMqtt(payload))
76 103
77 mqtt.subscribe("frontdoor/switch/strike/state").subscribe(on_next=toGraph) 104 mqtt.subscribe("frontdoor/switch/strike/state").subscribe(on_next=toGraph)
78 port = 10011 105 port = 10011
79 reactor.listenTCP(port, cyclone.web.Application([ 106 reactor.listenTCP(port, cyclone.web.Application([
107 (r"/()", cyclone.web.StaticFileHandler,
108 {"path": ".", "default_filename": "index.html"}),
80 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}), 109 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}),
81 (r"/graph/events", CycloneGraphEventsHandler, 110 (r"/graph/events", CycloneGraphEventsHandler,
82 {'masterGraph': masterGraph}), 111 {'masterGraph': masterGraph}),
83 (r'/output', OutputPage), 112 (r'/output', OutputPage),
84 ], mqtt=mqtt, masterGraph=masterGraph, debug=arg['-v']), interface='::') 113 ], mqtt=mqtt, masterGraph=masterGraph, debug=arg['-v']), interface='::')