From 205989aefd2311d8f347592d69334441ac996280 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sat, 1 May 2021 15:27:33 -0500 Subject: [PATCH] sensor: Use pipe to interrupt loop The `time.sleep` function cannot be stopped prematurely. This means that when the program receives a signal indicating it should stop, it will not be able to do so until the running `sleep` completes. This means it could take up to 10 seconds for the process to stop. A better way to handle the shutdown signal is to use a pipe. When the signal is received, the write end of the pipe is closed. The event loop will detect this immediately, as `select.select` returns as soon as any event occurs on any of the polled file descriptors, or the timeout expires. --- pyproject.toml | 2 +- src/thermostat/sensor.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3e0f275..2c4ab46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "thermostat" -version = "0.2.0" +version = "0.3.0dev1" description = "" authors = ["Dustin C. Hatch "] diff --git a/src/thermostat/sensor.py b/src/thermostat/sensor.py index 189d6bb..ee305a6 100644 --- a/src/thermostat/sensor.py +++ b/src/thermostat/sensor.py @@ -1,6 +1,7 @@ import json import logging import os +import select import signal import time from contextlib import closing @@ -52,12 +53,12 @@ SENSOR_CONFIG = { class Daemon: def __init__(self) -> None: - self.running = True + self.quitpipe = os.pipe() def on_signal(self, signum: int, frame: FrameType) -> None: log.debug("Got signal %d at %s", signum, frame) log.info("Stopping") - self.running = False + os.close(self.quitpipe[1]) def run(self): signal.signal(signal.SIGINT, self.on_signal) @@ -73,7 +74,7 @@ class Daemon: client.loop_start() with closing(smbus2.SMBus(I2CPORT)) as bus: params = bme280.load_calibration_params(bus, SENSOR_ADDR) - while self.running: + while 1: data = bme280.sample(bus, SENSOR_ADDR, params) values = { "temperature": int(data.temperature), @@ -81,7 +82,10 @@ class Daemon: "humidity": int(data.humidity), } client.publish(TOPIC, json.dumps(values)) - time.sleep(10) + ready = select.select((self.quitpipe[0],), (), (), 10)[0] + if self.quitpipe[0] in ready: + os.close(self.quitpipe[0]) + break client.disconnect() client.loop_stop()