changeset 1184:c87e5c8eb8ab

frontdoor autolock. logging improvements. use simpler mqtt interface. Ignore-this: e2bf5262a89ebb898108a634679fdec7 darcs-hash:4864716cd06f14c5ad5ef7e0e7bc51458603012b
author drewp <drewp@bigasterisk.com>
date Wed, 12 Dec 2018 01:11:54 -0800
parents 6561367aa60a
children 56bca87ed939
files service/frontDoorLock/Dockerfile service/frontDoorLock/front_door_lock.py service/frontDoorLock/index.html service/frontDoorLock/makefile service/frontDoorLock/requirements.txt
diffstat 5 files changed, 166 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/service/frontDoorLock/Dockerfile	Wed Dec 12 01:10:48 2018 -0800
+++ b/service/frontDoorLock/Dockerfile	Wed Dec 12 01:11:54 2018 -0800
@@ -9,4 +9,4 @@
 
 EXPOSE 10011:10011
 
-CMD [ "python", "./front_door_lock.py", "-v" ]
+CMD [ "python", "./front_door_lock.py" ]
--- a/service/frontDoorLock/front_door_lock.py	Wed Dec 12 01:10:48 2018 -0800
+++ b/service/frontDoorLock/front_door_lock.py	Wed Dec 12 01:11:54 2018 -0800
@@ -2,16 +2,14 @@
 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
 from rdflib import Namespace, URIRef, Literal, Graph
 from rdflib.parser import StringInputSource
-from twisted.internet import reactor
+from twisted.internet import reactor, task
 import cyclone.web
-import sys, logging
+import sys, logging, time
 from mqtt_client import MqttClient
+from logsetup import log, enableTwistedLog
 
 ROOM = Namespace('http://projects.bigasterisk.com/room/')
 
-logging.basicConfig()
-log = logging.getLogger()
-
 ctx = ROOM['frontDoorControl']
 
 def rdfGraphBody(body, headers):
@@ -44,15 +42,44 @@
             assert len(g) == 1, len(g)
             stmt = g.triples((None, None, None)).next()
         self._onStatement(stmt)
-            
+    post = put
+    
     def _onStatement(self, stmt):
         if stmt[0:2] == (ROOM['frontDoorLock'], ROOM['state']):
             self.settings.mqtt.publish("frontdoor/switch/strike/command",
                                        mqttMessageFromState(stmt[2]))
-            self.settings.masterGraph.patchObject(ctx,
-                                                  stmt[0], stmt[1], stmt[2])
             return
         log.warn("ignoring %s", stmt)
+
+
+class AutoLock(object):
+    def __init__(self, masterGraph, mqtt):
+        self.masterGraph = masterGraph
+        self.mqtt = mqtt
+        self.timeUnlocked = None
+        self.autoLockSec = 5
+        self.subj = ROOM['frontDoorLock']
+        task.LoopingCall(self.check).start(1)
+
+    def check(self):
+        now = time.time()
+        state = self.masterGraph._graph.value(self.subj, ROOM['state'])
+        if state == ROOM['unlocked']:
+            if self.timeUnlocked is None:
+                self.timeUnlocked = now
+            unlockedFor = now - self.timeUnlocked
+            self.masterGraph.patchObject(ctx, self.subj, ROOM['unlockedForSec'],
+                                         Literal(int(unlockedFor)))
+            self.masterGraph.patchObject(ctx, self.subj, ROOM['autoLockInSec'],
+                                         Literal(self.autoLockSec - int(unlockedFor)))
+            if unlockedFor > self.autoLockSec:
+                self.mqtt.publish("frontdoor/switch/strike/command",
+                                  mqttMessageFromState(ROOM['locked']))
+        else:
+            self.timeUnlocked = None
+            self.masterGraph.patchObject(ctx, self.subj, ROOM['unlockedForSec'], None)
+            self.masterGraph.patchObject(ctx, self.subj, ROOM['autoLockInSec'], None)
+
             
 if __name__ == '__main__':
     arg = docopt("""
@@ -60,23 +87,25 @@
 
     -v   Verbose
     """)
-    log.setLevel(logging.WARN)
+    log.setLevel(logging.INFO)
     if arg['-v']:
-        from twisted.python import log as twlog
-        twlog.startLogging(sys.stdout)
+        enableTwistedLog()
         log.setLevel(logging.DEBUG)
 
     masterGraph = PatchableGraph()
     mqtt = MqttClient(brokerPort=10010)
+    autoclose = AutoLock(masterGraph, mqtt)
 
     def toGraph(payload):
-        log.debug('toGraph %r', payload)
+        log.info('mqtt->graph %r', payload)
         masterGraph.patchObject(ctx, ROOM['frontDoorLock'], ROOM['state'],
                                 stateFromMqtt(payload))
 
     mqtt.subscribe("frontdoor/switch/strike/state").subscribe(on_next=toGraph)
     port = 10011
     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}),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/frontDoorLock/index.html	Wed Dec 12 01:11:54 2018 -0800
