Mercurial > personal > weatherlog
comparison weatherlog/daemon.py @ 17:39c0686e6765
daemon: Change to executing from a config file.
This updates daemon.py to execute based on a config file, rather than
needing manual configuration. It also instructs setup.py to create
an entry point for the new daemon.py main function.
Configuration is specified in a TOML file whose format is documented,
kind of, in the parse_config function.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Thu, 17 Oct 2019 22:28:12 -0400 |
| parents | c01f9929ae38 |
| children | 7117db65715e |
comparison
equal
deleted
inserted
replaced
| 16:770215590d80 | 17:39c0686e6765 |
|---|---|
| 1 """Entry point to set up a temperature logging daemon.""" | 1 """Entry point to set up a temperature logging daemon.""" |
| 2 | 2 |
| 3 import argparse | |
| 4 import enum | |
| 3 import time | 5 import time |
| 4 import typing as t | 6 import typing as t |
| 7 | |
| 8 import attr | |
| 9 import toml | |
| 5 | 10 |
| 6 from . import http_writer | 11 from . import http_writer |
| 7 from . import logger | 12 from . import logger |
| 8 from . import reader | 13 from . import reader |
| 9 | 14 |
| 10 DEFAULT_INTERVAL_SECS = 60 | 15 DEFAULT_INTERVAL_SECS = 60 |
| 11 MIN_INTERVAL_SECS = 5 | 16 MIN_INTERVAL_SECS = 5 |
| 12 | 17 |
| 13 | 18 |
| 14 def run( | 19 def run( |
| 15 directory: str, | 20 rd: reader.Reader, |
| 16 url: str, | 21 log: logger.BufferedLogger, |
| 17 preamble: t.Dict[str, t.Any], | 22 writer: logger.RemoteWriter, |
| 18 interval: int = DEFAULT_INTERVAL_SECS, | 23 interval: int = DEFAULT_INTERVAL_SECS, |
| 19 ): | 24 ): |
| 20 """Sets up and runs a logger daemon.""" | 25 """Sets up and runs a logger daemon.""" |
| 21 writer = http_writer.HTTPWriter(url, preamble) | |
| 22 log = logger.BufferedLogger(directory, writer) | |
| 23 log.start() | 26 log.start() |
| 24 | |
| 25 r = reader.DHT22Reader() | |
| 26 cycle = 0 | 27 cycle = 0 |
| 27 start = time.time() | 28 start = time.time() |
| 28 try: | 29 try: |
| 29 while True: | 30 while True: |
| 30 log.write(r.read().as_dict()) | 31 log.write(rd.read().as_dict()) |
| 31 cycle += 1 | 32 cycle += 1 |
| 32 target = start + interval * cycle | 33 target = start + interval * cycle |
| 33 now = time.time() | 34 now = time.time() |
| 34 time.sleep(max(target - now, MIN_INTERVAL_SECS)) | 35 time.sleep(max(target - now, MIN_INTERVAL_SECS)) |
| 35 finally: | 36 finally: |
| 36 log.close() | 37 log.close() |
| 38 | |
| 39 | |
| 40 class SensorType(enum.Enum): | |
| 41 DHT22 = 'DHT22' | |
| 42 BME280 = 'BME280' | |
| 43 | |
| 44 | |
| 45 @attr.s(auto_attribs=True, frozen=True, slots=True) | |
| 46 class _Config: | |
| 47 # The directory to store reading data in. | |
| 48 directory: str | |
| 49 # The URL to submit readings to. | |
| 50 url: str | |
| 51 # The type of sensor to read from. | |
| 52 sensor: SensorType | |
| 53 # The authentication preamble for the URL. | |
| 54 auth: t.Dict[str, object] | |
| 55 | |
| 56 | |
| 57 def parse_config(config_file: str): | |
| 58 with open(config_file, 'r') as infile: | |
| 59 config = toml.load(infile) | |
| 60 return _Config( | |
| 61 directory=config['directory'], | |
| 62 url=config['url'], | |
| 63 sensor=SensorType(config['sensor']['type']), | |
| 64 auth=config['auth']) | |
| 65 | |
| 66 | |
| 67 def main(args: t.Optional[t.Sequence[str]] = None) -> None: | |
| 68 parser = argparse.ArgumentParser() | |
| 69 parser.add_argument('config_file', help='TOML file to load config from.') | |
| 70 parsed = parser.parse_args(args) | |
| 71 config = parse_config(parsed.config_file) | |
| 72 writer = http_writer.HTTPWriter(config.url, config.auth) | |
| 73 log = logger.BufferedLogger(config.directory, writer) | |
| 74 | |
| 75 if config.sensor is SensorType.DHT22: | |
| 76 rdr = reader.DHT22Reader() | |
| 77 elif config.sensor is SensorType.BME280: | |
| 78 rdr = reader.BME280Reader() | |
| 79 else: | |
| 80 raise AssertionError('Unknown sensor type') | |
| 81 run(rdr, log, writer) | |
| 82 | |
| 83 | |
| 84 if __name__ == '__main__': | |
| 85 main() |
