-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adafruit_minimqtt produces non-descript error inside _wait_for_msg on Pico W #6988
Comments
Same issue with a slightly modified version of https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/blob/main/examples/minimqtt_simpletest.py: # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import socketpool
import wifi
import adafruit_minimqtt.adafruit_minimqtt as MQTT
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
### Topic Setup ###
# MQTT Topic
# Use this topic if you'd like to connect to a standard MQTT broker
mqtt_topic = "test/topic"
### Code ###
# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connect(mqtt_client, userdata, flags, rc):
# This function will be called when the mqtt_client is connected
# successfully to the broker.
print("Connected to MQTT Broker!")
print("Flags: {0}\n RC: {1}".format(flags, rc))
def disconnect(mqtt_client, userdata, rc):
# This method is called when the mqtt_client disconnects
# from the broker.
print("Disconnected from MQTT Broker!")
def subscribe(mqtt_client, userdata, topic, granted_qos):
# This method is called when the mqtt_client subscribes to a new feed.
print("Subscribed to {0} with QOS level {1}".format(topic, granted_qos))
def unsubscribe(mqtt_client, userdata, topic, pid):
# This method is called when the mqtt_client unsubscribes from a feed.
print("Unsubscribed from {0} with PID {1}".format(topic, pid))
def publish(mqtt_client, userdata, topic, pid):
# This method is called when the mqtt_client publishes data to a feed.
print("Published to {0} with PID {1}".format(topic, pid))
def message(client, topic, message):
# Method called when a client's subscribed feed has a new value.
print("New message on topic {0}: {1}".format(topic, message))
# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)
# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
broker="test.mosquitto.org",
username=None,
password=None,
socket_pool=pool,
is_ssl=False,
)
# Connect callback handlers to mqtt_client
mqtt_client.on_connect = connect
mqtt_client.on_disconnect = disconnect
mqtt_client.on_subscribe = subscribe
mqtt_client.on_unsubscribe = unsubscribe
mqtt_client.on_publish = publish
mqtt_client.on_message = message
print("Attempting to connect to %s" % mqtt_client.broker)
mqtt_client.connect()
print("Subscribing to %s" % mqtt_topic)
mqtt_client.subscribe(mqtt_topic)
print("Publishing to %s" % mqtt_topic)
mqtt_client.publish(mqtt_topic, "Hello Broker!")
print("Unsubscribing from %s" % mqtt_topic)
mqtt_client.unsubscribe(mqtt_topic)
print("Disconnecting from %s" % mqtt_client.broker)
mqtt_client.disconnect() Connecting to <SSID>
Connected to <SSID>!
Attempting to connect to test.mosquitto.org
Connected to MQTT Broker!
Flags: 0
RC: 0
Subscribing to test/topic
Traceback (most recent call last):
File "<stdin>", line 88, 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: |
I don't know why the exception is blank, but it's possible it's an |
@anecdata thanks for the quick response! Would that be something similar to a MicroPython implementation: wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
# Wait for connect or fail
max_wait = 30
while max_wait > 0: # type: ignore
if wlan.status() < 0 or wlan.status() >= 3: # type: ignore
break
max_wait -= 1
print("waiting for connection...")
sleep(1)
# Handle connection error
if wlan.status() != 3: # type: ignore
raise RuntimeError("network connection failed")
else:
print("connected")
status = wlan.ifconfig()
ip = status[0] # type: ignore
print(f"ip: {ip}") except wrapped in a function and using: wifi.radio.connect(SSID, PASSWORD) # is it this line or is it `pool = socketpool.SocketPool(wifi.radio)`? inside of an |
Well, the paradigm is a little different, and the implementation is early. There is no equivalent to MicroPython's In the CircuitPython addendum: (I'm really not sure how pedantically CircuitPython |
Oof, I made a mistake 🤦♂️. It's erroring out during |
Would this be helpful in writing network libraries or user code? If it's possible, maybe we should consider adding it. |
@dhalbert It would be helpful for testing for now at least. Also some equivalent of uP |
I redefined def _wait_for_msg(self, timeout=0.1):
"""Reads and processes network events."""
# CPython socket module contains a timeout attribute
if hasattr(self._socket_pool, "timeout"):
print("self._socket_pool.timeout exists")
try:
res = self._sock_exact_recv(1)
except self._socket_pool.timeout:
return None
else: # socketpool, esp32spi
print("self._socket_pool.timeout does not exist")
try:
res = self._sock_exact_recv(1)
except OSError as error:
if error.errno in (errno.ETIMEDOUT, errno.EAGAIN):
# raised by a socket timeout if 0 bytes were present
return None
print(error)
raise MMQTTException from error and ran Connecting to <SSID>
Connected to <SSID>!
Attempting to connect to test.mosquitto.org
self._socket_pool.timeout does not exist
Connected to MQTT Broker!
Flags: 0
RC: 0
Subscribing to test/topic
self._socket_pool.timeout does not exist
-1 In other words, the error is |
Turns out it was an issue with the timeout during Connecting to <SSID>
Connected to <SSID>!
Attempting to connect to test.mosquitto.org
Connected to MQTT Broker!
Flags: 0
RC: 0
Subscribing to test/topic
Subscribed to test/topic with QOS level 0
Publishing to test/topic
Published to test/topic with PID 1
Unsubscribing from test/topic
New message on topic test/topic: moshi moshi
New message on topic test/topic: Hello Broker!
Unsubscribed from test/topic with PID 2
Disconnecting from test.mosquitto.org
Disconnected from MQTT Broker! Also, loving the "moshi moshi" |
Looking less like the wifi connection is dropping. Since Pico W is alpha, do you have an ESP32-S2 to try this code on for comparison? |
@anecdata, unfortunately I don't own an ESP32-S2 |
|
At first glance, Maybe the call to Changing However, when I move away from the simple example and towards a script that listens in an ongoing sense for new messages, I'm getting that same error despite larger timeout values. while True:
client.loop()
heartbeat(False)
sign_of_life(False) If I use a try:except: while True:
try:
client.loop()
except Exception as e:
pass
heartbeat(False)
sign_of_life(False) Then it loops without error-ing, but when the the companion host code is publishing messages (which works well in tandem with my MicroPython implementation), it's not being received by the CircuitPython implementation. Also, I tried digging a bit more and found: error.errno: -1
errno.ETIMEDOUT: 116
errno.EAGAIN: 11 |
That last part is in the context of these lines: if error.errno in (errno.ETIMEDOUT, errno.EAGAIN):
# raised by a socket timeout if 0 bytes were present
return None
raise MMQTTException from error |
I'm hitting my limit here for now. I'm having trouble tracking down why it's giving I've gotten as far as: if not self._backwards_compatible_sock:
# CPython/Socketpool Impl.
rc = bytearray(bufsize)
self._sock.recv_into(rc, bufsize) # OSError originating from here (probably) |
yeah, this seems related to #101 I don't typically get OSError at the same point you are seeing it (during subscribe) I'm also running a watchdog timer to reset the system if it hangs. Which happens too often for my liking. I've been using ESP32S2, and getting best results using timeout=0 I realise Circuitpython isn't targeting 100% uptime applications... but I've had so many stability problems that I'm reluctantly going to give this product a go for handling the networking. |
I've been seeing it consistently on the Pico-W when I'm using MQTT with a
Maybe I'll give EDIT: EDIT: I tried with your PR, which allowed the first while True:
sleep(2.0)
client.loop(timeout=0.0)
heartbeat(False)
sign_of_life(False)
On a side note, thank you for mentioning this! I had been looking around for something like it but was having trouble finding something reasonably priced. A project/tutorial I'm developing would ideally be implemented in classrooms by instructors or as 100% uptime machines in university settings, but the Pico W doesn't support Enterprise-WPA authentication which is typical of many universities (e.g. Eduroam). Agreed about getting CP (and MP) to the point where it can handle the otherwise (usually) unavoidable stability issues. |
Sleep should be fine. Although I actually use the pattern
(so it doesn't block other code from running) |
It seems to me like That way we would get A workaround for now seems to be to add try:
res = self._sock_exact_recv(1)
except OSError as error:
if error.errno in (errno.ETIMEDOUT, errno.EAGAIN, -1):
# raised by a socket timeout if 0 bytes were present
return None
raise MMQTTException from error |
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.
I tried hard coding longer timeouts and zero timeout in the loop() method but I can't get it to work. |
@rdagger Can you please try again with latest nightly build? |
@georgboe Looks like it works now, thanks! |
CircuitPython version
Code/REPL
Behavior
For reference:
File "<stdin>", line 87, in <module>
is:client.connect()
EDIT:
https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/blob/f2cb3bbe830f05cb75cd397fe83803ee1e59946b/adafruit_minimqtt/adafruit_minimqtt.py#L741
https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/blob/f2cb3bbe830f05cb75cd397fe83803ee1e59946b/adafruit_minimqtt/adafruit_minimqtt.py#L861-L876
Description
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 ArduCAM/PICO_SPI_CAM#8 namato/micropython-ov2640#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.
adafruit_minimqtt documentation
The text was updated successfully, but these errors were encountered: