Skip to content

Commit 2943c8d

Browse files
authored
feat: Add MQTT message retention and client status topic (#22)
1 parent 6fbcf4a commit 2943c8d

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ APS2MQTT configuration can be provided by a yaml config file or by environment v
108108
| MQTT_BROKER_PASSWD | User password of the MQTT broker | "itsasecret" | "" |
109109
| MQTT_CLIENT_ID | Client ID if the MQTT client | "MyAwesomeClient" | "APS2MQTT" |
110110
| MQTT_TOPIC_PREFIX | Topic prefix for publishing | "my-personal-topic" | "" |
111+
| MQTT_RETAIN | Retain MQTT messages | True | False |
111112
| MQTT_BROKER_SECURED_CONNECTION | Use secure connection to MQTT broker | True | False |
112113
| MQTT_BROKER_CACERTS_PATH | Path to the cacerts file | "/User/johndoe/.ssl/cacerts" | None |
113114

@@ -150,6 +151,7 @@ mqtt:
150151
MQTT_BROKER_PORT: 1883
151152
MQTT_BROKER_USER: 'johndoe'
152153
MQTT_BROKER_PASSWD: 'itsasecret'
154+
MQTT_RETAIN: True
153155
```
154156
155157
#### Secured connection
@@ -194,6 +196,8 @@ services:
194196
195197
The aps2mqtt retrieve from the whole PV array as a whole as well as each individual inverter in detail.
196198
199+
* aps/status - current status of the service, `online` or `offline`. The `offline` message is sent using LWT
200+
197201
### ECU data
198202

199203
* aps/[ECU_ID]/power - total amount of power (in W) being generated right now

aps2mqtt/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def __init__(self, cfg):
1515
self.broker_passwd = cfg.get("MQTT_BROKER_PASSWD", "")
1616
self.client_id = cfg.get("MQTT_CLIENT_ID", "APS2MQTT")
1717
self.topic_prefix = cfg.get("MQTT_TOPIC_PREFIX", "")
18+
self.retain = str2bool_exc(str(cfg.get("MQTT_RETAIN", False)))
1819
self.secured_connection = str2bool_exc(
1920
str(cfg.get("MQTT_BROKER_SECURED_CONNECTION", False))
2021
)

aps2mqtt/mqtthandler.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ def __init__(self, mqtt_config):
2121
mqtt_config.topic_prefix + "/" if len(mqtt_config.topic_prefix.strip()) > 0 else ""
2222
)
2323
self.client = None
24+
self.status_topic = self.topic_prefix + "aps/status"
2425

2526
def on_connect(self, client, userdata, flags, reason_code, properties):
2627
"""Callback function on broker connection"""
27-
del client, userdata, flags, properties
28+
del userdata, flags, properties
2829
if reason_code == 0:
2930
_LOGGER.info("Connected to MQTT Broker!")
31+
self._publish(client, self.status_topic, "online", retain=True)
3032
else:
3133
_LOGGER.error("Failed to connect: %s", reason_code)
3234

@@ -35,10 +37,13 @@ def on_disconnect(self, client, userdata, flags, reason_code, properties):
3537
del client, userdata, flags, properties
3638
_LOGGER.info("Disconnected from MQTT Broker: %s", reason_code)
3739

38-
def _publish(self, client, topic, msg):
39-
result = client.publish(topic, msg)
40+
def _publish(self, client, topic, msg, retain=False):
41+
# If mqtt_retain is True in config, all messages are retained.
42+
# Otherwise, only LWT uses retain.
43+
actual_retain = retain or self.mqtt_config.retain
44+
result = client.publish(topic, msg, retain=actual_retain)
4045
if result.rc == 0:
41-
_LOGGER.debug("Send `%s` to topic `%s`", msg, topic)
46+
_LOGGER.debug("Send `%s` to topic `%s` (retain=%s)", msg, topic, actual_retain)
4247
else:
4348
_LOGGER.error("Failed to send message to topic %s: %s", topic, result.rc)
4449

@@ -72,6 +77,9 @@ def connect_mqtt(self):
7277
else:
7378
_LOGGER.debug("Use unsecured connection")
7479

80+
_LOGGER.debug("Set LWT on topic '%s'", self.status_topic)
81+
self.client.will_set(self.status_topic, "offline", qos=1, retain=True)
82+
7583
self.client.on_connect = self.on_connect
7684
self.client.on_disconnect = self.on_disconnect
7785

@@ -82,7 +90,13 @@ def connect_mqtt(self):
8290
)
8391
self.client.connect_async(self.mqtt_config.broker_addr, self.mqtt_config.broker_port)
8492
self.client.loop_start()
85-
atexit.register(self.client.loop_stop)
93+
atexit.register(self.disconnect)
94+
95+
def disconnect(self):
96+
if self.client.is_connected():
97+
_LOGGER.info("Publishing 'offline' status on graceful exit.")
98+
self._publish(self.client, self.status_topic, "offline", retain=True)
99+
self.client.loop_stop()
86100

87101
def publish_values(self, data):
88102
"""Publish ECU data to MQTT"""

0 commit comments

Comments
 (0)