How to publish to AWS MQTT after message was received - python

After importing the AWSIoTMQTTClient module with
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
I went ahead and configured the MQTT client connection
myMQTTClient = AWSIoTMQTTClient("my-clientid")
myMQTTClient.configureEndpoint("123abc-ats.iot.us-east-1.amazonaws.com", 8883)
myMQTTClient.configureCredentials(ROOT_KEY, PRIVATE_KEY, CERT)
myMQTTClient.connect()
I defined helloworld function that I want to use as a callback to catch the messages from the topic as:
def helloworld(client, params, packet):
print('...topic:', packet.topic)
print('...payload:', packet.payload)
myMQTTClient.publish(topic="home/fromserver", QoS=1, payload="{'message':'hello from server'}" )
Please note that the last line in the helloworld function I publish the message back to MQTT to the "home/from-server" topic.
I added two more lines to the script and run it
myMQTTClient.subscribe("home/to-server", 1, helloworld)
while True:
time.sleep(1)
I can fetch the messages from the to-server topic. But publishing the message to from-server topic crashes with AWSIoTExceptions.publishTimeoutException
How can I publish a message back to MQTT without raising the publishTimeoutException?

Related

How to keep a message within a string instead of showing it on CMD ? python

What does the channel.basic_consume' function return?
how i can access to message using variable i want consumed message and show it in browser?
i build django application send message to rabbitmq and consume messsage from it to show message
in browser like chat
import pika, sys
global message
def consume(room,username):
credentials = pika.PlainCredentials('admin', 'admin')
parameters = pika.ConnectionParameters('192.168.1.14',5672,'/', credentials)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
channel.exchange_declare(exchange='topic_exchange', exchange_type='topic')
result = channel.queue_declare('', exclusive=True)
queue_name = result.method.queue
arr= [room,username]
binding_key ='.'.join([str(i) for i in arr])
channel.queue_bind(exchange='topic_exchange', queue=queue_name, routing_key=binding_key)
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] %r:%r" % (method.routing_key, body))
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
global message
#message =
channel.start_consuming()
return message
This isn't going to work. You are running a process that is consuming the messages and printing them. Some other process (django) is listening for requests from your browser.
Not sure how you hope it will work, but consider these alternatives-
your consumer writes the messages to a file, and django reads that file when it gets a request
django connects to the message bus and reads all waiting messages when it gets a request
your consumer writes the messages to a database
You build a websocket application that can push messages to currently connected browsers when it receives a message

Move a message to subscription deadletter for failed HTTP request

