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
errno
should be returned here instead ofret
when something goes wrong: https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/common-hal/socketpool/Socket.c#L1057-L1082That way we would get
MP_EAGAIN
andMP_ETIMEDOUT
instead of -1.A workaround for now seems to be to add
-1
to the ignored errors in_wait_for_msg()
inadafruit_mqtt.py
as 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
espressif
port, 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
raspberrypi
API is going to try to mirror theespressif
API. It should be close, but there may be limitations due to the driver.)