Skip to content

Session 4: Connection Resilience and Reconnection Strategies

Synopsis

Focuses on detecting dropouts, retry backoff, state recovery, and designing network-aware applications that remain useful when connectivity is unreliable.

Session Content

Session 4: Connection Resilience and Reconnection Strategies

Duration: ~45 minutes
Focus: Building reliable IoT applications on Raspberry Pi Pico 2 W using MicroPython with robust Wi-Fi connection handling, retry logic, and automatic reconnection strategies.


1) Session Goals

By the end of this session, learners will be able to:

  • Detect Wi-Fi connection failures in MicroPython
  • Implement retry loops with backoff
  • Reconnect automatically after a dropped Wi-Fi connection
  • Structure code to keep trying without freezing the main application
  • Apply resilience patterns to simple Pico 2 W IoT projects

2) Prerequisites

  • Raspberry Pi Pico 2 W
  • USB cable
  • Thonny IDE installed
  • MicroPython firmware flashed to the Pico 2 W
  • Basic understanding of:
  • Python syntax
  • machine
  • network
  • time

3) Development Environment Setup

Thonny Setup

  1. Open Thonny
  2. Go to Run > Select interpreter
  3. Choose:
  4. MicroPython (Raspberry Pi Pico)
  5. Select the correct serial port for the Pico 2 W
  6. Confirm the REPL is visible in the shell pane
  • Save reusable code as main.py on the Pico
  • Use boot.py for startup Wi-Fi setup if needed
  • Test small pieces in the REPL before saving full programs

4) Theory: Why Connection Resilience Matters

Wireless connections are not always stable. A Pico 2 W may experience:

  • Weak Wi-Fi signal
  • Router restarts
  • Temporary network congestion
  • DHCP delays
  • Access point changes
  • Power interruptions

If your program assumes Wi-Fi will always work, it may:

  • Stop sending sensor data
  • Freeze in a blocking loop
  • Lose MQTT or web service connectivity
  • Fail silently

Resilience Techniques

Common strategies include:

  • Retry with limit: try several times before giving up
  • Backoff delay: wait a little longer after each failed attempt
  • Recheck connection state: verify connection before network activity
  • Auto-reconnect loop: reconnect when the link drops
  • Non-blocking structure: keep the rest of the program running

5) Key Concepts

5.1 Basic Wi-Fi Connection Flow

Typical connection logic:

  1. Activate the wireless interface
  2. Start connection attempt
  3. Wait for connection to complete
  4. Confirm IP address assignment
  5. Proceed with network tasks

5.2 Connection Status Checks

Useful checks:

  • wlan.isconnected()
  • wlan.status()
  • wlan.ifconfig()

5.3 Retry with Backoff

A simple resilience pattern:

  • Attempt 1: wait 1 second
  • Attempt 2: wait 2 seconds
  • Attempt 3: wait 4 seconds

This reduces network hammering and gives the router time to recover.


6) Hands-On Exercise 1: Reliable Wi-Fi Connection Function

Objective

Create a reusable function that connects to Wi-Fi with retries and backoff.

Hardware

  • Raspberry Pi Pico 2 W
  • No additional hardware required

Code: main.py

import network
import time

# Replace with your Wi-Fi credentials
SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"


def connect_wifi(ssid, password, max_attempts=5):
    """
    Connect to Wi-Fi with retry and backoff.

    Returns:
        network.WLAN object if connected, otherwise None
    """
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)

    # If already connected, return immediately
    if wlan.isconnected():
        print("Already connected")
        print("Network config:", wlan.ifconfig())
        return wlan

    attempt = 0
    delay = 1

    while attempt < max_attempts:
        attempt += 1
        print("Connecting to Wi-Fi... attempt", attempt)

        try:
            wlan.connect(ssid, password)
        except Exception as e:
            print("Connection call failed:", e)

        timeout = 10
        start = time.ticks_ms()

        while not wlan.isconnected():
            if time.ticks_diff(time.ticks_ms(), start) > timeout * 1000:
                print("Timeout waiting for connection")
                break
            time.sleep(0.2)

        if wlan.isconnected():
            print("Connected successfully")
            print("Network config:", wlan.ifconfig())
            return wlan

        print("Retrying in", delay, "seconds...")
        time.sleep(delay)
        delay = min(delay * 2, 16)

    print("Failed to connect after", max_attempts, "attempts")
    return None


