Mqtt check if subscribed topic has stopped publishing messages - python

I am trying to implement a way to know when a specific device has stopped publishing messages to an mqtt broker and in that case send an email to myself. I want to do this to be able to know if there is a problem with the device that is publishing the messages so I can check it and turn it back on. To try to accomplish this I created a mqtt client that subscribes to the topic that the device publishes e.g. test/device_1 and then set as last will and testament for that device status/device_1 where I put as payload="Offline". Ideally, I want to be able to do this for more than 1 device, but let's assume I just want it for the simple case of one device.
I created another script that implements another client that is subscribed to the topic status/device_1 and then on the on_message function it checks if it gets the payload="Offline" and if it does get it then I send an email to myself.
This approach however doesn't work as when I turn off my device, the mqtt client that is subscribed to the topic test/device_1 keeps listening but gets no messages. In other words, it doesn't send its last will even when the topic is empty. However, it seems to work when I stop the script that is subscribed to the topic test/device_1.
Am I missing something or is it not possible to accomplish what I am trying to do? Any advice is appreciated!

First LWT messages are only published by the broker if the client goes offline unexpectedly, which means if it shuts down cleanly then it will not get published, you have to manually publish a message as part of shut down process.
You can set the retained flag on the LWT so that any client that subscribes after the device has gone offline it will still see the state message.
You should also clear that message on when the device starts up, either by publishing something like Online or a null payload to clear the retained message.

You can use last timestamp when device published the messages as heartbeat and in your another script, if (current_time - last_timestamp) > 30 then you can email yourself that your device is offline. this way you can have threshold of time when you want to get email of device offline.
script 1:
mqttCient.on_message(msg):
last_timestamp = time.time()
script 2:
cur_time = time.time()
if ((cur_time - last_timestamp) > 30):
# email yourself
use Json file or database as buffer for storing and accessing last_timestamp

Related

MQTT How to know the Broker Status

In a web application with MQTT in python (using paho-mqtt lib) I would like to know if there is a way to get the broker status in real time, because the only way that i find is to store the variable "rc" into the method on_connect but it's more like a client/connection state.
EDIT 1 : after reading mosquitto broker documentation, i found that you can subscribe to '$SYS/broker/connection/#' which is supposed to give you back 1 if the connection is up and 0 if it goes down. However when i do :
subscribe.callback(self.message_callback, '$SYS/broker/connection/#', port = port, hostname=broker, auth=authentication, protocol=client.MQTTv31, tls=TLS)
impossible to get payload and topic this message although i'm doing exactly the same command to get messages from my sensors except that the topic is '#' and it's working perfectly.
Does anyone knows why ?
There is no way to poll the state of the connection to the broker from the client.
The on_disconnect callback should be called when the connection to the broker is dropped.
This should be kicked off when the keep alive times out, but also as the result of a failure to publish (if you try to publish data before the timeout expires).
Also the rc from a call to the publish command will indicate if the connection has dropped.

How to write a function that awaits for a message from MQTT before continuing the program?

I am trying to send a message using publish.single and then receive it and act upon the data received. Hence, I can't proceed unless I receive something from the server, so is there a way to write a statement that will wait for a message from MQTT before proceeding?
Example code:
publish.single("$topic", data, ip_address)
#can't do anything here
receive(data_from_broker) #or anythin that looks like it!
#continue with the program here
The short answer is you don't.
At least not in the way you describe. MQTT is an asynchronous protocol, there is no sense of sending a message and waiting for a response, a publishing client has no way to know if the is 0, 1 or n subscribing clients listening on the topic the message is published.
You will need to build something called a state machine to keep track of where in the program flow you are when messages are received.
e.g.
Application published message and sets flag in the state machine to say the message was sent
Remote client receives message and publishes a response
New message is received by the first client, it checks the state machine to determine that the message should be treated as a response to the original message.
To subscribe to a topic you will have to move on from using publish.single to the full MQTT client so you can setup the onMessage callback to handle the incoming messages.

How does redis publish work?

