Closed RichardMore closed 1 week ago
I can't reproduce this, i.e. works perfectly here.
Which MQTT broker are you using and which MQTT client do you have subscribed to the status
topic to receive the last will message? Have you checked the broker server logs?
It is the responsibility of the server to publish the last will message and of course only clients subscribed (in your example) to the status
topic will receive it. Depending on what value MQTT_ROOT
has, your client code above does not subscribe to this topic, so it will not receive the disconnected
messages on re-connect, even if retain=True
is set for the last will.
For reference, here's the code, with which I tested this. If MQTT_ROOT
is changed to ''
(empty string), this client will receive messages to the status
topic and so, on re-connect, will receive its own last will message from the previous disconnect.
from umqtt.simple import MQTTClient
MQTT_CLIENT = 'upy'
MQTT_SERVER = '127.0.0.1'
MQTT_ROOT = '/'
def sub_cb(topic, msg):
print((topic, msg))
client = MQTTClient(client_id=MQTT_CLIENT, server=MQTT_SERVER)
client.set_last_will('status', 'disconnected', retain=True)
client.set_callback(sub_cb)
client.connect()
client.subscribe(MQTT_ROOT + '#')
client.publish('status', 'connected', retain=True)
try:
while True:
client.wait_msg()
except KeyboardInterrupt:
pass
I am using the public Cloudmqtt and I am checking the messages through the websocket UI which shows every topic. Just as a side note, a Ubutntu based server that has a mosquitto service attached to it has a las will as well and I receive those, so probably the broker side is good from Cloudmqtt. Here is my full code I am testing with:
from umqtt.simple import MQTTClient
import wifi
# init program
wifi.do_connect()
MQTT_SERVER = 'm21.cloudmqtt.com'
MQTT_PORT = <PORT>
MQTT_USER = <USER>
MQTT_PASS = <PASSWORD>
MQTT_TIMEOUT = 30
MQTT_CLIENT = <ID>
MQTT_ROOT = <ROOT>
client = None
topic_l1 = 'sensors/'
# helper methods
def mqtt_publish(topic_l2, payload, retain=False, qos=0):
client.publish(MQTT_ROOT + topic_l1 + topic_l2, payload, retain, 0)
print('mqtt published msg: %s; to topic: %s' % (payload, MQTT_ROOT + topic_l1 + topic_l2))
def sub_cb(topic, msg):
print('got msg')
client = MQTTClient(client_id=MQTT_CLIENT, server=MQTT_SERVER, port=MQTT_PORT, user=MQTT_USER, password=MQTT_PASS)
client.set_last_will('status', 'disconnected', retain=True)
client.set_callback(sub_cb)
client.connect()
client.subscribe(MQTT_ROOT + '#')
print('mqtt connected to %s, subscribed to %s topic' % (MQTT_SERVER, MQTT_ROOT))
mqtt_publish('status', 'connected', retain=True)
try:
while True:
client.wait_msg()
except KeyboardInterrupt:
pass
Also I am running the code on a NodeMCU ESP8266 board.
Thank you.
I am using the public Cloudmqtt and I am checking the messages through the websocket UI which shows every topic. Just as a side note, a Ubutntu based server that has a mosquitto service attached to it has a las will as well and I receive those, so probably the broker side is good from Cloudmqtt.
I don't follow. If it works with the mosquito server (with which I tested it successfully as well), but not with Cloumqtt, my guess would be that Cloudmqtt is to blame.
Also I am running the code on a NodeMCU ESP8266 board.
I've only tested it with the micropython unix port so far, but knowing the umqtt.simple
code very well, I don't see were this would make any difference. If the client sends the last will topic and message successfully when connecting to the broker, everything else is up to the broker.
There was a discussion on this topic at the forum here:
https://forum.micropython.org/viewtopic.php?f=2&t=5242
The gist of it is: if no keepalive timout is set when connecting and the connection to the client is lost, e.g in the case of power loss, and the client doesn't / can't close the socket properly, mosquitto does not realize the connection is gone, until either it tries to publish a message to the client or the client reconnects. Then it will publish the last will.
The lesson from this is: if you want the last will to be sent reliably as soon as possible, set a keepalive timeout and use client.ping()
regularly within the timeout period.
Setting keepalive seems to avoid this problem. Proposing to close this issue.
Setting keepalive seems to avoid this problem. Proposing to close this issue.
Note also this refers to a keepalive timeout on the server. Reliable last will delivery depends on the server noticing the client has gone away.
Last will message is not sent when Nodemcu loses power.
Code:
The "connected" message is delivered after connection and topic subscribe, but no "disconnected" message ever.