1
0
Fork 0

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.
master
Dustin 2021-05-01 15:27:33 -05:00
parent 9503e87b4b
commit 205989aefd
2 changed files with 9 additions and 5 deletions

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "thermostat"
version = "0.2.0"
version = "0.3.0dev1"
description = ""
authors = ["Dustin C. Hatch <dustin@hatch.name>"]

View File

@ -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()