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
parent
205989aefd
commit
e30e8aaedc
|
@ -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>"]
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue