I'm learning how to use MQTT on AWS IoT - the goal is to simply publish and receive between AWS IoT MQTT test client and a Python script.
I can successfully publish from my Python code but I am unable to receive.
Publish works if I set QOS to "AT_MOST_ONCE" and I in this case successfully receive "Hi" in AWS. If I set QOS to AT_LEAST_ONCE it does NOT work and remains stuck on ""Waiting for publish to complete...".
It should be further noted that when I tried to loop publish with a 2.5s sleep between it crashed with a no connection error after successfully sending one "Hi" message.
from awscrt import io, mqtt, auth, http
from awsiot import mqtt_connection_builder
import time
# Define the same connection parameters as your publish script
ENDPOINT = "123.iot.eu-north-1.amazonaws.com"
CLIENT_ID = "pc-v3"
PATH_TO_CERTIFICATE = "certificates/certs-certificate.pem.crt"
PATH_TO_PRIVATE_KEY = "certificates/certs-private.pem.key"
PATH_TO_AMAZON_ROOT_CA_1 = "certificates/AmazonRootCA1.pem"
TOPIC = "mqtt_test"
def publish_message(message: str):
print(f"Attempting to publish message: {message}")
publish_future, packet_id = mqtt_connection.publish(
topic=TOPIC,
payload=message,
qos=mqtt.QoS.AT_MOST_ONCE
)
print("Waiting for publish to complete...")
publish_future.result()
print("Publish completed")
# Define callback for incoming messages
def on_message_received(topic, payload, **kwargs):
print(f"Received message from topic '{topic}': {payload}")
# Spin up resources
event_loop_group = io.EventLoopGroup(1)
host_resolver = io.DefaultHostResolver(event_loop_group)
client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)
mqtt_connection = mqtt_connection_builder.mtls_from_path(
endpoint=ENDPOINT,
cert_filepath=PATH_TO_CERTIFICATE,
pri_key_filepath=PATH_TO_PRIVATE_KEY,
client_bootstrap=client_bootstrap,
ca_filepath=PATH_TO_AMAZON_ROOT_CA_1,
client_id=CLIENT_ID,
clean_session=False,
keep_alive_secs=60
)
print(f"Connecting to {ENDPOINT} with client ID '{CLIENT_ID}'...")
connect_future = mqtt_connection.connect()
connect_future.result()
print("Connected!")
print(f"Subscribing to topic '{TOPIC}'...")
subscribe_future, packet_id = mqtt_connection.subscribe(
topic=TOPIC,
qos=mqtt.QoS.AT_LEAST_ONCE ,
callback=on_message_received
)
publish_message("Hi")
When I try to receive the messages in my Python code, it does not work even with AT_MOST_ONCE. The latter part of the snippet is bellow and it gets stuck on the first "Subscribed and listening for messages..." as I'm publishing messages on AWS MQTT test client.
print(f"Connecting to {ENDPOINT} with client ID '{CLIENT_ID}'...")
connect_future = mqtt_connection.connect()
connect_future.result()
print("Connected!")
print(f"Subscribing to topic '{TOPIC}'...")
subscribe_future, packet_id = mqtt_connection.subscribe(
topic=TOPIC,
qos=mqtt.QoS.AT_MOST_ONCE ,
callback=on_message_received
)
#publish_message("Hi")
print("Subscribed and listening for messages...")
subscribe_future.result()
print("Subscribed and listening for messages...")
try:
# Keep the script running to listen for messages
while True:
print("looping")
subscribe_future.result()
time.sleep(1)
except KeyboardInterrupt:
print("Disconnecting...")
disconnect_future = mqtt_connection.disconnect()
disconnect_future.result()
print("Disconnected!")
The cert attached to the Thing is:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect",
"iot:Publish",
"iot:Subscribe",
"iot:*",
"iot:Receive"
],
"Resource": [
"arn:aws:iot:eu-north-1:123:client/pc-v3",
"arn:aws:iot:eu-north-1:123:client/${iot:Connection.Thing.ThingName}",
"arn:aws:iot:eu-north-1:123:topic/mqtt_test",
"arn:aws:iot:eu-north-1:123:topicfilter/${iot:Connection.Thing.ThingName}/",
"arn:aws:iot:eu-north-1:123:topic/${iot:Connection.Thing.ThingName}/"
]
}
]
}
libs: awscrt 0.28.1 awsiot 0.1.3 awsiotsdk 1.26.0 boto3 1.40.70
I'm stuck and would appreciate any help or ideas where to try and debug my code.