wlan = connect_wifi(SSID, PASSWORD)

if wlan:
    print("Wi-Fi ready for use")
else:
    print("Wi-Fi unavailable")

Example Output

Connecting to Wi-Fi... attempt 1
Timeout waiting for connection
Retrying in 1 seconds...
Connecting to Wi-Fi... attempt 2
Connected successfully
Network config: ('192.168.1.45', '255.255.255.0', '192.168.1.1', '8.8.8.8')
Wi-Fi ready for use

Exercise Tasks

  • Replace the SSID and password with your network values
  • Change max_attempts to 3 and test behavior
  • Observe how the delay increases after each failure
  • Disconnect the router or use the wrong password to see failure handling

7) Theory: Designing for Reconnection

A single successful connection is not enough for IoT systems. Your application should keep checking whether the connection is still valid.

Common Reconnection Pattern

  • Before every network request, check isconnected()
  • If disconnected, call a reconnection function
  • Retry the main task only after connection is restored

Good Practice

Keep reconnection logic separate from application logic. This makes the code easier to maintain and reuse.


8) Hands-On Exercise 2: Auto-Reconnect Network Monitor

Objective

Create a program that continuously monitors Wi-Fi and reconnects automatically if the link drops.

Code: main.py

import network
import time

SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"


class WiFiManager:
    def __init__(self, ssid, password):
        self.ssid = ssid
        self.password = password
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)

    def connect(self, max_attempts=5):
        if self.wlan.isconnected():
            return True

        attempt = 0
        delay = 1

        while attempt < max_attempts:
            attempt += 1
            print("Wi-Fi connect attempt", attempt)

            try:
                self.wlan.connect(self.ssid, self.password)
            except Exception as e:
                print("Connect error:", e)

            timeout = 10
            start = time.ticks_ms()

            while not self.wlan.isconnected():
                if time.ticks_diff(time.ticks_ms(), start) > timeout * 1000:
                    break
                time.sleep(0.2)

            if self.wlan.isconnected():
                print("Wi-Fi connected")
                print("IP:", self.wlan.ifconfig()[0])
                return True

            print("Waiting", delay, "seconds before retry")
            time.sleep(delay)
            delay = min(delay * 2, 16)

        print("Wi-Fi connection failed")
        return False

    def ensure_connection(self):
        if not self.wlan.isconnected():
            print("Wi-Fi lost, reconnecting...")
            return self.connect()
        return True

    def status(self):
        return self.wlan.isconnected()


wifi = WiFiManager(SSID, PASSWORD)

if wifi.connect():
    print("Starting monitor loop")
    while True:
        if wifi.ensure_connection():
            print("Connection OK")
        else:
            print("Still disconnected")

        time.sleep(5)

Example Output

Wi-Fi connect attempt 1
Wi-Fi connected
IP: 192.168.1.45
Starting monitor loop
Connection OK
Connection OK
Wi-Fi lost, reconnecting...
Wi-Fi connect attempt 1
Wi-Fi connected
IP: 192.168.1.45
Connection OK

Exercise Tasks

  • Run the monitor loop
  • Turn off the router briefly and observe behavior
  • Reduce the loop interval to 2 seconds
  • Add a print statement for the current RSSI if supported by your MicroPython build

9) Theory: Avoiding Blocking Code

A common mistake is using long blocking waits that stop the rest of the program. If your app also reads sensors or drives LEDs, you want those tasks to continue even if Wi-Fi is unstable.

Better Approach

  • Keep connection attempts short
  • Check connection periodically
  • Let the main loop continue working

10) Hands-On Exercise 3: LED Status Indicator for Connection Health

Objective

Use the Pico 2 W onboard LED to display connection status: - On solid: connected - Blinking: trying to reconnect - Off: disconnected after repeated failure

Hardware

  • Raspberry Pi Pico 2 W

Code: main.py

import network
import time
from machine import Pin

SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"

led = Pin("LED", Pin.OUT)