I've been looking for resources but I can't seem to find what I need.. I have an Azure function with a Service Bus trigger. From this, I make an HTTP call with one of the values found in the Service Bus message.
An additional requirement for me is to deadletter a message if it the HTTP call fails. But as I understand it, the message is not present in the subscription anymore because it was properly received. Is there a way for me to keep the message in the subscription, and then dispose it once it is successful (transfer to DLQ if not?)
I found this piece of code but I'm not sure how it's sending to the DLQ?
https://github.com/Azure/azure-sdk-for-python/blob/azure-servicebus_7.3.0/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_deadlettered_messages.py
"""
Example to show receiving dead-lettered messages from a Service Bus Queue.
"""
# pylint: disable=C0111
import os
from azure.servicebus import ServiceBusClient, ServiceBusMessage, ServiceBusSubQueue
CONNECTION_STR = os.environ['SERVICE_BUS_CONNECTION_STR']
QUEUE_NAME = os.environ["SERVICE_BUS_QUEUE_NAME"]
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR)
with servicebus_client:
sender = servicebus_client.get_queue_sender(queue_name=QUEUE_NAME)
messages = [ServiceBusMessage("Message to be deadlettered") for _ in range(10)]
with sender:
sender.send_messages(messages)
print('dead lettering messages')
receiver = servicebus_client.get_queue_receiver(queue_name=QUEUE_NAME)
with receiver:
received_msgs = receiver.receive_messages(max_message_count=10, max_wait_time=5)
for msg in received_msgs:
print(str(msg))
receiver.dead_letter_message(msg)
print('receiving deadlettered messages')
dlq_receiver = servicebus_client.get_queue_receiver(queue_name=QUEUE_NAME, sub_queue=ServiceBusSubQueue.DEAD_LETTER)
with dlq_receiver:
received_msgs = dlq_receiver.receive_messages(max_message_count=10, max_wait_time=5)
for msg in received_msgs:
print(str(msg))
dlq_receiver.complete_message(msg)
print("Receive is done.")
Here is a code snippet in mine:
async def main(msg: func.ServiceBusMessage):
try:
logging.info('Python ServiceBus queue trigger processed message: %s',
msg.get_body().decode('utf-8'))
await asyncio.gather(wait(), wait())
result = json.dumps({
'message_id': msg.message_id,
'metadata' : msg.metadata
})
msgobj = json.loads(result)
val = msgobj['metadata']['value']
run_pipeline(val, msg)
except Exception as e:
logging.error(f"trigger failed: {e}")
TLDR; How do I keep the message in the subscription and either dispose them (if successful) or send them to the DLQ if not?
The code that you pasted is to Recieve Deadletter Messages from the deadletter queue.
I found some code in the docs. You can use this snippet from their example
from azure.servicebus import ServiceBusClient
import os
connstr = os.environ['SERVICE_BUS_CONNECTION_STR']
queue_name = os.environ['SERVICE_BUS_QUEUE_NAME']
with ServiceBusClient.from_connection_string(connstr) as client:
with client.get_queue_receiver(queue_name) as receiver:
for msg in receiver:
print(str(msg))
receiver.dead_letter_message(msg)
You can look at using this above code in your Exception handler
There're four methods to settle a message after receipt:
Complete:
Declares the message processing to be successfully completed, removing the message from the queue.
receiver.complete_message(msg)
Abandon:
Abandon processing of the message for the time being, returning the message immediately back to the queue to be picked up by another (or the same) receiver.
receiver.abandon_message(msg)
DeadLetter:
Transfer the message from the primary queue into the DQL.
receiver.dead_letter_message(msg)
Defer:
Defer is subtly different from the prior settlement methods. It prevents the message from being directly received from the queue by setting it aside.
receiver.defer_message(msg)
To answer your question "How do I keep the message in the subscription and either dispose them (if successful) or send them to the DLQ if not?":
keep the message in the subscription: use abandon_message
dispose them (if successful): use complete_message
send them to the DLQ: use dead_letter_message

Continuously receiving messages from Azure ServiceBus

According to the Azure ServiceBus docs here:
The ServiceBusReceiver class defines a high level interface for receiving messages from the Azure Service Bus Queue or Topic Subscription. The two primary channels for message receipt are receive() to make a single request for messages, and async for message in receiver: to continuously receive incoming messages in an ongoing fashion.
I have been attempting to use the async for message in receiver: advice to trigger a function everytime a message comes up, but I'm unsure how to do it right, as I have little experience working with async functions. Could someone familiar with async/service bus explain how the code should be formatted?
Edit: Let me provide some more context. I am creating a python flask service, and on start-up, I need it to start listening to messages on a topic/subscription_name. Whenever it receives a message, it will execute some code, then send a message back. So... how do I start an async listener on startup, and have it execute some code whenever it is triggered? It should also be able to process each message in a non-blocking way. So if two messages are received at once, both should be processed at the same time.
Note: I cannot use Azure Functions.
Assuming you are using topic-subscription, you can use below code:
#!/usr/bin/env python
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
"""
Example to show receiving batch messages from a Service Bus Subscription under specific Topic asynchronously.
"""
# pylint: disable=C0111
import os
import asyncio
from azure.servicebus.aio import ServiceBusClient
CONNECTION_STR = os.environ['SERVICE_BUS_CONNECTION_STR']
TOPIC_NAME = os.environ["SERVICE_BUS_TOPIC_NAME"]
SUBSCRIPTION_NAME = os.environ["SERVICE_BUS_SUBSCRIPTION_NAME"]
async def main():
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR)
async with servicebus_client:
receiver = servicebus_client.get_subscription_receiver(
topic_name=TOPIC_NAME,
subscription_name=SUBSCRIPTION_NAME
)
async with receiver:
received_msgs = await receiver.receive_messages(max_message_count=10, max_wait_time=5)
for msg in received_msgs:
print(str(msg))
await receiver.complete_message(msg)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Complete tutorial: Send messages to an Azure Service Bus topic and receive messages from subscriptions to the topic (Python)
Further, you can explore these samples (both sync and async versions): Azure Service Bus client library for Python Samples

