changeset 233:19569cb5ed46

better arg parser. seems close to ready
author Matt Johnston <matt@ucc.asn.au>
date Sat, 11 Apr 2015 23:32:59 +0800
parents a01b7bccccd3
children fd29ae905d1b
files py/fridge.py py/params.py py/tempserver.py py/uploader.py
diffstat 4 files changed, 74 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/py/fridge.py	Sat Apr 11 21:09:13 2015 +0800
+++ b/py/fridge.py	Sat Apr 11 23:32:59 2015 +0800
@@ -81,6 +81,8 @@
         if fridge is None:
             W("Invalid fridge sensor")
 
+        D("fridge on %s" % self.is_on())
+
         if self.is_on():
             turn_off = False
             on_time = self.server.now() - self.fridge_on_clock
@@ -109,6 +111,7 @@
         else:
             # fridge is off
             turn_on = False
+            D("fridge %(fridge)f max %(fridge_max)f wort %(wort)f wort_max %(wort_max)f" % locals())
             if not params.nowort \
                 and wort is not None \
                 and wort >= wort_max:
--- a/py/params.py	Sat Apr 11 21:09:13 2015 +0800
+++ b/py/params.py	Sat Apr 11 23:32:59 2015 +0800
@@ -33,13 +33,7 @@
         self[k]
         self[k] = v
 
-    def load(self, f = None):
-        if not f:
-            try:
-                f = open(config.PARAMS_FILE, 'r')
-            except IOError as e:
-                W("Missing parameter file, using defaults. %s", e)
-                return
+    def _do_load(self, f):
         try:
             u = json.load(f)
         except Exception as e:
@@ -55,14 +49,29 @@
         L("Loaded parameters")
         L(self.save_string())
 
+    def load(self, f = None):
+        if f:
+            return self._do_load(f)
+        else:
+            with open(config.PARAMS_FILE, 'r') as f:
+                try:
+                    return self._do_load(f)
+                except IOError as e:
+                    W("Missing parameter file, using defaults. %s" % str(e))
+                    return
 
-    def save(self, f = None):
-        if not f:
-            f = file(config.PARAMS_FILE, 'w')
+    def _do_save(self, f):
         json.dump(self, f, sort_keys=True, indent=4)
         f.write('\n')
         f.flush()
 
+    def save(self, f = None):
+        if f:
+            return self._do_save(f)
+        else:
+            with file(config.PARAMS_FILE, 'w') as f:
+                return self._do_save(f)
+
     def save_string(self):
         s = io.StringIO()
         self.save(s)
--- a/py/tempserver.py	Sat Apr 11 21:09:13 2015 +0800
+++ b/py/tempserver.py	Sat Apr 11 23:32:59 2015 +0800
@@ -6,6 +6,7 @@
 import time
 import signal
 import asyncio
+import argparse
 
 import lockfile.pidlockfile
 import daemon
@@ -20,11 +21,12 @@
 
 
 class Tempserver(object):
-    def __init__(self):
+    def __init__(self, test_mode):
         self.readings = []
         self.current = (None, None)
         self.fridge = None
-        self._wakeup = asyncio.Condition()
+        self._wakeup = asyncio.Event()
+        self._test_mode = test_mode
 
     def __enter__(self):
         self.params = params.Params()
@@ -53,9 +55,15 @@
         )
 
         loop = asyncio.get_event_loop()
-        result_tasks = loop.run_until_complete(asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION))
-        # use the results so that exceptions get thrown
-        [t.result() for x in result_tasks for t in x]
+        try:
+            result_tasks = loop.run_until_complete(asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION))
+            # use the results so that exceptions get thrown
+            [t.result() for x in result_tasks for t in x]
+        except KeyboardInterrupt:
+            print('ctrl-c')
+            pass
+        finally:
+            loop.close()
 
     def now(self):
         return utils.monotonic_time()
@@ -98,42 +106,58 @@
         # XXX fixme - we should wake on _wakeup but asyncio Condition with wait_for is a bit broken? 
         # https://groups.google.com/forum/#!topic/python-tulip/eSm7rZAe9LM
         # For now we just sleep, ignore the _wakeup
