Responding in MQTT with Python - python

I'm having a little bit of a delay-issue in my MQTT Python (v2.7) script that has me wondering...
So I have one device request a function to another device. Let's call them A and B.
So A sends out a MQTT message to do something, and B does that function. I have A send it out by a normal publish method. There are no issues here.
B gets the published message with the part:
def on_message(client, userdata, msg):
if msg.topic == "action":
>> then do something here <<
Also there seem to be no issues here. It gets the message and it performs the action.
The problem gets here when I try to report back what it's going, which looks like this:
def on_message(client, userdata, msg):
if msg.topic == "action":
>> then do something here <<
client.publish("report", payload=message1, qos=2, retain=False)
>> then do some more action here <<
client.publish("report", payload=message2, qos=2, retain=False)
The problem is not that it doesn't do the action nor that it doesnt do the action, but it seems that it will do both, but rather in a very strange order, like:
action
action
(several seconds wait)
message1
message2
This doesn't seem right? How can I make the script send out the message before it's doing the second part?

This is working as expected.
The network loop is a single thread which is already handling the incoming message. The publishes are queued up until the on_message function completes and then the network loop will handle these queued publishes

TCP stack is asynchronous. When you call for sending data, it does not mean that it goes out immediately. There is an event loop running behind your code. If you want to do something in sequence, you must break your sequential tasks into separate functions and call them on next on_publish() when the message was really sent out.

I was able to send out messages using the library:
import paho.mqtt.publish as mqttc
and using a:
mqttc.single("report", payload=message1, qos=2, hostname=XXXX, port=XXXX)
which will follow the natural flow of the script and still send out the message.

Related

How do i make a socket in python to be able to receive but also to send in a while true loop?

So, if i want to make a "chat" with python sockets, i need to be able to write a message and send it anytime i want, maybe by doing something like this:
while True:
msg = input()
socket.send(msg)
But, if i do that, i will not be able to use socket.recv() without making python wait for a message and stop the program until it gets received, i tried to solve this with threading but it of course can't work like that. How can i solve this?
Below the attempt by threading.
def receive():
while True:
client.recv(2048)
looprecv = threading.Thread(target=receive())
looprecv.start()
while True:
message = input("messaggio: ")
send(message)
if message == "!exit":
break

How can i interrupt my function to stop sending data to my angular server

I have my Angular server which plots my Data I get from a python-bokeh Server. On my Frontend, I have a Button which calls my function getData(). This function sends a Message over a Websocket connection to my Python Server. In this message, there is a String which function should be called. When the python server received the message "getData" he collects the Data and sends them to the angular server. But now I want to stop sending data to my angular server(because the Stop Button is pressed).
My Problem: Either I do a while loop to send data the whole time, but then I cant stop the function or I don't use a while loop but then I have to send messages to my python server the whole time with a time delay.
In Python my Code ist something like :
while websocketconnection == true:
imp = getMessage()
FunctionString == imp['name']
if(FunctionString == 'getData'):
*get the Data and send them back to angular*
if(FunctionString == 'Stop'):
*close socket connection(not websocket connection)*
...(*some more not relevant functions*)
I will recommend a way I used in the past. You can use multithreading to handle such bahaviour.
Then you either do quick and dirty:
in another thread you assign global value of websocketconnection to be False
or
you can create some Event and Signal, so once you trigger button it will perform some logic
PS
in python you can do just:
while websocketconnection:
imp = getMessage()
..............

How to interrupt in python

my subscribe function will call on_message function everytime that have message from websocket
and unsubscribe when message is STOP
is_sub = True
def on_message(msg):
print(msg)
if msg == "STOP":
unsubscribe(key)
is_sub = False
#continue to code
print("Start")
key = subscribe(on_message)
while is_sub:
print("on sub")
time.sleep(1)
#cotinue here
print("End")
without while loop the code will end and not recive any more message.
I want to find the better way (without time.sleep) to interrupt and continue the code
ps. I can't edit subscribe and unsubscribe function
You could run the instance of your websocket server in a separate thread. This will allow you to still continue to run your main thread while your webserver is listening to incoming messages.
I think you can't do it without a while loop. If you want to free your main thread you can do your message subscription on separate thread but that's not what you want I guess. Most WebSocket client would provide a method to keep the connection alive. for example this provides a run_forever() methods which does the 'while loop' part for you. If you are using a client there is a chance that they provide methods for keeping the connection alive. I suggest you go through the documentation once more.
If you want to continue the code, you could use the continue() command and if you want to stop, you could use the break() command.

