Pico W Async LED Control (MicroPython) is a runnable microcontroller simulation example on SensBench — open the wired circuit, inspect the code, and compile real firmware in your browser, no install needed. Last updated Aug 14, 2026.

FREE SIMULATOR EXAMPLE · INTERMEDIATE

Pico W Async LED Control (MicroPython)

This example controls the Pico W’s onboard LED through an asyncio HTTP server in MicroPython — the async pattern that lets one core serve many clients. The CYW43 LED path plus concurrent networking.

Board Raspberry Pi Pico W (RP2040 + WiFi)
Difficulty intermediate
Category communication
Libraries None — just the Arduino core
Runs in Sensbench browser simulator — free, no account
Raspberry Pi Pico W controlling its LED through an async MicroPython server in the Sensbench simulator

The exact circuit you get when you open this example — already wired, ready to run.

The sketch

# main.py
import uasyncio as asyncio
import network
from machine import Pin

SSID = "kritish"
PASSWORD = "pass"

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

# ---------- Async WiFi Connect ----------
async def wifi_connect():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(SSID, PASSWORD)

    print("Connecting WiFi...")
    while not wlan.isconnected():
        await asyncio.sleep(0.5)

    print("IP:", wlan.ifconfig()[0])


# ---------- HTML ----------
HTML_PAGE = """<!DOCTYPE html>
<html>
<head>
<title>Pico Async LED</title>
</head>
<body>
<h2>Pico W Async LED Control</h2>
<p>Status: <span id="status">--</span></p>

<button onclick="ledOn()">ON</button>
<button onclick="ledOff()">OFF</button>

<script>
function ledOn(){
 fetch("/on").then(r=>r.text()).then(t=>{
   document.getElementById("status").innerText=t;
 });
}
function ledOff(){
 fetch("/off").then(r=>r.text()).then(t=>{
   document.getElementById("status").innerText=t;
 });
}
</script>
</body>
</html>
"""


# ---------- Client Handler ----------
async def handle_client(reader, writer):
    request_line = await reader.readline()
    request = request_line.decode()

    # skip headers
    while await reader.readline() != b"\r\n":
        pass

    print("REQ:", request)

    if "GET /on" in request:
        led.on()
        body = "ON"
        content_type = "text/plain"

    elif "GET /off" in request:
        led.off()
        body = "OFF"
        content_type = "text/plain"

    else:
        body = HTML_PAGE
        content_type = "text/html"

    response = (
        "HTTP/1.1 200 OK\r\n"
        f"Content-Type: {content_type}\r\n"
        "Connection: close\r\n\r\n"
        + body
    )

    writer.write(response.encode())
    await writer.drain()
    await writer.wait_closed()


# ---------- Main ----------
async def main():
    await wifi_connect()

    server = await asyncio.start_server(handle_client, "0.0.0.0", 80)
    print("Server running on port 80")

    while True:
        await asyncio.sleep(1)


asyncio.run(main())

How it works

The firmware runs an asyncio HTTP server that toggles the Pico W’s onboard LED through the CYW43 driver. The server coroutine accepts connections and spawns a handler per client, so multiple browsers can toggle the LED concurrently without one blocking the others.

The onboard LED path is the Pico W’s signature detail: Pin('LED') routes through the WiFi chip, not a plain GPIO. The async pattern is the transferable lesson — the same structure drives sensors, relays or any other peripheral.

Before you build it for real

The async scheduler is cooperative, not preemptive — one blocking call (a long sleep, a busy loop) freezes every other task; async code only works if every task yields. The onboard LED goes through the CYW43 chip, so plain-GPIO LED code does not apply. And the single core is the hard limit: concurrency here is interleaving, not parallelism — the scheduler gives the illusion of multitasking, which is enough for IO-bound servers and nothing more.

Related examples

FAQ

Why async for a single LED?

Because the LED is not the point — the concurrency is. An async server interleaves multiple clients on one core, so a slow browser never blocks a fast one. The single LED is the simplest observable that demonstrates the scheduling.

How does asyncio work in MicroPython?

MicroPython’s uasyncio provides the same coroutine model as desktop Python: tasks yield at await points, and the scheduler switches between them. The Pico’s single core runs everything, so the scheduling is cooperative — a blocking task stalls everyone.