class WiFiManager:
    def __init__(self, ssid, password):
        self.ssid = ssid
        self.password = password
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)

    def connect(self, max_attempts=3):
        attempt = 0
        delay = 1

        while attempt < max_attempts:
            attempt += 1
            print("Attempt", attempt)
            led.value(1)  # LED on while attempting

            try:
                self.wlan.connect(self.ssid, self.password)
            except Exception as e:
                print("Connect error:", e)

            timeout = 8
            start = time.ticks_ms()

            while not self.wlan.isconnected():
                if time.ticks_diff(time.ticks_ms(), start) > timeout * 1000:
                    break
                time.sleep(0.2)

            if self.wlan.isconnected():
                print("Connected:", self.wlan.ifconfig())
                led.value(1)
                return True

            print("Retry in", delay, "seconds")
            led.value(0)
            time.sleep(delay)
            delay = min(delay * 2, 8)

        led.value(0)
        return False

    def ensure_connection(self):
        return self.wlan.isconnected() or self.connect()


wifi = WiFiManager(SSID, PASSWORD)

while True:
    if wifi.ensure_connection():
        print("Wi-Fi connected")
        led.value(1)
    else:
        print("Wi-Fi unavailable")
        for _ in range(3):
            led.toggle()
            time.sleep(0.2)
        led.value(0)

    time.sleep(4)

Example Output

Attempt 1
Connected: ('192.168.1.45', '255.255.255.0', '192.168.1.1', '8.8.8.8')
Wi-Fi connected
Wi-Fi connected
Wi-Fi connected

Exercise Tasks

  • Watch the LED behavior during connection attempts
  • Simulate failure with the wrong password
  • Adjust blink timing to make the status more visible

11) Mini Project: Resilient Sensor Reporting Skeleton

Objective

Combine connection resilience with a periodic task, preparing for sensor-to-cloud projects.

Code: main.py

import network
import time

SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"


class WiFiManager:
    def __init__(self, ssid, password):
        self.ssid = ssid
        self.password = password
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)

    def connect(self):
        if self.wlan.isconnected():
            return True

        try:
            self.wlan.connect(self.ssid, self.password)
        except Exception as e:
            print("Connect error:", e)
            return False

        timeout = 10
        start = time.ticks_ms()

        while not self.wlan.isconnected():
            if time.ticks_diff(time.ticks_ms(), start) > timeout * 1000:
                return False
            time.sleep(0.2)

        return True

    def ensure_connection(self):
        if not self.wlan.isconnected():
            print("Reconnecting Wi-Fi...")
            return self.connect()
        return True


wifi = WiFiManager(SSID, PASSWORD)

while True:
    if wifi.ensure_connection():
        # Placeholder for reading a sensor and sending data
        print("Ready to send data")
        print("IP address:", wifi.wlan.ifconfig()[0])
    else:
        print("Network down, skipping data send")

    time.sleep(10)

Example Output

Ready to send data
IP address: 192.168.1.45
Ready to send data
IP address: 192.168.1.45
Reconnecting Wi-Fi...
Network down, skipping data send
Ready to send data
IP address: 192.168.1.45

12) Best Practices Checklist

  • Keep Wi-Fi connection code in a dedicated function or class
  • Always check isconnected() before network operations
  • Use bounded retries to avoid infinite hangs
  • Add a timeout for each connection attempt
  • Use backoff delays to reduce network pressure
  • Keep the main loop alive even if Wi-Fi fails
  • Provide status feedback using the LED or serial output
  • Avoid repeating connect() too rapidly

13) Common Mistakes

  • Hard-coding Wi-Fi credentials in shared code repositories
  • Blocking forever in a connection loop
  • Reconnecting on every iteration even when already connected
  • Ignoring None or failed return values
  • Using large delays that make the system unresponsive
  • Mixing application code and connection management in the same block

14) Knowledge Check

  1. Why is retry logic important in wireless IoT devices?
  2. What is the purpose of exponential backoff?
  3. How can wlan.isconnected() help prevent failures?
  4. Why should reconnection logic be separated from sensor-reading logic?
  5. What happens if your code blocks forever while waiting for Wi-Fi?

15) Wrap-Up

What You Learned

  • How to detect Wi-Fi failures
  • How to implement connection retries
  • How to automatically reconnect
  • How to structure resilient Pico 2 W code for IoT applications

Next Session Preview

In the next session, you will use these resilience techniques to build a small networked IoT application that reads data and sends it to an online service reliably.


Back to Chapter | Back to Master Plan | Previous Session