Pika python asynchronous publisher: how to send data from user via console?

I am using the standard asynchronous publisher example. and i noticed that the publisher will keep publishing the same message in a loop forever.
So i commented the schedule_next_message call from publish_message to stop that loop.
But what i really want is for the publissher to start and publish only when a user give it a "message_body" and "Key"
basically publisher to publish the user inputs.
i was not able to fin any examples or hints of how to make the publisher take inputs from user in real time.
I am new to raabitmq, pika, python e.t.c
here is the snippet of code i am talking about :-
def publish_message(self):
"""If the class is not stopping, publish a message to RabbitMQ,
appending a list of deliveries with the message number that was sent.
This list will be used to check for delivery confirmations in the
on_delivery_confirmations method.
Once the message has been sent, schedule another message to be sent.
The main reason I put scheduling in was just so you can get a good idea
of how the process is flowing by slowing down and speeding up the
delivery intervals by changing the PUBLISH_INTERVAL constant in the
class.
"""
if self._stopping:
return
message = {"service":"sendgrid", "sender": "nutshi#gmail.com", "receiver": "nutshi#gmail.com", "subject": "test notification", "text":"sample email"}
routing_key = "email"
properties = pika.BasicProperties(app_id='example-publisher',
content_type='application/json',
headers=message)
self._channel.basic_publish(self.EXCHANGE, routing_key,
json.dumps(message, ensure_ascii=False),
properties)
self._message_number += 1
self._deliveries.append(self._message_number)
LOGGER.info('Published message # %i', self._message_number)
#self.schedule_next_message()
#self.stop()
def schedule_next_message(self):
"""If we are not closing our connection to RabbitMQ, schedule another
message to be delivered in PUBLISH_INTERVAL seconds.
"""
if self._stopping:
return
LOGGER.info('Scheduling next message for %0.1f seconds',
self.PUBLISH_INTERVAL)
self._connection.add_timeout(self.PUBLISH_INTERVAL,
self.publish_message)
def start_publishing(self):
"""This method will enable delivery confirmations and schedule the
first message to be sent to RabbitMQ
"""
LOGGER.info('Issuing consumer related RPC commands')
self.enable_delivery_confirmations()
self.schedule_next_message()
the site does not let me add the solution .. i was able to solve my issue using raw_input()
Thanks
I know I'm a bit late to answer the question but have you looked at this one?
Seems to be a bit more related to what you need than using a full async publisher. Normally you use those with a Python Queue to pass messages between threads.

server sent event to multiple clients from Flask

I am playing around with a small project to get a better understanding of web technologies.
One requirement is that if multiple clients have access to my site, and one make a change all the others should be notified. From what I have gathered Server Sent events seems to do what I want.
However when I open my site in both Firefox and Chrome and try to send an event, only one of the browsers gets it. If I send an event again only one of the browsers gets the new event, usually the browser that did not get event number one.
Here is the relevant code snippets.
Client:
console.log("setting sse handlers")
viewEventSource = new EventSource("{{ url_for('viewEventRequest') }}");
viewEventSource.onmessage = handleViewEvent;
function handleViewEvent(event){
console.log("called handle view event")
console.log(event);
}
Server:
#app.route('/3-3-3/view-event')
def view_event_request():
return Response(handle_view_event(), mimetype='text/event-stream')
def handle_view_event():
while True:
for message in pubsub_view.listen():
if message['type'] == 'message':
data = 'retry: 1\n'
data += 'data: ' + message['data'] + '\n\n'
return data
#app.route('/3-3-3/test')
def test():
red.publish('view-event', "This is a test message")
return make_response("success", 200)
My question is, how do I get the event send to all connected clients and not just one?
Here are some gists that may help (I've been meaning to release something like 'flask-sse' based on 'django-sse):
https://gist.github.com/3680055
https://gist.github.com/3687523
also useful - https://github.com/jkbr/chat/blob/master/app.py
The first thing I notice about your code is that 'handle_view_event' is not a generator.
Though it is in a 'while' loop, the use of 'return' will always exit the function the first time we return data; a function can only return once. I think you want it to be 'yield' instead.
In any case, the above links should give you an example of a working setup.
As Anarov says, websockets and socket.io are also an option, but SSE should work anyway. I think socket.io supports using SSE if ws are not needed.

Categories