annotate weatherlog/daemon.py @ 19:7117db65715e

Make weatherlog shutdown properly by handling SIGTERM.
author Paul Fisher <paul@pfish.zone>
date Mon, 20 Jan 2020 23:36:23 -0500
parents 39c0686e6765
children 92367b644e29
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
1 """Entry point to set up a temperature logging daemon."""
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
2
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
3 import argparse
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
4 import enum
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
5 import signal
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
6 import threading
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
7 import time
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
8 import typing as t
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
9
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
10 import attr
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
11 import toml
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
12
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
13 from . import http_writer
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
14 from . import logger
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
15 from . import reader
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
16
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
17 DEFAULT_INTERVAL_SECS = 60
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
18 MIN_INTERVAL_SECS = 5
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
19
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
20
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
21 def run(
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
22 rd: reader.Reader,
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
23 log: logger.BufferedLogger,
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
24 writer: logger.RemoteWriter,
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
25 interval: int = DEFAULT_INTERVAL_SECS,
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
26 ) -> None:
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
27 """Sets up and runs a logger daemon."""
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
28 evt = threading.Event()
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
29 signal.signal(signal.SIGTERM, lambda *args: evt.set())
12
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
30 cycle = 0
91e22a09b82f Create 'daemon.py', a runner to tie it all together.
Paul Fisher <paul@pfish.zone>
parents:
diff changeset
31 start = time.time()
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
32 running = True
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
33 log.start()
13
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
34 try:
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
35 while running:
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
36 log.write(rd.read().as_dict())
13
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
37 cycle += 1
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
38 target = start + interval * cycle
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
39 now = time.time()
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
40 running = not evt.wait(max(target - now, MIN_INTERVAL_SECS))
13
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
41 finally:
4c81182eaa6b daemon: Fail less ungracefully, bump to v0.1.0.
Paul Fisher <paul@pfish.zone>
parents: 12
diff changeset
42 log.close()
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
43
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
44
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
45 class SensorType(enum.Enum):
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
46 DHT22 = 'DHT22'
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
47 BME280 = 'BME280'
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
48
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
49
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
50 @attr.s(auto_attribs=True, frozen=True, slots=True)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
51 class _Config:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
52 # The directory to store reading data in.
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
53 directory: str
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
54 # The URL to submit readings to.
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
55 url: str
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
56 # The type of sensor to read from.
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
57 sensor: SensorType
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
58 # The authentication preamble for the URL.
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
59 auth: t.Dict[str, object]
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
60
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
61
19
7117db65715e Make weatherlog shutdown properly by handling SIGTERM.
Paul Fisher <paul@pfish.zone>
parents: 17
diff changeset
62 def parse_config(config_file: str) -> _Config:
17
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
63 with open(config_file, 'r') as infile:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
64 config = toml.load(infile)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
65 return _Config(
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
66 directory=config['directory'],
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
67 url=config['url'],
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
68 sensor=SensorType(config['sensor']['type']),
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
69 auth=config['auth'])
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
70
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
71
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
72 def main(args: t.Optional[t.Sequence[str]] = None) -> None:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
73 parser = argparse.ArgumentParser()
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
74 parser.add_argument('config_file', help='TOML file to load config from.')
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
75 parsed = parser.parse_args(args)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
76 config = parse_config(parsed.config_file)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
77 writer = http_writer.HTTPWriter(config.url, config.auth)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
78 log = logger.BufferedLogger(config.directory, writer)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
79
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
80 if config.sensor is SensorType.DHT22:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
81 rdr = reader.DHT22Reader()
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
82 elif config.sensor is SensorType.BME280:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
83 rdr = reader.BME280Reader()
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
84 else:
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
85 raise AssertionError('Unknown sensor type')
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
86 run(rdr, log, writer)
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
87
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
88
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
89 if __name__ == '__main__':
39c0686e6765 daemon: Change to executing from a config file.
Paul Fisher <paul@pfish.zone>
parents: 14
diff changeset
90 main()