adafruit / adafruit/Adafruit_CircuitPython_MiniMQTT

MQTT loop() blocks script. Works fine with adafruit_io

Open
#138 3 comments 1 reaction 1 assignee Claimed by @brentru View on GitHub
bug
Dominant language
Python
Stars
81
Forks
52
PR merge metrics
No merged PRs in 30d

Description

This happens with **CircuitPython 7.3.3** and **8 beta-6** using the **mpy-20221230** libraries for both 7 and 8 releases.

The `loop()` works flawlessly when run used with the AIO client. However, it stalls with plain MQTT.

A **simple workaround** is to add a timeout (in seconds) to the loop: `mqtt_client.loop(timeout = 1)`

I expect that while `loop()` is checking for updates the code below would send messages to the topic. What happens instead, is that the `loop()` blocks the script until it receives a message and then it allows the rest of the code to run.

To reproduce:

1. run this on a MatrixPortal M4
2. notice that the script sends no messages
3. from another client send a message to `test/test-topic`
4. notice that the sent message is processed and the rest of the `while True` loop runs.

To run the same loop with adafruit_io change the `use_MQTT = True` variable to `False`.

```python
''' Bug Reproduction Demo - MatrixPortal M4 '''

import time
import board
import busio
from microcontroller import cpu
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_io.adafruit_io import IO_MQTT

start = time.monotonic()

# -----------------------------------------------------------------------------------------
# WIFI Connection
# -----------------------------------------------------------------------------------------

try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise

esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets)

print("Connecting to WiFi...")
wifi.connect()
print("Connected!")

# -----------------------------------------------------------------------------------------
# MQTT Connection
# -----------------------------------------------------------------------------------------

use_MQTT = True # set to False to use Adafruit IO

if use_MQTT:
mqtt_topic = "test/test-topic"
the_broker = "Mosquitto"

# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)

# Initialize a new MQTT Client object
io = MQTT.MQTT(
broker=secrets["mqtt_broker"],
port=1883,
username=secrets["mqtt_user"],
password=secrets["mqtt_pass"],
socket_pool=socket,
is_ssl = False
)

if not use_MQTT:
mqtt_topic = "test-topic"
the_broker = "Adafruit IO"

# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)

# Initialize a new MQTT Client object
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
username=secrets["aio_username"],
password=secrets["aio_key"],
)

# Initialize an Adafruit IO MQTT Client
io = IO_MQTT(mqtt_client)

def new_message(client, topic, message):
# Method called whenever user/feeds/led has a new value
print(f'New message on {topic}: {message}')

# Connect the callback methods defined above to Adafruit IO
io.on_message = new_message

# Connect to Adafruit IO
print(f"Connecting to {the_broker}...")
io.connect()
print(f'Time to connect: {(time.monotonic() - start):0.1f} seconds')

# -----------------------------------------------------------------------------------------
# MQTT Activity
# -----------------------------------------------------------------------------------------

print(f'\nSubscribing: {mqtt_topic}')
io.subscribe(mqtt_topic)

prv_refresh_time = 0.0
end_all = time.monotonic() + 30 # seconds
print('Listening for messages...')
while True:
# Poll for incoming messages
try:
io.loop()
# io.loop(timeout=1) # this timeout allows the loop to continue
except (ValueError, RuntimeError) as e:
print("Failed to get data, retrying\n", e)
wifi.reset()
wifi.connect()
io.reconnect()
continue
if (time.monotonic() - prv_refresh_time) > 5:
cpu_temp = cpu.temperature
cpu_temp = f'{cpu_temp:>0.2f}'
print(f'Sending: {cpu_temp}')
io.publish(mqtt_topic, cpu_temp)
prv_refresh_time = time.monotonic()

if time.monotonic() >= end_all:
break

print(f'Unsubscribing: {mqtt_topic}')
io.unsubscribe(mqtt_topic)
print(f'Disconnecting from {the_broker}')
io.disconnect()
print(f'\nTotal Time: {(time.monotonic() - start):0.1f} seconds \nGood bye!')
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.