@@ -0,0 +1,121 @@
+<!doctype html>
+<html>
+  <head>
+    <title>front door lock</title>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script src="/lib/polymer/1.0.9/webcomponentsjs/webcomponents.min.js"></script>
+    <script src="/lib/require/require-2.3.3.js"></script>
+    <script>
+     requirejs.config({
+       paths: {
+         "streamed-graph": "/rdf/streamed-graph",
+         "quadstore": "/rdf/quadstore",
+         "async-module": "/lib/async/80f1793/async",
+         "async": "/lib/async/80f1793/async",
+         "jsonld-module": "/lib/jsonld.js/0.4.11/js/jsonld",
+         "jsonld": "/lib/jsonld.js/0.4.11/js/jsonld",
+         "rdfstore": "/lib/rdf_store/0.9.7/dist/rdfstore",
+         "moment": "/lib/moment.min",
+         "underscore": "/lib/underscore-1.5.2.min",
+       }
+     });
+    </script>
+    <script>
+     window.NS = {
+       dev: 'http://projects.bigasterisk.com/device/',
+       room: 'http://projects.bigasterisk.com/room/',
+       rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
+       sensor: 'http://bigasterisk.com/homeauto/sensor/',
+     };
+    </script>
+    <link rel="import" href="/rdf/streamed-graph.html">
+    <link rel="import" href="/lib/polymer/1.0.9/polymer/polymer.html">
+    <link rel="import" href="/rdf/rdf-oneshot.html">
+    <link rel="import" href="/rdf/rdf-uri.html">
+  </head>
+  <body>
+    <dom-module id="door-control">
+      <style>
+       button {
+           min-width: 60px;
+           min-height: 40px;
+       }
+       div#form {
+           margin: 20px;
+           background: #dff5e5;
+           padding: 10px;
+           line-height: 40px;
+           text-align: center;
+           border: 2px groove white;
+       }
+      </style>
+      <template>
+        <div>
+          <streamed-graph url="graph/events" graph="{{graph}}"></streamed-graph>
+        </div>
+
+        <div id="form">
+
+          <div>
+            Door is {{lockState}}
+          </div>
+
+          <rdf-oneshot
+            id="unlockOneshot"
+            post="output"
+            subject="<http://projects.bigasterisk.com/room/frontDoorLock>"
+            predicate="<http://projects.bigasterisk.com/room/state>"
+            object="<http://projects.bigasterisk.com/room/unlocked>"
+          ></rdf-oneshot>
+          <button on-click="unlock">Unlock</button>
+          
+          <template is="dom-if" if="{{autoLockIsComing}}">
+            <div>
+              Locking in {{autoLockInSec}}
+            </div>
+          </template>
+        </div>
+      </template>
+      <script>
+       HTMLImports.whenReady(function () {
+         Polymer({
+           is: 'door-control',
+           properties: {
+             graph: { type: Object, notify: true, observer: "_onGraph" },
+             lockState: { type: String },
+             autoLockIsComing: { type: Boolean },
+             autoLockInSec: { type: String},
+           },
+           behaviors: [BigastUri],
+           _onGraph: function(graph) {
+             if (!graph.graph) return;
+             const env = graph.graph.store.rdf;
+             graph.graph.quadStore.quads(
+               {subject: env.createNamedNode('room:frontDoorLock'),
+                predicate: env.createNamedNode('room:state'),
+               },
+               (q) => {
+                 this.lockState = q.object.toString().replace(/.*\//, '');
+               });
+             
+             this.autoLockIsComing = false;
+             graph.graph.quadStore.quads(
+               {subject: env.createNamedNode('room:frontDoorLock'),
+                predicate: env.createNamedNode('room:autoLockInSec'),
+               },
+               (q) => {
+                 this.autoLockIsComing = true;
+                 this.autoLockInSec = parseFloat(q.object.valueOf());
+               });
+           },
+           unlock: function() {
+             this.$.unlockOneshot.go();
+           }
+         });
+       });
+      </script>
+    </dom-module>
+    <door-control></door-control>
+  </body>
+</html>
--- a/service/frontDoorLock/makefile	Wed Dec 12 01:10:48 2018 -0800
+++ b/service/frontDoorLock/makefile	Wed Dec 12 01:11:54 2018 -0800
@@ -6,7 +6,7 @@
 build_image:
 	rm -rf tmp_ctx
 	mkdir -p tmp_ctx
-	cp -a Dockerfile ../../lib/*.py *.py *.txt tmp_ctx
+	cp -a Dockerfile ../../lib/*.py *.py *.txt *.html tmp_ctx
 	docker build --network=host -t ${TAG} tmp_ctx
 	docker push ${TAG}
 	rm -rf tmp_ctx
@@ -16,4 +16,4 @@
 	docker run --rm -it --cap-add SYS_PTRACE --net=host bang6:5000/$(JOB)_x86:latest  /bin/sh
 
 local_run:
-	docker run --rm -it --net=host bang6:5000/$(JOB)_x86:latest
+	docker run --rm -it --net=host -v `pwd`/index.html:/opt/index.html bang6:5000/$(JOB)_x86:latest python ./front_door_lock.py 
--- a/service/frontDoorLock/requirements.txt	Wed Dec 12 01:10:48 2018 -0800
+++ b/service/frontDoorLock/requirements.txt	Wed Dec 12 01:11:54 2018 -0800
@@ -2,5 +2,5 @@
 rdflib-jsonld==0.4.0
 rdflib==4.2.2
 twisted-mqtt==0.3.6
-https://projects.bigasterisk.com/rdfdb/rdfdb-0.3.0.tar.gz
+https://projects.bigasterisk.com/rdfdb/rdfdb-0.6.0.tar.gz
 rx==1.6.1