Raspberry Pi Pico W WiFi: crea un servidor web con MicroPython
Raspberry Pi Pico W WiFi: el UF2 correcto, network.WLAN y códigos de estado, servidor web para un LED, datos de sensores en vivo, API con urequests y hora NTP.
Usar el WiFi de la Raspberry Pi Pico W es una de las formas más baratas y sencillas de crear un pequeño dispositivo que controlas desde el móvil. La Pico W es la versión de la conocida Raspberry Pi Pico que añade WiFi de 2,4 GHz y Bluetooth: con unas pocas líneas de MicroPython se conecta a la red de casa, sirve su propia página web y descarga el tiempo y la hora de internet. En esta guía conectarás una Pico W al WiFi desde cero, montarás un servidor web que enciende un LED desde el móvil y después harás una página que muestra datos de un sensor en tiempo real.
Al terminar sabrás elegir el archivo UF2 correcto, conectarte con network.WLAN e interpretar sus códigos de estado, obtener datos de una API con urequests, poner la hora con NTP y hacer lo mismo desde el Arduino IDE. Si la Pico es nueva para ti, te ayudará leer primero ¿Qué es la Raspberry Pi Pico?, y los comandos básicos están en la guía ¿Qué es MicroPython?.

¿Qué es la Raspberry Pi Pico W y en qué se diferencia de la Pico?
La Pico W usa el mismo procesador RP2040, el mismo tamaño y la misma distribución de 40 pines que la Pico. La diferencia es el chip inalámbrico Infineon CYW43439 añadido a la placa: ofrece WiFi 802.11n a 2,4 GHz y Bluetooth 5.2. El procesador se comunica con este chip mediante un bus SPI interno; tú solo usas el módulo network de MicroPython. Más tarde Raspberry Pi lanzó la Pico 2 W con el procesador RP2350; como el chip inalámbrico es el mismo, todo el código de este artículo funciona también en ella.
| Característica | Pico W | Pico 2 W | ESP32 (WROOM-32) |
|---|---|---|---|
| Procesador | RP2040, doble núcleo Cortex-M0+, 133 MHz | RP2350, doble núcleo Cortex-M33 (o RISC-V), 150 MHz | Xtensa LX6, doble núcleo, 240 MHz |
| RAM | 264 KB | 520 KB | 520 KB |
| Memoria flash | 2 MB | 4 MB | Normalmente 4 MB |
| WiFi | 2,4 GHz, 802.11n (CYW43439) | 2,4 GHz, 802.11n (CYW43439) | 2,4 GHz, 802.11 b/g/n (integrado) |
| Bluetooth | 5.2 (Classic y BLE) | 5.2 (Classic y BLE) | 4.2 (Classic y BLE) |
| Entradas analógicas | 3 canales, 12 bits | 3 canales, 12 bits | 18 canales, 12 bits |
| Archivo de MicroPython | RPI_PICO_W (.uf2) | RPI_PICO2_W (.uf2) | ESP32_GENERIC (.bin) |
Sobre el papel, el ESP32 es más rápido y tiene más ejemplos en el mundo Arduino. Los puntos fuertes de la Pico W son un soporte de MicroPython oficial y maduro, una documentación ordenada y unos pines sin trampas del tipo "debe estar a este nivel al arrancar". Si te gusta aprender con Python, la Pico W es una gran elección; si para ti priman el código Arduino y las librerías listas para usar, el ESP32 puede resultarte más cómodo. Si dudas entre las dos, la comparativa ¿Arduino o ESP32? te orientará.
El chip inalámbrico de la Pico W y las diferencias en los pines
Los pines accesibles de la Pico W son exactamente los mismos que en la Pico: GP0–GP22 y GP26–GP28 se pueden usar libremente, y las entradas analógicas siguen en GP26, GP27 y GP28. Lo que cambia son los cuatro pines que quedan dentro de la placa. En la Pico gestionan el LED integrado, el modo de la fuente y la detección de USB; en la Pico W están reservados para hablar con el chip inalámbrico, y el LED va conectado directamente a ese chip. Puedes ver el mapa completo de pines en la herramienta Pinout.
| Pin interno | Función en la Pico | Función en la Pico W |
|---|---|---|
| GP23 | Modo de la fuente de alimentación (SMPS) | Encendido del chip inalámbrico (WL_ON) |
| GP24 | Detección de tensión USB (VBUS) | Línea de datos e interrupción inalámbrica (WL_D) |
| GP25 | LED integrado | Selección del chip inalámbrico (WL_CS) |
| GP29 | Medida de la tensión VSYS (ADC3) | Reloj inalámbrico (WL_CLK) y medida de VSYS |
| LED integrado | GP25: Pin(25) | WL_GPIO0 del chip inalámbrico: Pin("LED") |
Paso 1: Cargar el archivo UF2 correcto para la Pico W
El error más habitual es cargar en la Pico W el archivo de MicroPython de la Pico normal. La placa funciona y ves el prompt en el Shell de Thonny, pero en cuanto escribes import network aparece "ImportError: no module named 'network'", porque la versión para la Pico normal no incluye el driver inalámbrico. Cada placa tiene su propio archivo UF2:
| Placa | Archivo UF2 de MicroPython | Unidad que aparece con BOOTSEL |
|---|---|---|
| Raspberry Pi Pico | RPI_PICO-….uf2 | RPI-RP2 |
| Raspberry Pi Pico W / WH | RPI_PICO_W-….uf2 | RPI-RP2 |
| Raspberry Pi Pico 2 | RPI_PICO2-….uf2 | RP2350 |
| Raspberry Pi Pico 2 W | RPI_PICO2_W-….uf2 | RP2350 |
- En la página de descargas de micropython.org busca la placa RPI_PICO_W (RPI_PICO2_W para la Pico 2 W) y descarga el último archivo .uf2 estable, el que no pone "preview".
- Mantén pulsado el botón BOOTSEL de la Pico W mientras conectas el cable USB de datos al ordenador y luego suéltalo.
- En el ordenador aparece una unidad llamada RPI-RP2. Arrastra a ella el archivo descargado; al terminar la copia, la unidad desaparece sola y la placa se reinicia con MicroPython.
- Abre Thonny y elige MicroPython (Raspberry Pi Pico) en el menú del intérprete, abajo a la derecha. Si lo prefieres, la ventana "Install or update MicroPython" de Thonny hace la misma instalación con un clic si eliges la variante Pico W / Pico WH.
- Escribe import network en el Shell. Si no hay error, tienes instalado el firmware correcto con soporte inalámbrico.
Paso 2: Conectarse al WiFi con network.WLAN
La Pico W tiene dos interfaces inalámbricas: en modo WLAN.IF_STA (estación) se conecta a tu router como un móvil, y en modo WLAN.IF_AP (punto de acceso) crea su propia red WiFi. Empecemos por el modo estación. Pega el código siguiente en un archivo nuevo de Thonny, escribe el nombre de tu red y la contraseña y guárdalo en la Pico como wifi.py. Todos los ejemplos siguientes usan este archivo con import wifi, así tu contraseña está en un solo sitio. Si usas una versión de MicroPython anterior a la 1.24, escribe estas constantes como network.STA_IF y network.AP_IF; los nombres antiguos también siguen funcionando en las versiones nuevas.
1# wifi.py: Pico W'ye bu adla kaydet / save it to the Pico W with this name
2import network
3import time
4
5SSID = "AgAdi" # Wi-Fi adın / your Wi-Fi name
6PASSWORD = "Sifre123" # Wi-Fi şifren / your Wi-Fi password
7HOSTNAME = "picow" # http://picow.local adresi için / for http://picow.local
8
9STATUS = {
10 0: "Boşta / idle",
11 1: "Ağa katılıyor / joining",
12 2: "IP bekleniyor / waiting for IP",
13 3: "Bağlandı / connected",
14 -1: "Bağlantı başarısız / connection failed",
15 -2: "Ağ bulunamadı / network not found",
16 -3: "Şifre hatalı / wrong password",
17}
18
19
20def connect(timeout=20):
21 network.country("TR") # ülke kodu / country code
22 network.hostname(HOSTNAME) # ağdaki adı / name on the network
23 wlan = network.WLAN(network.WLAN.IF_STA)
24 wlan.active(True)
25 wlan.config(pm=network.WLAN.PM_NONE) # güç tasarrufunu kapat / disable power saving
26 if not wlan.isconnected():
27 wlan.connect(SSID, PASSWORD)
28 for _ in range(timeout):
29 code = wlan.status()
30 print(code, STATUS.get(code, "?"))
31 if code < 0 or code == 3:
32 break
33 time.sleep(1)
34 if wlan.status() != 3:
35 raise RuntimeError("Wi-Fi: " + STATUS.get(wlan.status(), "?"))
36 print("IP:", wlan.ifconfig()[0])
37 return wlan
38
39
40if __name__ == "__main__":
41 connect()Veamos las líneas clave. network.country("TR") indica al chip inalámbrico qué normas de canales debe seguir; cambia TR por el código de tu país, por ejemplo ES, MX o AR. Si no lo haces, puede costarte ver redes en los canales 12 y 13, que usan algunos routers (en firmwares antiguos se hace con rp2.country()). wlan.config(pm=network.WLAN.PM_NONE) desactiva el ahorro de energía (los ejemplos antiguos escriben el mismo ajuste como pm=0xa11140): por defecto la Pico W ahorra energía, y eso puede hacer que el servidor web responda tarde o que la conexión se caiga al cabo de unas horas. El bucle muestra el código de estado cada segundo y se detiene al llegar a 3 o al recibir un código de error negativo. Así la placa nunca espera para siempre y ves en pantalla qué ha fallado.
¿Qué significan los códigos de wlan.status()?
La mayoría de los problemas de conexión se resuelven en segundos mirando el número que devuelve wlan.status(). MicroPython también ofrece constantes para estos números en el módulo network; tienes ambos en la tabla siguiente:
| Código | Constante | Significado | Qué hacer |
|---|---|---|---|
| 0 | STAT_IDLE | Sin conexión, no se ha iniciado nada | Comprueba que se llamó a wlan.active(True) y wlan.connect() |
| 1 | STAT_CONNECTING | Uniéndose a la red | Espera unos segundos |
| 2 | (sin constante) | Unida a la red, esperando una IP del router | Si tarda mucho, revisa el DHCP del router |
| 3 | STAT_GOT_IP | Conectada y con dirección IP | Todo listo |
| -1 | STAT_CONNECT_FAIL | Fallo de conexión | Revisa la señal y la alimentación y vuelve a intentarlo |
| -2 | STAT_NO_AP_FOUND | Red no encontrada | Revisa el nombre de la red, la banda de 2,4 GHz y la distancia |
| -3 | STAT_WRONG_PASSWORD | Error de autenticación | Vuelve a escribir la contraseña respetando mayúsculas y minúsculas |
Si obtienes el código -2, la Pico W no ve tu red. Listar las redes cercanas descubre el problema enseguida: si la tuya no aparece, o emite en 5 GHz o la señal es demasiado débil. Un RSSI mejor que -70 dBm (por ejemplo -55 dBm) es cómodo; hacia -80 dBm la conexión empieza a cortarse.
1import network
2
3wlan = network.WLAN(network.WLAN.IF_STA)
4wlan.active(True)
5for ssid, bssid, channel, rssi, security, hidden in wlan.scan():
6 print(ssid.decode(), "| kanal / channel:", channel, "| RSSI:", rssi, "dBm")Paso 3: Un servidor web sencillo con MicroPython (página para encender y apagar un LED)
Ahora convertiremos la Pico W en un pequeño servidor web que puedes abrir desde el móvil. No hace falta ninguna librería extra; basta con el módulo socket de MicroPython. Guarda el código siguiente como main.py y ejecútalo. Escribe la dirección que aparece en el Shell (por ejemplo http://192.168.1.42) en el navegador de un móvil conectado a la misma red WiFi; los botones ON y OFF de la página encienden y apagan el LED de la placa.
1import socket
2from machine import Pin
3import wifi
4
5wlan = wifi.connect()
6led = Pin("LED", Pin.OUT) # Pico W dahili LED / Pico W onboard LED
7led_on = False
8
9
10def page(on):
11 state = "AÇIK / ON" if on else "KAPALI / OFF"
12 return """<!DOCTYPE html>
13<html><head><meta charset="utf-8">
14<meta name="viewport" content="width=device-width, initial-scale=1">
15<title>Pico W LED</title></head>
16<body style="font-family:sans-serif;text-align:center">
17<h1>Pico W LED</h1>
18<p>Durum / State: <b>""" + state + """</b></p>
19<p><a href="/on"><button style="font-size:24px">AÇ / ON</button></a>
20<a href="/off"><button style="font-size:24px">KAPAT / OFF</button></a></p>
21</body></html>"""
22
23
24addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1]
25server = socket.socket()
26server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # EADDRINUSE hatasını önler / prevents EADDRINUSE
27server.bind(addr)
28server.listen(2)
29print("Tarayıcıda aç / open in browser: http://" + wlan.ifconfig()[0])
30
31while True:
32 client, remote = server.accept() # bir tarayıcı bekle / wait for a browser
33 try:
34 request = client.recv(1024) # b"GET /on HTTP/1.1 ..."
35 parts = request.split(b" ")
36 path = parts[1] if len(parts) > 1 else b"/"
37 if path == b"/on":
38 led.on()
39 led_on = True
40 elif path == b"/off":
41 led.off()
42 led_on = False
43 if path in (b"/", b"/on", b"/off"):
44 client.sendall("HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
45 client.sendall(page(led_on))
46 else:
47 client.sendall("HTTP/1.0 404 Not Found\r\n\r\n") # ör. /favicon.ico / e.g. /favicon.ico
48 except OSError as e:
49 print("Bağlantı hatası / connection error:", e)
50 finally:
51 client.close()Veamos cómo funciona. Con bind y listen, la Pico W empieza a escuchar en el puerto 80 (HTTP), y accept() espera hasta que se conecta un navegador. La primera línea de la petición del navegador es del tipo "GET /on HTTP/1.1"; el código la divide por los espacios para encontrar la ruta pedida (/on) y ajusta el LED en consecuencia. Después envía la cabecera HTTP ("HTTP/1.0 200 OK" y el tipo de contenido), una línea en blanco y, por último, la página HTML, y cierra la conexión. La línea meta viewport hace que la página se adapte bien al móvil, y charset=utf-8 que los acentos y la ñ se vean correctamente.
| Ruta | Qué hace |
|---|---|
| / | Muestra la página y el estado actual del LED |
| /on | Enciende el LED y vuelve a enviar la página |
| /off | Apaga el LED y vuelve a enviar la página |
| /favicon.ico y otras | Devuelve 404; los navegadores piden esta ruta por su cuenta para el icono de la pestaña |
Conectar un relé o un LED externo en lugar del LED integrado
Cuando funcione con el LED integrado, para controlar un aparato real desde la misma página solo cambias una línea: sustituye Pin("LED", Pin.OUT) por, por ejemplo, Pin(16, Pin.OUT). La resistencia adecuada para un LED externo la calculas con la herramienta Resistencia para LED; para un pin de 3,3 V bastan 220–330 Ω. Si usas un módulo de relé, aliméntalo desde el pin VBUS de 5 V y conecta su entrada IN al GPIO. Muchos módulos de relé se activan con una señal LOW; en ese caso intercambia las líneas led.on() y led.off(). Tienes los detalles del cableado en ¿Qué es un módulo de relé?.
| Componente | Pin del componente | Pin de la Pico W (n.º de pin físico) |
|---|---|---|
| LED externo | Ánodo (+), a través de una resistencia de 220 Ω | GP14 (19) |
| LED externo | Cátodo (−) | GND (18) |
| DHT22 | VCC / DATA / GND | 3V3(OUT) (36) / GP15 (20) / GND (38) |
| Módulo de relé | VCC | VBUS, 5 V del USB (40) |
| Módulo de relé | IN | GP16 (21) |
| Módulo de relé | GND | GND (23) |
Paso 4: Mostrar datos de un sensor en directo en una página web
La página del LED se recargaba entera cada vez que pulsabas un botón. En una página que muestra medidas queda mucho mejor que los valores se actualicen sin recargar. Para eso usaremos dos rutas: / envía la propia página y /data solo las medidas en formato JSON. Un pequeño código JavaScript en la página lee /data cada dos segundos y cambia las cifras. El ejemplo muestra el sensor de temperatura interno, que no necesita componentes extra, y la intensidad de la señal WiFi (RSSI); además monta el servidor con el módulo asyncio de MicroPython, para que la Pico W siga midiendo mientras espera peticiones.
1import asyncio
2import json
3import time
4from machine import ADC, Pin
5import wifi
6
7wlan = wifi.connect()
8sensor = ADC(4) # dahili sıcaklık sensörü / internal temperature sensor
9led = Pin("LED", Pin.OUT)
10start = time.time()
11readings = {"temp": 0, "rssi": 0, "uptime": 0}
12
13HTML = """<!DOCTYPE html>
14<html><head><meta charset="utf-8">
15<meta name="viewport" content="width=device-width, initial-scale=1">
16<title>Pico W</title></head>
17<body style="font-family:sans-serif;text-align:center">
18<h1>Pico W</h1>
19<p>Sıcaklık / Temperature: <b id="t">-</b> °C</p>
20<p>Wi-Fi sinyali / signal: <b id="r">-</b> dBm</p>
21<p>Çalışma süresi / uptime: <b id="u">-</b> s</p>
22<script>
23async function update() {
24 try {
25 const d = await (await fetch("/data")).json();
26 document.getElementById("t").textContent = d.temp;
27 document.getElementById("r").textContent = d.rssi;
28 document.getElementById("u").textContent = d.uptime;
29 } catch (e) {}
30}
31update();
32setInterval(update, 2000);
33</script>
34</body></html>"""
35
36
37def read_temp():
38 volts = sensor.read_u16() * 3.3 / 65535
39 return round(27 - (volts - 0.706) / 0.001721, 1)
40
41
42async def measure():
43 while True:
44 readings["temp"] = read_temp()
45 readings["rssi"] = wlan.status("rssi") # yalnız STA modunda / STA mode only
46 readings["uptime"] = time.time() - start
47 led.toggle() # kalp atışı / heartbeat
48 await asyncio.sleep(2)
49
50
51async def handle(reader, writer):
52 try:
53 line = await reader.readline() # b"GET /data HTTP/1.1"
54 while True: # başlıkları atla / skip the headers
55 header = await reader.readline()
56 if header in (b"\r\n", b""):
57 break
58 parts = line.split(b" ")
59 path = parts[1] if len(parts) > 1 else b"/"
60 if path == b"/":
61 writer.write(b"HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
62 writer.write(HTML.encode())
63 elif path == b"/data":
64 writer.write(b"HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n")
65 writer.write(json.dumps(readings).encode())
66 else:
67 writer.write(b"HTTP/1.0 404 Not Found\r\n\r\n")
68 await writer.drain()
69 except OSError as e:
70 print("Bağlantı hatası / connection error:", e)
71 finally:
72 writer.close()
73 await writer.wait_closed()
74
75
76async def main():
77 await asyncio.start_server(handle, "0.0.0.0", 80)
78 print("Tarayıcıda aç / open in browser: http://" + wlan.ifconfig()[0])
79 await measure()
80
81
82asyncio.run(main())asyncio.start_server() ejecuta la función handle como una tarea aparte por cada nueva conexión del navegador, mientras la tarea measure() toma una medida cada dos segundos en segundo plano y hace parpadear el LED integrado. Por el parpadeo sabrás también que la placa no se ha colgado. Ojo: con asyncio, convierte el texto a bytes con .encode() antes de enviarlo, o las páginas con acentos darán error. El sensor de temperatura interno mide la temperatura del propio chip, así que da valores ruidosos y unos grados distintos de la temperatura ambiente; la fórmula 27 − (V − 0,706) / 0,001721 del código procede de la hoja de datos del RP2040. Para la temperatura real de la habitación, usa un sensor externo.

Para medir de verdad temperatura y humedad, conecta un DHT22 (DATA a GP15). El driver de los sensores DHT viene incluido en el firmware de la Pico W, así que no tienes que subir nada más. En la función measure() del código del sensor, sustituye la línea readings["temp"] = read_temp() por una llamada a read_sensor(), que tienes abajo, y añade al HTML una línea para la humedad. El DHT22 no debe leerse más de una vez cada dos segundos, que es justo el ritmo del bucle. Tienes más detalles del sensor en Sensor de temperatura y humedad DHT11.
1import dht
2from machine import Pin
3
4dht_sensor = dht.DHT22(Pin(15)) # DATA ucu GP15'te / DATA pin on GP15
5
6
7def read_sensor():
8 try:
9 dht_sensor.measure() # ölçümü başlat / trigger a reading
10 readings["temp"] = dht_sensor.temperature() # °C
11 readings["hum"] = dht_sensor.humidity() # % bağıl nem / % relative humidity
12 except OSError as e:
13 print("DHT22 okunamadı / read failed:", e)Paso 5: Llamar a una API con urequests (traer datos de internet)
La Pico W puede ser cliente además de servidor: envía una petición a un servicio en línea y lee la respuesta. El módulo requests viene incluido en el firmware de la Pico W; el nombre urequests que verás en ejemplos antiguos apunta al mismo módulo, así que funcionan las dos formas. El ejemplo siguiente obtiene la temperatura, la humedad y la velocidad del viento actuales en Estambul desde el servicio meteorológico gratuito Open-Meteo, que no necesita clave de API. Solo tienes que cambiar LAT y LON por los de tu ciudad, por ejemplo 40.42 y -3.70 para Madrid.
1import requests
2import wifi
3
4wifi.connect()
5
6# İstanbul; kendi konumunu yaz / Istanbul; put your own location
7LAT, LON = 41.01, 28.98
8URL = ("https://api.open-meteo.com/v1/forecast?latitude={}&longitude={}"
9 "¤t=temperature_2m,relative_humidity_2m,wind_speed_10m").format(LAT, LON)
10
11response = requests.get(URL)
12try:
13 if response.status_code == 200:
14 current = response.json()["current"]
15 print("Sıcaklık / temperature:", current["temperature_2m"], "°C")
16 print("Nem / humidity:", current["relative_humidity_2m"], "%")
17 print("Rüzgâr / wind:", current["wind_speed_10m"], "km/h")
18 else:
19 print("HTTP hatası / HTTP error:", response.status_code)
20finally:
21 response.close() # soketi ve belleği serbest bırak / free the socket and memoryEn este código hay tres cosas a tener en cuenta. Primero, llama a response.close() después de cada respuesta; las respuestas sin cerrar consumen sockets y memoria, y tras unas cuantas peticiones aparecerá "OSError: [Errno 12] ENOMEM". Segundo, response.json() carga toda la respuesta en memoria; la Pico W tiene 264 KB de RAM en total, así que con APIs que devuelven JSON grandes usa direcciones que pidan solo los campos necesarios (como el parámetro current de aquí). Tercero, una conexión HTTPS necesita memoria extra para el cifrado; si haces peticiones periódicas en un bucle, añadir gc.collect() entre ellas reduce la fragmentación de la memoria. Con el mismo método puedes enviar mensajes de Telegram, escribir datos en una hoja de cálculo o consultar el tipo de cambio; la configuración del bot de Telegram es la misma que en Bot de Telegram con ESP32.
Paso 6: La hora exacta de internet con NTP
La Pico W tiene un reloj en tiempo real (RTC) interno, pero sin pila de respaldo: cada vez que se enciende, el reloj vuelve al 1 de enero de 2021. Con WiFi es muy fácil obtener la hora correcta de los servidores NTP de internet: la función settime() del módulo integrado ntptime pone el reloj interno en UTC. Para la hora local el código suma un desfase fijo; el ejemplo usa 3 horas (10 800 segundos) para Turquía. En España peninsular pon UTC_OFFSET a 1 * 3600 en invierno y 2 * 3600 en verano; en México, -6 * 3600.
1import time
2import ntptime
3import wifi
4
5wifi.connect()
6ntptime.host = "pool.ntp.org" # varsayılan sunucu / default server
7UTC_OFFSET = 3 * 3600 # Türkiye UTC+3; kendi saat dilimini yaz / set your own time zone
8
9for attempt in range(5):
10 try:
11 ntptime.settime() # dahili saati UTC'ye ayarlar / sets the internal clock to UTC
12 print("Saat ayarlandı / time set")
13 break
14 except OSError as e:
15 print("NTP hatası / NTP error:", e)
16 time.sleep(2)
17
18DAYS = ("Pzt/Mon", "Sal/Tue", "Çar/Wed", "Per/Thu", "Cum/Fri", "Cmt/Sat", "Paz/Sun")
19
20while True:
21 y, mo, d, h, mi, s, wd, yd = time.localtime(time.time() + UTC_OFFSET)
22 print("%02d.%02d.%d %s %02d:%02d:%02d" % (d, mo, y, DAYS[wd], h, mi, s))
23 time.sleep(1)Por defecto ntptime usa el servidor pool.ntp.org y espera un segundo la respuesta; si no llega, lanza "OSError: [Errno 110] ETIMEDOUT", por eso el código lo intenta cinco veces. El reloj interno puede desviarse unos segundos con el tiempo, así que en proyectos que funcionan mucho tiempo vuelve a llamar a settime() una vez al día. En los países con horario de verano el desfase cambia dos veces al año; tendrás que gestionarlo en el código con una comprobación de la fecha. Si quieres mostrar la hora en una pantalla, combina este código con los ejemplos de MicroPython de los artículos sobre la pantalla OLED o la LCD I2C; la versión para ESP32 está en ESP32 NTP.
Crear tu propia red (modo AP) y la dirección picow.local
Donde no hay router, por ejemplo en el puesto de una feria de ciencias o en el jardín, la Pico W puede emitir su propia red WiFi. En modo punto de acceso conectas el móvil directamente a la red "PicoW-BlueGrays" y abres la página en http://192.168.4.1. El código del servidor web funciona sin cambios; solo escribe las líneas siguientes en lugar de wlan = wifi.connect() y añade wlan = ap. La contraseña debe tener al menos 8 caracteres. La línea del RSSI del ejemplo del sensor solo funciona en modo estación, así que bórrala en modo AP. En este modo la Pico W no tiene acceso a internet, por lo que los ejemplos de NTP y de la API no funcionan.
1import network
2
3ap = network.WLAN(network.WLAN.IF_AP)
4ap.config(ssid="PicoW-BlueGrays", password="bluegrays123") # şifre en az 8 karakter / at least 8 characters
5ap.active(True)
6while not ap.active():
7 pass
8print("Ağ hazır / network ready:", ap.ifconfig()[0]) # genellikle 192.168.4.1 / usually 192.168.4.1Si te resulta pesado leer la IP en el Shell cada vez, puedes usar un nombre. Las versiones actuales de MicroPython admiten mDNS en la Pico W: gracias a la línea network.hostname("picow") de wifi.py, la placa también responde en http://picow.local. Esta dirección suele funcionar en Windows, macOS, Linux y iPhone; algunos móviles Android no abren direcciones .local, así que allí usa la IP. Si quieres que la IP no cambie nunca, lo más fiable es asignar una IP fija a la dirección MAC de la Pico W desde la configuración del router (reserva DHCP).
Nota sobre la Pico 2 W: ¿qué cambia?
La Pico 2 W tiene el mismo tamaño y la misma distribución de pines que la Pico W y usa el mismo chip inalámbrico CYW43439, pero su procesador es el RP2350, más rápido. En el software, la única diferencia es el firmware: descarga el archivo RPI_PICO2_W de micropython.org, y al conectarla con BOOTSEL la unidad aparece como RP2350. Todo el código MicroPython de este artículo funciona sin cambios. Con 520 KB de RAM, las peticiones HTTPS, las respuestas JSON grandes y las páginas HTML largas caben mucho más holgadas en la Pico 2 W. En el Arduino IDE se elige la placa Raspberry Pi Pico 2W. Una nota: las primeras versiones del RP2350 tienen una errata conocida del chip (E9) que afecta a las resistencias pull-down internas; para los pulsadores, conectarlos a GND y usar PULL_UP es la opción más segura. Para funciones avanzadas como los dos núcleos y el PIO, consulta PIO y doble núcleo de la Pico.
Alternativa: programar la Pico W con el Arduino IDE (arduino-pico)
Si te resultan más familiares C++ y las librerías de Arduino, puedes programar la Pico W desde el Arduino IDE con el core arduino-pico de Earle Philhower. Incluye librerías WiFi y WebServer compatibles con las del ESP32, así que el código de servidor web escrito para el ESP32 funciona en la Pico W con pequeños cambios.
- En el Arduino IDE abre Archivo > Preferencias y añade https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json en el campo «Gestor de URLs adicionales de tarjetas».
- En el Gestor de tarjetas busca pico e instala el paquete Raspberry Pi Pico/RP2040/RP2350 de Earle F. Philhower.
- Elige Raspberry Pi Pico W en Herramientas > Placa (Raspberry Pi Pico 2W para la Pico 2 W).
- En la primera carga, conecta la placa manteniendo pulsado BOOTSEL; el Arduino IDE la detecta como unidad UF2. En las siguientes cargas basta con elegir el puerto serie que aparece en Herramientas > Puerto.
- Tras cargar el código, abre el Monitor Serie a 115200 baudios y lee la dirección IP.
1#include <WiFi.h>
2#include <WebServer.h>
3#include <LEAmDNS.h>
4
5const char* ssid = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
6const char* password = "Sifre123"; // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9bool ledOn = false;
10
11void sendPage() {
12 String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
13 "<meta name='viewport' content='width=device-width, initial-scale=1'>"
14 "<title>Pico W</title></head>"
15 "<body style='font-family:sans-serif;text-align:center'><h1>Pico W LED</h1>";
16 html += "<p>Durum / State: <b>";
17 html += ledOn ? "AÇIK / ON" : "KAPALI / OFF";
18 html += "</b></p><p><a href='/on'><button>AÇ / ON</button></a> ";
19 html += "<a href='/off'><button>KAPAT / OFF</button></a></p>";
20 html += "<p>Sıcaklık / Temp: ";
21 html += String(analogReadTemp(), 1); // dahili sensör / internal sensor
22 html += " °C</p></body></html>";
23 server.send(200, "text/html", html);
24}
25
26void setup() {
27 Serial.begin(115200);
28 pinMode(LED_BUILTIN, OUTPUT); // Pico W'de kablosuz yongadaki LED / the LED on the wireless chip
29 WiFi.mode(WIFI_STA);
30 WiFi.begin(ssid, password);
31 while (WiFi.status() != WL_CONNECTED) {
32 delay(500);
33 Serial.print(".");
34 }
35 Serial.println();
36 Serial.print("IP: ");
37 Serial.println(WiFi.localIP()); // bu adresi telefonda aç / open this address on your phone
38
39 MDNS.begin("picow"); // http://picow.local
40 server.on("/", sendPage);
41 server.on("/on", []() { ledOn = true; digitalWrite(LED_BUILTIN, HIGH); sendPage(); });
42 server.on("/off", []() { ledOn = false; digitalWrite(LED_BUILTIN, LOW); sendPage(); });
43 server.onNotFound([]() { server.send(404, "text/plain", "404"); });
44 server.begin();
45}
46
47void loop() {
48 server.handleClient();
49 MDNS.update();
50}Este sketch hace lo mismo que la página del LED en MicroPython y añade la temperatura interna leída con analogReadTemp(). En la Pico W, LED_BUILTIN controla automáticamente el LED conectado al chip inalámbrico, y gracias a la línea MDNS.begin("picow") la página también se abre en http://picow.local. El driver WiFi añade unos 220 KB al programa compilado, así que la primera compilación puede tardar un poco. Para elegir entre MicroPython y Arduino, piensa en esto: con MicroPython guardas el código y lo pruebas al instante; con Arduino esperas a que compile, pero obtienes un código más rápido y un gran catálogo de librerías.
Ideas de proyectos con la Raspberry Pi Pico W
- Termómetro WiFi: consulta desde el móvil la temperatura y la humedad medidas con un DHT11 o DHT22.
- Lámpara desde el móvil: añade un módulo de relé a la página del LED de este artículo y enciende y apaga la lámpara del escritorio.
- Control de humedad de plantas: muestra en la página el valor del sensor de humedad del suelo y avisa cuando la tierra se seque.
- Aviso de movimiento: cuando un sensor PIR detecte a alguien, envía un mensaje de Telegram a tu móvil con urequests.
- Reloj de internet: muestra la hora NTP con la fecha y el día de la semana en una pantalla OLED.
- Domótica: instala la librería umqtt.simple con mip y envía tus medidas a Home Assistant por MQTT; la idea se explica en ESP32 MQTT.
- Panel en tiempo real: para páginas que se actualicen más rápido, adapta a la Pico W las ideas del artículo servidor web asíncrono con ESP32, que usa WebSocket.
Errores frecuentes y soluciones
| Síntoma o error | Causa | Solución |
|---|---|---|
| ImportError: no module named 'network' | Se cargó el firmware de la Pico normal en la Pico W | Carga el UF2 RPI_PICO_W (RPI_PICO2_W para la Pico 2 W) |
| wlan.status() se queda en -2 | La red no se ve: 5 GHz, nombre de red incorrecto o señal débil | Activa la banda de 2,4 GHz, busca la red con wlan.scan(), acerca la placa al router |
| wlan.status() devuelve -3 | Contraseña incorrecta | Vuelve a escribirla respetando mayúsculas, minúsculas y espacios |
| OSError: [Errno 98] EADDRINUSE | El socket del servidor anterior sigue ocupando el puerto 80 | Usa SO_REUSEADDR y reinicia con Ctrl+D |
| La página no se abre en el móvil | El móvil está con datos móviles, en la red de invitados o el router tiene el aislamiento de clientes activado | Conecta el móvil al mismo WiFi y escribe la dirección con http, no https |
| OSError: -2 (urequests) | No se pudo resolver el nombre: sin WiFi o problema de DNS | Llama primero a wifi.connect() y revisa la URL |
| OSError: [Errno 12] ENOMEM | Memoria llena | Usa response.close() y gc.collect(), pide respuestas más pequeñas |
| La conexión se cae al cabo de horas | Ahorro de energía o reinicio del router | Usa pm=network.WLAN.PM_NONE, comprueba wlan.isconnected() en el bucle y reconecta |
| No funciona al desconectarla del ordenador | El código no está guardado como main.py o falta wifi.py en la Pico | Guarda los dos archivos en la Pico |
Como has visto, conectar la Raspberry Pi Pico W al WiFi, servir una página web y traer datos de internet es cuestión de un par de archivos: wifi.py se encarga de la conexión y main.py del proyecto en sí. Para afianzar lo básico de la Pico, en la app BlueGrays tienes proyectos con la Raspberry Pi Pico para encender LEDs, un semáforo, PWM y LED RGB, y en el lado del ESP32 proyectos de conexión WiFi, servidor web asíncrono, reloj NTP y API del tiempo, todos con esquema del circuito y código paso a paso.
Preguntas frecuentes
¿La Raspberry Pi Pico W se conecta a WiFi de 5 GHz?
No. El chip CYW43439 de la Pico W y la Pico 2 W solo funciona en la banda de 2,4 GHz y no ve las redes de 5 GHz. Asegúrate de que la banda de 2,4 GHz de tu router está activada; si ambas bandas comparten nombre y tienes problemas, dar un nombre propio a la de 2,4 GHz suele solucionarlo.
¿Cómo se instala MicroPython en la Pico W?
Descarga de micropython.org el archivo .uf2 de la placa RPI_PICO_W. Mantén pulsado BOOTSEL mientras conectas la Pico W al ordenador y arrastra el archivo a la unidad RPI-RP2 que aparece. La placa se reinicia y queda lista para usar con Thonny; la ventana "Install or update MicroPython" de Thonny hace lo mismo.
¿Cómo averiguo la dirección IP de la Pico W?
Una vez conectada, wlan.ifconfig()[0] te da la IP, y el archivo wifi.py de este artículo la muestra en el Shell. Si la placa no está conectada al ordenador, mira la lista de dispositivos conectados en la configuración del router o prueba http://picow.local en dispositivos compatibles con mDNS.
¿Por qué el LED integrado de la Pico W no se enciende con Pin(25)?
En la Pico W el LED integrado está conectado al chip inalámbrico, no al procesador, y GP25 se usa como línea de selección de ese chip. Con Pin("LED", Pin.OUT) en MicroPython o LED_BUILTIN en el Arduino IDE, el LED se enciende correctamente. Esta forma también funciona en la Pico normal, así que puedes usarla siempre.
¿Puedo acceder al servidor web de la Pico W desde internet?
Técnicamente sí, abriendo puertos en el router, pero no se recomienda, porque un servidor MicroPython sencillo no tiene cifrado ni autenticación. Para controlarla desde fuera, un intermediario como MQTT, un bot de Telegram o un servicio IoT en la nube es mucho más seguro.
¿Pico W o ESP32: cuál es mejor para proyectos WiFi?
Las dos ofrecen WiFi de 2,4 GHz y Bluetooth. Si quieres trabajar con MicroPython, con documentación ordenada y pines sin sorpresas, elige la Pico W; si necesitas más velocidad, muchas entradas analógicas y un amplio catálogo de librerías Arduino, el ESP32 encaja mejor. Para proyectos sencillos de servidor web, sensores y APIs, ambas cumplen de sobra.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Parpadeo LED Integrado Raspberry Pi Pico (Pico y Pico W)
¡El proyecto de apertura de la serie Raspberry Pi Pico! Hacemos parpadear el LED verde integrado para verificar que la placa funciona — un experimento clásico "Hello World". SIN componentes externos, solo Pico y cable USB. El código está escrito en MicroPython (el lenguaje oficialmente respaldado por la Raspberry Pi Foundation). Aprende la clase machine.Pin, el modo Pin.OUT, los métodos led.on()/off() y time.sleep() en Thonny IDE. Sigue cada cambio en vivo en l

Encendido de un LED externo con la Raspberry Pi Pico (placa de pruebas)
El siguiente paso tras el LED integrado de Pico: conectar un LED externo a la placa de pruebas y controlarlo a través del pin GP14. Con este proyecto aprenderás a utilizar cualquier pin GPIO de uso general del Pico como salida, la polaridad del LED (patilla larga = ánodo/+, patilla corta = cátodo/–) y por qué es imprescindible utilizar una resistencia limitadora de corriente (220 Ω). Si no colocas la resistencia, el LED recibirá una corriente excesiva y podría quemarse. El circuito es muy sencil

Simulador de Semáforo Raspberry Pi Pico (3 LEDs Secuenciales)
Simulamos un semáforo real con LEDs rojo, amarillo y verde. Verde 4 seg "pase", amarillo 1,5 seg "prepárese", rojo 3 seg "detenga" y rojo+amarillo 1 seg "arranque" (patrón europeo). Aprende definición de función, lógica de máquina de estados y sincronización multi-GPIO. Circuito simple: 3 LEDs en GP11/GP12/GP13.

Raspberry Pi Pico PWM LED Fade (Efecto Respiración)
¡El LED ya no solo parpadea — respira! Con el PWM (modulación por ancho de pulso) del Raspberry Pi Pico, el brillo sube y baja lentamente. Aprende la clase machine.PWM, duty_u16() (brillo de 16 bits 0–65535), la frecuencia PWM, bucles range() y salida tipo analógica. Base para mezcla de color RGB, control de motores, servos y buzzer.

Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
En este proyecto, convertimos el ESP32 en un servidor web asíncrono que puedes controlar desde tu teléfono o tu ordenador, siempre que estén conectados a la misma red Wi-Fi. Gracias a la biblioteca ESPAsyncWebServer, el servidor puede procesar varias solicitudes al mismo tiempo (a diferencia del clásico WebServer.h, que se bloquea con una sola solicitud).

Conexión Wi-Fi STA con ESP32 (con pantalla LCD)
En este proyecto, conectamos el ESP32 a la red Wi-Fi doméstica en modo Station (STA) de forma segura y tolerante a fallos. Separamos el SSID y la contraseña en el archivo secrets.h para evitar que se filtren a Git, configuramos un mecanismo de reconexión automática y mostramos el nivel de señal RSSI y la dirección IP en una pantalla LCD I2C. El LED interno actúa como indicador de estado.

ESP32: hora real desde Internet con NTP
El ESP32 se conecta a Wi-Fi y obtiene la hora real con precisión de milisegundos desde servidores NTP (Network Time Protocol). Gracias a configTzTime(), se aplica automáticamente la zona horaria de Turquía (TRT, UTC+3) y el cambio DST se gestiona mediante la cadena POSIX TZ. La hora se muestra en el monitor serie y en una pantalla LCD I2C opcional. configTzTime() inicia el servicio SNTP; se realizan resincronizaciones periódicas mientras hay acceso a la red, y el reloj del sistema sigue avan

ESP32 HTTPClient + API del tiempo (con pantalla LCD)
En este proyecto, utilizamos el ESP32 para realizar una llamada a la API REST de la página web de información meteorológica (wttr.in) a través de Internet, utilizando HTTPClient.h. Analizamos la respuesta JSON devuelta con ArduinoJson v7 y mostramos la información sobre la ciudad, la temperatura, la humedad, el tiempo y el viento en una pantalla LCD I2C, tanto en turco como en inglés. wttr.in es gratuito y no requiere clave API: basta con escribir el nombre de cualquier ciudad para obtener su
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