Suppose that there is one redis-client which is subscribing to channel c1 and another redis-client publishes "data" to channel c1.
At this point, does the data published is pending in a redis-server by when the client subscribing to "c1" get the data(by calling pubsub.listen() or pubsub.get_message()) or go directly to the client subscribing to the channel c1 through a redis-server?
In other words, When a redis-client call pubsub.getMessage() or pubsub.listen(), does redis-client send a request to redis-server to get data or just get data from the local socket buffer?
When I read some documents it is saying that pubsub.get_message() use select module for a socket internally.
It seems to mean that the data subscribed already is in the client local buffer, not server.
Could you give me any suggestion?
When a client does PUBLISH, this command immediately pushes the message into all sockets that are interested in it. The message is not stored in redis. If a client wasn't subscribed at the time of publishing, he will never see the message.
I'm not familiar with python driver for redis, but judging from the names, I'd guess that listen sends a SUBSCRIBE command and get_message takes a message from the local buffer.
Redis pubsub is fire and forget.
In other words, when a publish command is sent, the message is received by online subscribers, and who wasn't subscribed/listening for messages when the publish command was sent, won't never get these messages.

EWS Push Subscription, how to know when it expires?

I am subscribing to EWS push notifications for calendar events using python. https://msdn.microsoft.com/en-us/library/office/dd636171(v=exchg.80).aspx
When doing the same thing with google, you get an "expires" date in the first request, so you know when you need to renew the subscription.
How do I know when the EWS subscription is going to expire so I can renew?
There is no real timeout property for push notifications. Exchange push notifications works in a slightly different way, as alluded to by the time-out section in the documentation:
If the server does not receive a response to a push notification or
status ping, it retries sending the notification several times before
it stops sending the notifications.
So you do not subscribe for a set amount of time. You will get notifications as long as you respond to the server and acknowledge that you received the notification. The server will stop sending notifications to you when you stop sending status pings to every push notification.
How many times the Exchange server should retry and ask you for a status ping can be specified in the initial subscription request, with the StatusFrequency-element. You simply specify for how many minutes the server should ask you for an acknowledgement before giving up and stop pushing notifications to you.
Webdav101's article on the topic is really good, and he states that it is up to you to have some fallback code for when subscriptions stops for some reason. That could be handled by simply issuing a new push subscription if you have not received a notification for a while.

What is the best design for polling a modem for incoming data?

I have a GSM modem connected to my computer, i want to receive text messages sent to it using a python program i have written, am just wondering what is the best technique to poll for data.
Should i write a program that has a infinite loop that continuously checks for incoming sms's i.e within the loop the program sends the AT commands and reads the input data. or do modems have a way of signaling an application of an incoming data(sms).
Am trying to imagine a cellphone is just a GSM modem, and when an sms is received, the phone alerts you of the event, or does the phone software have an infinite loop that polls for incoming data.
I have written something similar before. There is a way using AT commands to tell the modem to signal you each time an SMS is received.
For reference, I was using a Maestro 100 GSM Modem in an embedded application.
First you have to initialize the modem properly. I was using text mode for the SMS, but you might be using something different. Pick from these what you want. AT+CNMI is the most important.
AT&F0 # Restore factory defaults
ATE0 # Disable command echo
AT+CMGF=1 # Set message format to text mode
AT+CNMI=1,1,0,1,0 # Set new message indicator
AT+CPMS="SM","SM","SM" # Set preferred message storage to SIM
You would then wait for a message notification, that will look like this. (Don't match on the index number, that might differ between notifications)
+CMTI: "SM",0 # Message notification with index
When you get that notification, retrieve the unread SMS's:
AT+CMGL="REC UNREAD" # Retrieve unread messages
I would recommend you also add a poll, maybe every 5 minutes or so, just in case you miss a notification. With serial comms you can never be sure!
I find I can't remember much of the AT command set related to SMS. Andre Miller's answer seems to ring a few bells. Anyway you should read the documentation very carefully, I'm sure there were a few gotchas.
My recommentation for polling is at least every 5 seconds - this is just for robustness and responsiveness in the face of disconnection.
I used a state machine to navigate between initialisation, reading and deleting messages.

Categories