Mercurial > templog
annotate py/tempserver.py @ 529:5201f441bf4a
run 2to3
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 10 Apr 2015 23:59:16 +0800 |
parents | 61e61de49a50 |
children | e39ed85d87a5 |
rev | line source |
---|---|
447 | 1 #!/home/matt/templog/venv/bin/python |
439 | 2 |
3 import sys | |
4 import os | |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
5 import logging |
498 | 6 import time |
7 import signal | |
527 | 8 import asyncio |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
9 |
471 | 10 import lockfile.pidlockfile |
461
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
11 import daemon |
439 | 12 |
13 import utils | |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
14 from utils import L,D,EX,W |
444 | 15 import fridge |
16 import config | |
17 import sensor_ds18b20 | |
18 import params | |
459 | 19 import uploader |
444 | 20 |
439 | 21 |
22 class Tempserver(object): | |
23 def __init__(self): | |
24 self.readings = [] | |
444 | 25 self.current = (None, None) |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
26 self.fridge = None |
527 | 27 self._wakeup = asyncio.Event() |
439 | 28 |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
29 def __enter__(self): |
444 | 30 self.params = params.Params() |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
31 self.fridge = fridge.Fridge(self) |
459 | 32 self.uploader = uploader.Uploader(self) |
444 | 33 self.params.load() |
528 | 34 self.set_sensors(sensor.make_sensor(self)) |
527 | 35 asyncio.get_event_loop().add_signal_handler(signal.SIGHUP, self._reload_signal) |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
36 return self |
439 | 37 |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
38 def __exit__(self, exc_type, exc_value, traceback): |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
39 L("Exiting, cleanup handler"); |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
40 self.fridge.off() |
439 | 41 |
444 | 42 def run(self): |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
43 |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
44 if self.fridge is None: |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
45 raise Exception("Tempserver.run() must be within 'with Tempserver() as server'") |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
46 |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
47 # XXX do these go here or in __enter_() ? |
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
48 self.start_time = self.now() |
527 | 49 tasks = ( |
50 self.fridge.run(), | |
51 self.sensors.run(), | |
52 self.uploader.run(), | |
53 ) | |
54 loop = asyncio.get_event_loop() | |
55 try: | |
56 loop.run_until_complete(asyncio.wait(tasks)) | |
57 # not reached | |
58 except KeyboardInterrupt: | |
59 pass | |
444 | 60 |
61 def now(self): | |
62 return utils.monotonic_time() | |
63 | |
443 | 64 def set_sensors(self, sensors): |
447 | 65 if hasattr(self, 'sensors'): |
443 | 66 self.sensors.kill() |
67 self.sensors = sensors | |
68 self.wort_name = sensors.wort_name() | |
69 self.fridge_name = sensors.fridge_name() | |
439 | 70 |
71 def take_readings(self): | |
72 ret = self.readings | |
73 self.readings = [] | |
74 return ret | |
75 | |
76 def pushfront(self, readings): | |
77 """ used if a caller of take_readings() fails """ | |
459 | 78 self.readings = readings + self.readings |
439 | 79 |
443 | 80 # a reading is a map of {sensorname: value}. temperatures |
81 # are float degrees | |
439 | 82 def add_reading(self, reading): |
83 """ adds a reading at the current time """ | |
454 | 84 D("add_reading(%s)" % str(reading)) |
444 | 85 self.readings.append( (reading, self.now())) |
443 | 86 self.current = (reading.get(self.wort_name, None), |
87 reading.get(self.fridge_name, None)) | |
459 | 88 if len(self.readings) > config.MAX_READINGS: |
89 self.readings = self.readings[-config.MAX_READINGS:] | |
439 | 90 |
91 def current_temps(self): | |
443 | 92 """ returns (wort_temp, fridge_temp) tuple """ |
447 | 93 return self.current |
444 | 94 |
518
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
95 def sleep(self, timeout): |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
96 """ sleeps for timeout seconds, though wakes if the server's config is updated """ |
527 | 97 asyncio.wait_for(self._wakeup, timeout=timeout) |
518
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
98 |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
99 def _reload_signal(self): |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
100 try: |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
101 self.params.load() |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
102 L("Reloaded.") |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
103 self._wakeup.set() |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
104 self._wakeup.clear() |
528 | 105 except Error as e: |
518
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
106 W("Problem reloading: %s" % str(e)) |
0b5ff341d124
sleep on a semaphore so it can start/stop immediately when there's a SIGHUP
Matt Johnston <matt@ucc.asn.au>
parents:
514
diff
changeset
|
107 |
444 | 108 def setup_logging(): |
109 logging.basicConfig(format='%(asctime)s %(message)s', | |
110 datefmt='%m/%d/%Y %I:%M:%S %p', | |
462 | 111 level=logging.INFO) |
444 | 112 |
461
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
113 def start(): |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
114 with Tempserver() as server: |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
115 server.run() |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
116 |
444 | 117 def main(): |
448
fe729664a5e6
working better. logging works properly, cleanup fridge.off() happens.
Matt Johnston <matt@ucc.asn.au>
parents:
447
diff
changeset
|
118 setup_logging() |
444 | 119 |
473
bd29ddb360a5
fix to absolute path for lockfile, --daemon does chdir("/")
Matt Johnston <matt@ucc.asn.au>
parents:
471
diff
changeset
|
120 heredir = os.path.abspath(os.path.dirname(__file__)) |
bd29ddb360a5
fix to absolute path for lockfile, --daemon does chdir("/")
Matt Johnston <matt@ucc.asn.au>
parents:
471
diff
changeset
|
121 pidpath = os.path.join(heredir, 'tempserver.pid') |
471 | 122 pidf = lockfile.pidlockfile.PIDLockFile(pidpath, threaded=False) |
499 | 123 do_hup = '--hup' in sys.argv |
471 | 124 try: |
514 | 125 pidf.acquire(1) |
471 | 126 pidf.release() |
528 | 127 except (lockfile.AlreadyLocked, lockfile.LockTimeout) as e: |
471 | 128 pid = pidf.read_pid() |
499 | 129 if do_hup: |
130 try: | |
131 os.kill(pid, signal.SIGHUP) | |
529 | 132 print("Sent SIGHUP to process %d" % pid, file=sys.stderr) |
499 | 133 sys.exit(0) |
134 except OSError: | |
529 | 135 print("Process %d isn't running?" % pid, file=sys.stderr) |
499 | 136 sys.exit(1) |
137 | |
529 | 138 print("Locked by PID %d" % pid, file=sys.stderr) |
499 | 139 |
498 | 140 stale = False |
471 | 141 if pid > 0: |
498 | 142 if '--new' in sys.argv: |
143 try: | |
144 os.kill(pid, 0) | |
145 except OSError: | |
146 stale = True | |
147 | |
148 if not stale: | |
529 | 149 print("Stopping old tempserver pid %d" % pid, file=sys.stderr) |
498 | 150 os.kill(pid, signal.SIGTERM) |
151 time.sleep(2) | |
152 pidf.acquire(0) | |
153 pidf.release() | |
154 else: | |
155 try: | |
156 os.kill(pid, 0) | |
157 # must still be running PID | |
158 raise e | |
159 except OSError: | |
160 stale = True | |
161 | |
162 if stale: | |
163 # isn't still running, steal the lock | |
529 | 164 print("Unlinking stale lockfile %s for pid %d" % (pidpath, pid), file=sys.stderr) |
498 | 165 pidf.break_lock() |
461
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
166 |
499 | 167 if do_hup: |
529 | 168 print("Doesn't seem to be running", file=sys.stderr) |
499 | 169 sys.exit(1) |
170 | |
444 | 171 if '--daemon' in sys.argv: |
461
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
172 logpath = os.path.join(os.path.dirname(__file__), 'tempserver.log') |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
173 logf = open(logpath, 'a+') |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
174 with daemon.DaemonContext(pidfile=pidf, stdout=logf, stderr = logf): |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
175 start() |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
176 else: |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
177 with pidf: |
1eb68df9f8ab
Add daemon mode with locking, add "disabled" parameter
Matt Johnston <matt@ucc.asn.au>
parents:
459
diff
changeset
|
178 start() |
444 | 179 |
180 if __name__ == '__main__': | |
181 main() |