Reading subscribed MQTT messages after reconnect

I am trying to read messages on a MQTT server. In some cases, the connection is unstable and requires to reconnect. But after reconnect, I am not able to receive any message from the topic that I previously subscribed to. I am using paho's python package to handle MQTT connection. Here is some code I am using
TopicName='some/topic/name'
class Counter:
def __init__(self, mqttClient):
self.messages_recieved = 0
self.mqttClient = mqttClient
self.mqttClient.subscribe(TopicName)
self.mqttClient.on_message = self.on_message
self.mqttClient.on_disconnect = self.on_disconnect
self.mqttClient.loop_start()
def on_message(self, client, userdata, message):
self.messages_received += 1
def on_disconnect(self, client, userdata, rc):
if rc != 0:
print("Trying to reconnect")
while not self.mqttClient.is_connected():
try:
self.mqttClient.reconnect()
except OSError:
pass
If my internet goes down, I am no longer able to receive messages. I have tried to subscribe again to the topic, also I have tried to call loop_start in the on_disconnect method, neither of those worked. Any solution would be helpful. Also to point out messages are being sent, I can see them in the browser on MQTT wall
You have not shown where you are calling connect, but the usual safe pattern is to put the calls to subscribe() in the on_connect() callback attached to the client.
This means that calls to subscribe will
Always wait until the connection has completed
Get called again automatically when a reconnect had happend
Not sure what module you are using, but most will require you to re-subscribe if you disconnect. Add your subscribe() call after your .reconnect() call and you should be good to go. Also, keep in mind that at QOS level 0, any messages that the broker received while you were disconnect, your client will NOT receive...only messages while the client is subscribed will be received by your client. If messages are published with the Retain flag, you client will receive the LAST one received by the broker...even if the client previously received it.

How do I send a response to a MQTT message?

I would like one RaspberryPi-A to send a massage to RaspberryPi-B, and RaspberryPI-B should send a massage back automatically. I know this is a beginners question, but I'm one and I have really struggled all day trying to find an anwser.
This is my client's code
import paho.mqtt.client as mqtt
MQTT_SERVER = "localhost"
MQTT_PATH = "test_channel"
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(MQTT_PATH)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
# more callbacks, etc
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, 1883, 60)
client.loop_forever()
And this is my publisher’s code
import paho.mqtt.publish as publish
MQTT_SERVER = "192.168.1.5"
MQTT_PATH = "test_channel"
publish.single(MQTT_PATH, "Hello World!", hostname=MQTT_SERVER)
How should i write the code differently so my client would return the massage for example: "Hello back"?
There are 2 kinds of messaging models:
Point to Point (one to one) - a message is sent from one application to another application via a queue. There can be more than 1 consuming (receiver) applications but only one of them will receive the message.
Publish / Subscribe - is where a message is published to a topic and multiple consumers (subscribers) will each receive a copy of the message. There can be 1 or more applications publishing messages to the same topic and 1 or more applications consuming (receiving) the messages.
MQTT is built on the Publish / Subscribe messaging model.
Your description sounds like you want Point to Point messaging. Yes, you can bend MQTT to act like Point to Point but be aware that if you have multiple applications publishing messages to the same topic, you may get confused.
MQTT_PATH = "test_channel"
publish.single(MQTT_PATH, "Hello World!", hostname=MQTT_SERVER)
There is no such thing as a "channel" in MQTT. Your code is publishing a message to the topic called: test_channel.
It is better to use a little hierarchy in your topic names.
i.e.
pivk95/food/burgers
pivk95/food/fries
pivk95/food/pizza
pivk95/food/burritos
pivk95/drink/shakes
pivk95/drink/soft_drink
Just remember that any number of applications can publish messages to a given topic and any number of applications can subscribe to a given topic and receive copies of the messages.

Categories