Răsfoiți Sursa

add/send mqtt birth ("online") & last will ("offline") message (@phbasler)

https://github.com/fphammerle/switchbot-mqtt/pull/105
Fabian Peter Hammerle 1 an în urmă
părinte
comite
31d66b2c66
5 a modificat fișierele cu 32 adăugiri și 1 ștergeri
  1. 1 1
      .github/workflows/container-image.yml
  2. 4 0
      CHANGELOG.md
  3. 5 0
      README.md
  4. 16 0
      switchbot_mqtt/__init__.py
  5. 6 0
      tests/test_mqtt.py

+ 1 - 1
.github/workflows/container-image.yml

@@ -17,7 +17,7 @@ jobs:
     # > will be done directly by buildkit. [...]
     # > any file mutation in the steps that precede [...] will be ignored
     # https://github.com/marketplace/actions/build-and-push-docker-images
-    - uses: docker/build-push-action@v3.1.0
+    - uses: docker/build-push-action@v3.1.1
       with:
         platforms: |
           linux/amd64

+ 4 - 0
CHANGELOG.md

@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Added
+- Birth ("online") and last will ("offline") message on topic
+  `homeassistant/switchbot-mqtt/status`
+  (@hbasler, https://github.com/fphammerle/switchbot-mqtt/pull/105)
 
 ## [3.2.1] - 2022-07-09
 ### Fixed

+ 5 - 0
README.md

@@ -105,6 +105,11 @@ switchbot-mqtt --mqtt-topic-prefix living-room/ …
 switchbot-mqtt --mqtt-topic-prefix '' …
 ```
 
+### Service Status Report
+
+After connecting to the MQTT broker, `switchbot-mqtt` will report `online` on topic `homeassistant/switchbot-mqtt/status`.
+When disconnecting (graceful shutdown or unexpected loss of connection), `offline` will be reported on the same topic.
+
 ## Home Assistant 🏡
 
 ### Rationale

+ 16 - 0
switchbot_mqtt/__init__.py

@@ -27,6 +27,12 @@ from switchbot_mqtt._actors.base import _MQTTCallbackUserdata
 
 _LOGGER = logging.getLogger(__name__)
 
+_MQTT_AVAILABILITY_TOPIC = "switchbot_mqtt/status"
+# "online" and "offline" to match home assistant's default settings
+# https://www.home-assistant.io/integrations/switch.mqtt/#payload_available
+_MQTT_BIRTH_PAYLOAD = "online"
+_MQTT_LAST_WILL_PAYLOAD = "offline"
+
 
 def _mqtt_on_connect(
     mqtt_client: paho.mqtt.client.Client,
@@ -46,6 +52,11 @@ def _mqtt_on_connect(
         else mqtt_broker_host,
         mqtt_broker_port,
     )
+    mqtt_client.publish(
+        topic=userdata.mqtt_topic_prefix + _MQTT_AVAILABILITY_TOPIC,
+        payload=_MQTT_BIRTH_PAYLOAD,
+        retain=True,
+    )
     _ButtonAutomator.mqtt_subscribe(mqtt_client=mqtt_client, settings=userdata)
     _CurtainMotor.mqtt_subscribe(mqtt_client=mqtt_client, settings=userdata)
 
@@ -84,6 +95,11 @@ def _run(
         mqtt_client.username_pw_set(username=mqtt_username, password=mqtt_password)
     elif mqtt_password:
         raise ValueError("Missing MQTT username")
+    mqtt_client.will_set(
+        topic=mqtt_topic_prefix + _MQTT_AVAILABILITY_TOPIC,
+        payload=_MQTT_LAST_WILL_PAYLOAD,
+        retain=True,
+    )
     mqtt_client.connect(host=mqtt_host, port=mqtt_port)
     # https://github.com/eclipse/paho.mqtt.python/blob/master/src/paho/mqtt/client.py#L1740
     mqtt_client.loop_forever()

+ 6 - 0
tests/test_mqtt.py

@@ -65,6 +65,9 @@ def test__mqtt_on_connect(
             {},
             0,
         )
+    mqtt_client.publish.assert_called_once_with(
+        topic="whatever/switchbot_mqtt/status", payload="online", retain=True
+    )
     assert mqtt_client.subscribe.call_args_list == [
         unittest.mock.call("whatever/switch/switchbot/+/set"),
         unittest.mock.call("whatever/cover/switchbot-curtain/+/set"),
@@ -138,6 +141,9 @@ def test__run(
     )
     assert not mqtt_client_mock().username_pw_set.called
     mqtt_client_mock().tls_set.assert_called_once_with(ca_certs=None)
+    mqtt_client_mock().will_set.assert_called_once_with(
+        topic="homeassistant/switchbot_mqtt/status", payload="offline", retain=True
+    )
     mqtt_client_mock().connect.assert_called_once_with(host=mqtt_host, port=mqtt_port)
     mqtt_client_mock().socket().getpeername.return_value = (mqtt_host, mqtt_port)
     with caplog.at_level(logging.DEBUG):