-        yield from asyncio.sleep(timeout)
+        try:
+            yield from asyncio.wait_for(self._wakeup.wait(), timeout=timeout)
+        except asyncio.TimeoutError:
+            pass
         
-    @asyncio.coroutine
     def _reload_signal(self):
         try:
             self.params.load()
             L("Reloaded.")
-            yield from self._wakeup.acquire()
-            self._wakeup.notify_all()
-            self._wakeup.release()
+            self._wakeup.set()
+            self._wakeup.clear()
         except Error as e:
             W("Problem reloading: %s" % str(e))
 
-def setup_logging():
+    def test_mode(self):
+        return self._test_mode
+
+def setup_logging(debug = False):
+    level = logging.INFO
+    if debug:
+        level = logging.DEBUG
     logging.basicConfig(format='%(asctime)s %(message)s', 
             datefmt='%m/%d/%Y %I:%M:%S %p',
-            level=logging.DEBUG)
-    logging.getLogger("asyncio").setLevel(logging.DEBUG)
+            level=level)
+    #logging.getLogger("asyncio").setLevel(logging.DEBUG)
 
-def start():
-    with Tempserver() as server:
+def start(test_mode):
+    with Tempserver(test_mode) as server:
         server.run()
 
 def main():
-    setup_logging()
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--hup', action='store_true')
+    parser.add_argument('--new', action='store_true')
+    parser.add_argument('--daemon', action='store_true')
+    parser.add_argument('-d', '--debug', action='store_true')
+    parser.add_argument('-t', '--test', action='store_true')
+    args = parser.parse_args()
+
+    setup_logging(args.debug)
 
     heredir = os.path.abspath(os.path.dirname(__file__))
     pidpath = os.path.join(heredir, 'tempserver.pid')
     pidf = lockfile.pidlockfile.PIDLockFile(pidpath, threaded=False)
-    do_hup = '--hup' in sys.argv
+
+
     try:
         pidf.acquire(1)
         pidf.release()
     except (lockfile.AlreadyLocked, lockfile.LockTimeout) as e:
         pid = pidf.read_pid()
-        if do_hup:
+        if args.hup:
             try:
                 os.kill(pid, signal.SIGHUP)
                 print("Sent SIGHUP to process %d" % pid, file=sys.stderr)
@@ -146,7 +170,7 @@
     
         stale = False
         if pid > 0:
-            if '--new' in sys.argv:
+            if args.new:
                 try:
                     os.kill(pid, 0)
                 except OSError:
@@ -171,18 +195,18 @@
             print("Unlinking stale lockfile %s for pid %d" % (pidpath, pid), file=sys.stderr)
             pidf.break_lock()
 
-    if do_hup:
+    if args.hup:
         print("Doesn't seem to be running", file=sys.stderr)
         sys.exit(1)
 
-    if '--daemon' in sys.argv:
+    if args.daemon:
         logpath = os.path.join(os.path.dirname(__file__), 'tempserver.log')
         logf = open(logpath, 'a+')
         with daemon.DaemonContext(pidfile=pidf, stdout=logf, stderr = logf):
-            start()
+            start(args.test)
     else:
         with pidf:
-            start()
+            start(args.test)
 
 if __name__ == '__main__':
     main()
--- a/py/uploader.py	Sat Apr 11 21:09:13 2015 +0800
+++ b/py/uploader.py	Sat Apr 11 23:32:59 2015 +0800
@@ -1,5 +1,6 @@
 import json
 import hmac
+import hashlib
 import zlib
 import binascii
 import logging
@@ -44,8 +45,11 @@
     @asyncio.coroutine
     def send(self, tosend):
         js = json.dumps(tosend)
+        if self.server.test_mode():
+            D("Would upload %s to %s" % (js, config.UPDATE_URL))
+            return
         js_enc = binascii.b2a_base64(zlib.compress(js.encode()))
-        mac = hmac.new(config.HMAC_KEY.encode(), js_enc).hexdigest()
+        mac = hmac.new(config.HMAC_KEY.encode(), js_enc, hashlib.sha1).hexdigest()
         send_data = {'data': js_enc, 'hmac': mac}
         r = yield from asyncio.wait_for(aiohttp.request('post', config.UPDATE_URL, data=send_data), 60)
         result = yield from asyncio.wait_for(r.text(), 60)