circuitpython: adafruit_minimqtt produces non-descript error inside _wait_for_msg on Pico W
CircuitPython version
Adafruit CircuitPython 0.8.0-beta1; Raspberry Pi Pico W
Code/REPL
"""
Based on https://gist.github.com/sammachin/b67cc4f395265bccd9b2da5972663e6d
http://www.steves-internet-guide.com/into-mqtt-python-client/
"""
import json
from secrets import secrets
import board
import digitalio
import busio
import socketpool
import wifi
import microcontroller
from binascii import hexlify
from adafruit_minimqtt.adafruit_minimqtt import MQTT
SSID, PASSWORD = secrets["ssid"], secrets["password"]
BROKER = "test.mosquitto.org"
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
pool = socketpool.SocketPool(wifi.radio)
wifi.radio.connect(SSID, PASSWORD)
uid = microcontroller.Processor.uid
my_id = hexlify(b"{uid}").decode()
prefix = f"sdl-demo/picow/{my_id}/"
print(f"prefix: {prefix}")
onboard_led = digitalio.DigitalInOut(board.LED)  # only works for Pico W
onboard_led.direction = digitalio.Direction.OUTPUT
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe(prefix + "GPIO/#", qos=0)
def callback(topic, msg):
    t = topic.decode("utf-8").lstrip(prefix)
    print(t)
    if t[:5] == "GPIO/":
        p = int(t[5:])
        print(msg)
        data = json.loads(msg)
        onboard_led.value = data["value"]
        payload = {"onboard_led_value": onboard_led.value}
        print(payload)
        client.publish(prefix + "onboard_led/", payload, qos=0)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))
# Set up a MiniMQTT Client
client = MQTT(
    client_id=prefix,
    broker=BROKER,
    username=None,
    password=None,
    is_ssl=False,
    socket_pool=pool,
)
client.connect()
client.add_topic_callback(prefix + "GPIO/#", callback)
client.on_connect = on_connect
client.on_message = on_message
client.subscribe(prefix + "GPIO/#")
while True:
    client.check_msg()
Behavior
prefix: sdl-demo/picow/<PICO ID>/
Traceback (most recent call last):
  File "<stdin>", line 87, in <module>
  File "adafruit_minimqtt/adafruit_minimqtt.py", line 741, in subscribe
  File "adafruit_minimqtt/adafruit_minimqtt.py", line 876, in _wait_for_msg
MMQTTException:
For reference:
File "<stdin>", line 87, in <module> is:
client.connect()
EDIT:
client.subscribe(prefix + "GPIO/#")
Description
- adafruit_minimqtt fails for Pico W
Additional information
I’ve been porting my MicroPython implementation at https://github.com/sparks-baird/self-driving-lab-demo/blob/main/src/public_mqtt_sdl_demo/main.py to CircuitPython. Part of the appeal of using CircuitPython is to use ArduCam, which only has C and CircuitPython support – no MicroPython support as far as I can tell https://github.com/ArduCAM/PICO_SPI_CAM/issues/8 https://github.com/namato/micropython-ov2640/issues/6. I’d be OK with another basic color camera, but had trouble finding one that looked like it would work as easily as ArduCam.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 23 (5 by maintainers)
It seems to me like
errnoshould be returned here instead ofretwhen something goes wrong: https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/common-hal/socketpool/Socket.c#L1057-L1082That way we would get
MP_EAGAINandMP_ETIMEDOUTinstead of -1.A workaround for now seems to be to add
-1to the ignored errors in_wait_for_msg()inadafruit_mqtt.pyas such:@georgboe Looks like it works now, thanks! Using 8.0.0-beta.3-15-g0bc986ea7 I reverted back to the unmodified version of adafruit_minimqtt.mpy and it still works without having to modify the timeouts. I’ll let it run for a couple of days to test the stability.
I’m getting the same problem on an QT PY ESP32-S2, after upgrading from CircuitPython 7.3.3 to 8.0.0-beta.3. My program subscribes to a topic on Adafruit IO. It’s been very reliable in CircuitPython 7 but is unusable in 8. I tried hard coding a 1 second timeout in the _wait_for_msg() method, and it fixed the MMQTTException during subscribing. However, the loop() method then fails with:
I tried hard coding longer timeouts and zero timeout in the loop() method but I can’t get it to work.
Well, the paradigm is a little different, and the implementation is early. There is no equivalent to MicroPython’s
wlan.status. At the moment, you would trywifi.radio.connect(SSID, PASSWORD)blindly, there is no harm trying to connect if already connected, it becomes a NOP internally.In the CircuitPython
espressifport, the presence of an IP address signifies connection to the AP, but I believe the uP/CYW43 driver has issues with that https://github.com/micropython/micropython/issues/9455#issuecomment-1264414826addendum: (I’m really not sure how pedantically CircuitPython
raspberrypiAPI is going to try to mirror theespressifAPI. It should be close, but there may be limitations due to the driver.)