Raspberry Pi Pico W WiFi Resiliency

, updated 24 March 2024 🔖 iot ⏲️ 2 minutes to read

The Raspberry Pi Pico W is a great little device for running Python code - I am using four of them as IoT sensor devices in my home, which you can read about here:

  1. Raspberry Pi Pico Home Assistant Motion & Temperature Sensor
  2. Raspberry Pi Pico Carbon Dioxide Sensor

However, there is one problem with the Pico W: the W. Between the wireless chip, its drivers, or Micropython there are problems. Just google "raspberry pi pico wifi issue" to see the spectrum of issues. So while my original post has a simple bit of code to manage the connection, this wasn’t enough to prevent the sensors from losing connectivity for hours at a time.

I found that this hanging was not solved by a machine.reset() either (see watchdog.py). Powering the boards off and then on again fixed it - which means my issue at least was very likely caused by some bad state somewhere (maybe, the WiFi SOC?).

I didn't have the time to debug the various levels of abstraction, so I set about trying to make my own code more robust. Let's analyse my first attempt to see where the pitfalls are:

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.config(pm = 0xa11140, hostname = "sensorpico")

while True:
  if not wlan.isconnected():
    # wlan.connect doesn't clear out the WiFi state
    # Subsequent reconnects may not work
    wlan.connect("my SSID", "my password")
    # This loop may never exit, because the
    # WiFi chip has no connection timeout!
    while not wlan.isconnected():
      utime.sleep(1)

Let's try to improve this a bit:

wlan = network.WLAN(network.STA_IF)
- wlan.active(True)
wlan.config(pm = 0xa11140, hostname = "sensorpico")

while True:
  if not wlan.isconnected():
+   wlan.active(False)
+   wlan.active(True)
    wlan.connect("my SSID", "my password")
+   started_connect_time = utime.ticks_ms()
    while not wlan.isconnected():
+     if utime.ticks_diff(utime.ticks_ms(), started_connect_time) > 20_000:
+       break
      utime.sleep(1)

The tweaks solved the hanging problem since we now give the WiFi chip 20 seconds to finish connecting, and if it doesn't, we abort and try the whole thing again. But this doesn't clear out the WiFi state, and means that sometimes, the code can keep spinning around but never actually connecting.

It turns out that wlan.active(False) isn't doing enough for us here. Maybe it's telling the chip to power down, but it's not resetting any state on the chip, and that's what we need to do. Sure enough, there is a method which can help:

wlan = network.WLAN(network.STA_IF)
wlan.config(pm = 0xa11140, hostname = "sensorpico")

while True:
  if not wlan.isconnected():
+   wlan.deinit()
    wlan.active(True)
    wlan.connect("my SSID", "my password")
    started_connect_time = utime.ticks_ms()
    while not wlan.isconnected():
      if utime.ticks_diff(utime.ticks_ms(), started_connect_time) > 20_000:
        break # (or, raise exception)
      utime.sleep(1)

The wlan.deinit() method appears to completely wipe the WiFi chip state. At least, I think it does, because at the time of writing the documentation doesn't actually list this method. I found the method by inspecting the wlan object's methods and testing it. But, it seems to do exactly as I want.

So there you have it - resilient WiFi connection code. I decided to wrap this up in a class too (wifi.py), so that my application code only needs to make the following calls in its initialization/main loop:

wlan = wifi.WiFi("sensorpico", "my SSID", "my password")

while True:
  try:
    wlan.ensure_connected()
    # Do other stuff
  except Exception as e:
    # Do something with exception
  utime.sleep(0.1)

This was all very difficult to arrive at and took a lot of time (in fact, most of the time on this sensor project has been the WiFi debugging/tweaking/testing), but I'm happy to have cracked this particular nut - at least for now!

🏷️ wifi pico code raspberry pi sensor chip connect state issue enough about let resiliency device

⬅️ Previous post: Raspberry Pi Pico Carbon Dioxide Sensor

➡️ Next post: Optimising Rocket Chat Content Delivery with CloudFront

🎲 Random post: Using Material Layers in UE5

Comments

Please click here to load comments.