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