Please try using the latest umqtt library and then provide a minimal reproducible test case that shows the error.
PINGRESP ignored in umqtt.simple.py
Hello,
In wait_msg, the PINGRESP message is ignored:
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
Shouldn't this return some information so that the calling code can determine if the server is indeed responding to pings?
"OSError: -1" if use keepalive>0
Traceback (most recent call last):
File "main.py", line 55, in <module>
File "umqtt/simple.py", line 202, in check_msg
File "umqtt/simple.py", line 171, in wait_msg
OSError: -1
guess i'll just take over this issue thread ;)
when using keepalive>0, server disconnects from client and client raises an exception in given line 171 in wait_msg. So the socket disconnection is being correctly detected.
disregard my error description below! (only if you have the same problem and need a solution)
the solution was to connect to the mqtt server with mqtt.connect(False) as only then a persistent session is started and the subscriptions are stored between connection problems. see #186
I forgot that in the connect method at the beginning and did it only in the reconnect function..
the only problem i have left is that with a restart of mosquitto, mosquitto loses all subscriptions although persistence is on. but this is not an issue of this library.
now to the original issue:
i did set a last will message that is correctly send by the server.
After this exception my client tries to reconnect and does it correctly (mqtt.connect(False) or True, does not make a difference here).
I confirm the connection by sending out an online status from the client.
Sending a message to the client now does nothing. the client just does not appear to get the message.
my thoughts on this so far:
- connection is there as the client sends a message to the server
- function check_msg is called without an exception as i'm monitoring it with an output
- the set callback is not called
Steps to reproduce:
- set last will
- catch exception in wait_msg, reconnect and let it send a message for proof
- connect to server with keepalive>0 without sending any messages or pings
- subscribe to a topic and have a callback printing new messages
- wait until connection breaks
- last will is being sent and shortly after that client sends the reconnection message proofing the connection
- send something to the subscribed topic
- that message should show up but it does not
maybe i have a misconfigured server, won't exclude that possibility although it would be rather strange if that is the problem.
I'm using a recent version of the mosquitto server.
I had same problem with continue disconnecting from the mqtt server with keepalive > 0.
But I figure it out that disconnection happens because there was no any activity from my board with mqtt server during the period of time like keepalive value of seconds.
So if the board will publish any mqtt message ("i'm alive") - the connection will not drop.
I program to send the current board time to the debug topic during the half of the keepalive value of seconds. And it is working like a charm!
If I correct this issue is not an issue it is a feature.
If you set keepalive value - you have to send something to mqtt server to inform that you are alive in less time than keepalive value of seconds.
I'm not sure is it task for mqtt client to keep connection alive in time.
The umqtt/simple.py lib is only sending information to the server about keepalive time.
Nothing more. It looks that this task to user who use this lib.
The Keep Alive is a time interval measured in seconds. Expressed as a 16-bit word, it is the maximum time interval that is permitted to elapse between the point at which the Client finishes transmitting one Control Packet and the point it starts sending the next. It is the responsibility of the Client to ensure that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client MUST send a PINGREQ Packet [MQTT-3.1.2-23].
The Client can send PINGREQ at any time, irrespective of the Keep Alive value, and use the PINGRESP to determine that the network and the Server are working.
If the Keep Alive value is non-zero and the Server does not receive a Control Packet from the Client within one and a half times the Keep Alive time period, it MUST disconnect the Network Connection to the Client as if the network had failed [MQTT-3.1.2-24].
If a Client does not receive a PINGRESP Packet within a reasonable amount of time after it has sent a PINGREQ, it SHOULD close the Network Connection to the Server.
A Keep Alive value of zero (0) has the effect of turning off the keep alive mechanism. This means that, in this case, the Server is not required to disconnect the Client on the grounds of inactivity.
Note that a Server is permitted to disconnect a Client that it determines to be inactive or non-responsive at any time, regardless of the Keep Alive value provided by that Client.Non normative comment
The actual value of the Keep Alive is application specific; typically this is a few minutes. The maximum value is 18 hours 12 minutes and 15 seconds.
that's why I call mqtt.ping() regularly. Together with last will this shows the device state in home-assistant.
But I do not check if the server actually answers the request. If the server is down, the socket breaks anyways, throwing an exception, so the only problem left would be a mqtt server that is stuck, but this should be really rare.
I'm using about a minute as keepalive.
The problem remains unsolved.
I also have this problem.
Hi! look this project https://github.com/leech001/Security-fire-alarm-ESP8266
I think I solved the problem there
keepLiveTime = 120
c = MQTTClient(CLIENT_ID, server, 1883, username, password, keepLiveTime)
tim = Timer(-1)
tim.init(period=keepLiveTime*1000, mode=Timer.PERIODIC, callback=lambda t: keepLiveTimeCb(c))
def keepLiveTimeCb(c):
c.ping()
shell use ping() func
I've explored this issue and its comments and believe it can be closed:
- In the OPs example, the behaviour is expected - the client must periodically
ping()the broker, or otherwise send the broker some traffic to communicate that it's still alive. - The "original issue" outlined by @kevinkk525 seems to be a different problem: messages not received after reconnecting - There are many reasons why this can occur: broker not set to support sessions,
connect()called withoutclean_session=False, etc. If it is reproducible, some code, and a new issue would be great. However, it looks like this was resolved using a periodicping() - Other comments contain helpful tips that could be considered for inclusion as examples.
您好,您的邮件已收到。
I'm going to have to upvote this... I feel like this should be the case as well. umqtt.robust doesn't fix this either. We need to know if the connection is still active or not.
I found some code on https://github.com/AntonisKekempanos/SonoffMicropythonMQTT.git
Where they return b'PINGRESP' this seems like an appropriate return code for the ping.
I don't know much about mqtt however from a quick search it appears that clients (like this module) are supposed to send a PINGREQ to the broker regularly, to which the broker responds with PINGRESP.
Changing wait_msg to return something different when this comes in would affect existing users of the library who haven't had to expect this message and know how to deal with it.
Perhaps instead of returning something, The library could have a new attribute in the mqtt client class where a timestamp is updated every time one of these comes in, that way an application that cares about it can query that attribute to see how long it's been since the last server communication?
+1 I love that idea! That would help with about half the code I'd be trying to write to check the time intervals between pings. So yes, love it!
@andrewleech were you thinking of https://github.com/fizista/micropython-umqtt.simple2.git when you suggested having it be an attribute of the client? Because it seems like that's exactly what's been implemented.
I've never seen that library myself, to be honest I haven't used mqtt at all.
@michaeka79 Maybe you have any ideas to fix it?
@nfj25 did you solve your problem?
Not using it anymore...
Spent some time trying to figure out why pings weren't working before finding this issue. Is there a rationale behind this? The docs even seem to imply that this should be handling the ping
That implies to me not that the ping is ignored, but that
wait_msgwill tell you a ping has been responded to.I've forked this and swapped the
Nonereturn for ab"PINGRESP", as someone suggested above, and it seems to work fine. However I'm not using any subscriptions on my end so maybe this messes that up? If it does maybe we could instead set a flag on the client that indicates the ping has been responded to and then clear it upon the next ping?I'm happy to make either change, they are very straightforward, not sure though if this is actually a desired change.
My understanding is that none of the current owners / maintainers of micropython-lib really use or know much about mqtt - hence this library hasn't seen any real work or expansion.
As such I really don't know if there's anyone who could really answer your question about the correct way to handle this, or what should be done to fix it.
I opened a pr with the solution I've been using locally. It's minimally invasive and non-breaking which is why I went with this approach although I'm not necessarily the most python oriented dev so it's possible this is an unusual approach in python. But I wanted to propose it since this issue has been open for some time and the current
pingcode doesn't seem as useful as it could be.Yes, there is some thing to change her. Maybe the doc, or the code. but I passed half a day searching to test
if is connectedFinally, my function
but not sure what append if server is down.