diff py/tempserver.py @ 293:d15dda1b1f76

merge
author Matt Johnston <matt@ucc.asn.au>
date Sat, 06 Jul 2019 18:29:45 +0800
parents 26eee8591f61
children 20c89630be6c
line wrap: on
line diff
--- a/py/tempserver.py	Thu Mar 19 21:50:52 2015 +0800
+++ b/py/tempserver.py	Sat Jul 06 18:29:45 2019 +0800
@@ -5,9 +5,9 @@
 import logging
 import time
 import signal
+import asyncio
+import argparse
 
-import gevent
-import gevent.monkey
 import lockfile.pidlockfile
 import daemon
 
@@ -15,28 +15,28 @@
 from utils import L,D,EX,W
 import fridge
 import config
-import sensor_ds18b20
+import sensor
 import params
 import uploader
+import configwaiter
 
 
 class Tempserver(object):
-    def __init__(self):
+    def __init__(self, test_mode):
         self.readings = []
         self.current = (None, None)
         self.fridge = None
-        self._wakeup = gevent.event.Event()
-
-        # don't patch os, fork() is used by daemonize
-        gevent.monkey.patch_all(os=False, thread=False)
+        self._wakeup = asyncio.Event()
+        self._test_mode = test_mode
 
     def __enter__(self):
         self.params = params.Params()
         self.fridge = fridge.Fridge(self)
         self.uploader = uploader.Uploader(self)
+        self.configwaiter = configwaiter.ConfigWaiter(self)
         self.params.load()
-        self.set_sensors(sensor_ds18b20.DS18B20s(self))
-        gevent.signal(signal.SIGHUP, self._reload_signal)
+        self.set_sensors(sensor.make_sensor(self))
+        asyncio.get_event_loop().add_signal_handler(signal.SIGHUP, self.reload_signal)
         return self
 
     def __exit__(self, exc_type, exc_value, traceback):
@@ -50,16 +50,21 @@
 
         # XXX do these go here or in __enter_() ?
         self.start_time = self.now()
-        self.fridge.start()
-        self.sensors.start()
-        self.uploader.start()
+        runloops = [
+            self.fridge.run(),
+            self.sensors.run(),
+            self.uploader.run(),
+            self.configwaiter.run(),
+        ]
 
-        # won't return.
-        while True:
-            try:
-                gevent.sleep(60)
-            except KeyboardInterrupt:
-                break
+        loop = asyncio.get_event_loop()
+        try:
+            loop.run_until_complete(asyncio.gather(*runloops))
+        except KeyboardInterrupt:
+            print('\nctrl-c')
+        finally:
+            # loop.close() seems necessary otherwise get warnings about signal handlers
+            loop.close()
 
     def now(self):
         return utils.monotonic_time()
@@ -93,63 +98,88 @@
 
     def current_temps(self):
         """ returns (wort_temp, fridge_temp) tuple """
+        D("current: %s" % str(self.current))
         return self.current
 
+    @asyncio.coroutine
     def sleep(self, timeout):
         """ sleeps for timeout seconds, though wakes if the server's config is updated """
-        self._wakeup.wait(timeout)
-        
-    def _reload_signal(self):
+        # 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
         try:
-            self.params.load()
-            L("Reloaded.")
+            yield from asyncio.wait_for(self._wakeup.wait(), timeout=timeout)
+        except asyncio.TimeoutError:
+            pass
+
+    def reload_signal(self, no_file = False):
+        try:
+            if not no_file:
+                self.params.load()
+                L("Reloaded.")
             self._wakeup.set()
             self._wakeup.clear()
-        except self.Error, e:
+        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.INFO)
+            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('-D', '--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), e:
+    except (lockfile.AlreadyLocked, lockfile.LockTimeout) as e:
         pid = pidf.read_pid()
-        if do_hup:
+        if args.hup:
             try:
                 os.kill(pid, signal.SIGHUP)
-                print>>sys.stderr, "Sent SIGHUP to process %d" % pid
+                print("Sent SIGHUP to process %d" % pid, file=sys.stderr)
                 sys.exit(0)
             except OSError:
-                print>>sys.stderr, "Process %d isn't running?" % pid
+                print("Process %d isn't running?" % pid, file=sys.stderr)
                 sys.exit(1)
 
-        print>>sys.stderr, "Locked by PID %d" % pid
+        print("Locked by PID %d" % pid, file=sys.stderr)
     
         stale = False
         if pid > 0:
-            if '--new' in sys.argv:
+            if args.new:
                 try:
                     os.kill(pid, 0)
                 except OSError:
                     stale = True
 
                 if not stale:
-                    print>>sys.stderr, "Stopping old tempserver pid %d" % pid
+                    print("Stopping old tempserver pid %d" % pid, file=sys.stderr)
                     os.kill(pid, signal.SIGTERM)
                     time.sleep(2)
                     pidf.acquire(0)
@@ -164,21 +194,21 @@
 
         if stale:
             # isn't still running, steal the lock
-            print>>sys.stderr, "Unlinking stale lockfile %s for pid %d" % (pidpath, pid)
+            print("Unlinking stale lockfile %s for pid %d" % (pidpath, pid), file=sys.stderr)
             pidf.break_lock()
 
-    if do_hup:
-        print>>sys.stderr, "Doesn't seem to be running"
+    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()