1
0
Fork 0

sensor: Add availability messages

Home Assistant can mark MQTT-based sensors as "unavailable" when it
receives a special message (`offline`) on a designated topic.  We send
an `online` message when the sensor process starts, and `offline` when
the process shuts down.  Additionally, we set the last will and
testament message to `offline` as well, so that Home Assistant will
still get the notification, even if the sensor does not shut down
cleanly.
master
Dustin 2021-05-01 15:57:03 -05:00
parent 205989aefd
commit e30e8aaedc
2 changed files with 12 additions and 1 deletions

View File

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

View File

@ -3,6 +3,7 @@ import logging
import os import os
import select import select
import signal import signal
import threading
import time import time
from contextlib import closing from contextlib import closing
from types import FrameType from types import FrameType
@ -21,6 +22,7 @@ PORT = 8883
USERNAME = os.environ.get("MQTT_USERNAME", "") USERNAME = os.environ.get("MQTT_USERNAME", "")
PASSWORD = os.environ.get("MQTT_PASSWORD", "") PASSWORD = os.environ.get("MQTT_PASSWORD", "")
TOPIC = "homeassistant/sensor/thermostat" TOPIC = "homeassistant/sensor/thermostat"
AVAILABILITY_TOPIC = f"{TOPIC}/availability"
I2CPORT = 1 I2CPORT = 1
SENSOR_ADDR = 0x77 SENSOR_ADDR = 0x77
@ -31,6 +33,7 @@ SENSOR_CONFIG = {
"device_class": "temperature", "device_class": "temperature",
"name": "Thermostat Temperature", "name": "Thermostat Temperature",
"state_topic": TOPIC, "state_topic": TOPIC,
"availability_topic": AVAILABILITY_TOPIC,
"unit_of_measurement": "°C", "unit_of_measurement": "°C",
"value_template": r"{{ value_json.temperature }}", "value_template": r"{{ value_json.temperature }}",
}, },
@ -38,6 +41,7 @@ SENSOR_CONFIG = {
"device_class": "pressure", "device_class": "pressure",
"name": "Thermostat Pressure", "name": "Thermostat Pressure",
"state_topic": TOPIC, "state_topic": TOPIC,
"availability_topic": AVAILABILITY_TOPIC,
"unit_of_measurement": "hPa", "unit_of_measurement": "hPa",
"value_template": r"{{ value_json.pressure }}", "value_template": r"{{ value_json.pressure }}",
}, },
@ -45,6 +49,7 @@ SENSOR_CONFIG = {
"device_class": "humidity", "device_class": "humidity",
"name": "Thermostat Humidity", "name": "Thermostat Humidity",
"state_topic": TOPIC, "state_topic": TOPIC,
"availability_topic": AVAILABILITY_TOPIC,
"unit_of_measurement": "%", "unit_of_measurement": "%",
"value_template": r"{{ value_json.humidity }}", "value_template": r"{{ value_json.humidity }}",
}, },
@ -54,6 +59,7 @@ SENSOR_CONFIG = {
class Daemon: class Daemon:
def __init__(self) -> None: def __init__(self) -> None:
self.quitpipe = os.pipe() self.quitpipe = os.pipe()
self._ready = threading.Event()
def on_signal(self, signum: int, frame: FrameType) -> None: def on_signal(self, signum: int, frame: FrameType) -> None:
log.debug("Got signal %d at %s", signum, frame) log.debug("Got signal %d at %s", signum, frame)
@ -65,6 +71,7 @@ class Daemon:
signal.signal(signal.SIGTERM, self.on_signal) signal.signal(signal.SIGTERM, self.on_signal)
client = mqtt.Client() client = mqtt.Client()
client.will_set(AVAILABILITY_TOPIC, "offline")
client.on_connect = self.on_connect client.on_connect = self.on_connect
client.on_message = self.on_message client.on_message = self.on_message
client.on_disconnect = self.on_disconnect client.on_disconnect = self.on_disconnect
@ -74,6 +81,7 @@ class Daemon:
client.loop_start() client.loop_start()
with closing(smbus2.SMBus(I2CPORT)) as bus: with closing(smbus2.SMBus(I2CPORT)) as bus:
params = bme280.load_calibration_params(bus, SENSOR_ADDR) params = bme280.load_calibration_params(bus, SENSOR_ADDR)
self._ready.wait()
while 1: while 1:
data = bme280.sample(bus, SENSOR_ADDR, params) data = bme280.sample(bus, SENSOR_ADDR, params)
values = { values = {
@ -86,6 +94,7 @@ class Daemon:
if self.quitpipe[0] in ready: if self.quitpipe[0] in ready:
os.close(self.quitpipe[0]) os.close(self.quitpipe[0])
break break
client.publish(AVAILABILITY_TOPIC, "offline")
client.disconnect() client.disconnect()
client.loop_stop() client.loop_stop()
@ -101,6 +110,8 @@ class Daemon:
client.publish( client.publish(
f"homeassistant/sensor/{key}/config", json.dumps(value) f"homeassistant/sensor/{key}/config", json.dumps(value)
) )
client.publish(AVAILABILITY_TOPIC, "online")
self._ready.set()
def on_disconnect(self, client, userdata, rc): def on_disconnect(self, client, userdata, rc):
log.error("Lost connection to MQTT broker") log.error("Lost connection to MQTT broker")