Correo: [email protected] - Teléfono: +56979962128

En esta guía, aprenderá a crear un servidor web local básico para Raspberry Pi Pico para controlar las salidas y obtener datos. Por ejemplo, crearemos una página web para controlar el encendido y apagado de un LED y obtener valores aleatorios generados por el Pico. Este ejemplo se puede modificar o ampliar fácilmente para controlar varias salidas y obtener datos de sensores en lugar de números aleatorios.

Este tutorial solo es compatible con la Raspberry Pi Pico W compatible con Wi-Fi. En este tutorial, cuando nos referimos a la Raspberry Pi Pico, nos referimos a la Raspberry Pi Pico W.
 
Servidor web básico Raspberry Pi Pico MicroPython
 

Requisitos previos: firmware de MicroPython

Para seguir este tutorial, necesitas tener instalado el firmware MicroPython en tu placa Raspberry Pi Pico. También necesitas un IDE para escribir y cargar el código en la placa.

El IDE de MicroPython recomendado para Raspberry Pi Pico es Thonny IDE. Sigue el siguiente tutorial para aprender a instalar Thonny IDE, instalar el firmware de MicroPython y cargar código en la placa.

 

Introducción de conceptos básicos

 

La Raspberry Pi Pico como servidor web

En pocas palabras, un servidor web es una “computadora” que proporciona páginas web. Almacena los archivos del sitio web, incluyendo todos los documentos HTML y recursos relacionados, como imágenes, hojas de estilo CSS, fuentes y otros archivos. También envía estos archivos al navegador web del usuario cuando este realiza una solicitud al servidor.

 
Servidor web Raspberry Pi Pico
 

Al usar la Raspberry Pi Pico como servidor web, básicamente la conviertes en una pequeña computadora que almacena y proporciona páginas web. Cuando los usuarios acceden a una página web, sus navegadores envían solicitudes a la Pico mediante el Protocolo de Transferencia de Hipertexto (HTTP). La Pico responde enviando la página web solicitada.

Cliente y servidor

Al escribir una URL en su navegador, usted (el cliente) envía una solicitud mediante el Protocolo de Transferencia de Hipertexto (HTTP) a un servidor. Cuando el servidor recibe la solicitud, envía una respuesta mediante HTTP, y usted verá la página web solicitada en su navegador. Los clientes y los servidores se comunican a través de una red informática.

En pocas palabras, los clientes realizan solicitudes a los servidores. Los servidores gestionan las solicitudes de los clientes. En este tutorial, Raspberry Pi Pico será el servidor y tú (tu navegador) será el cliente.

Dirección IP

Una dirección IP es una etiqueta numérica asignada a cada dispositivo conectado a una red informática. Consiste en una serie de cuatro valores separados por puntos, cada uno de los cuales va de 0 a 255. A continuación, un ejemplo:




192.168.1.75

 

En casa, tus dispositivos están conectados a una red privada a través de tu router (red local). Todos los dispositivos conectados a tu router forman parte de tu red local. Dentro de esta red, cada dispositivo tiene su propia dirección IP.

Los dispositivos conectados al mismo router pueden acceder entre sí mediante la dirección IP. Los dispositivos fuera de su red local no pueden acceder a sus dispositivos locales mediante su dirección IP local.

Al conectar tu Raspberry Pi Pico a tu router, se integra a tu red local. Por lo tanto, se le asignará una dirección IP local única y podrás acceder a ella desde tu ordenador en la red local.

Zócalos

Crearemos nuestro servidor web usando 

sockets

 y la 

API de sockets de Python

 .

Los sockets y la API de sockets se utilizan para enviar mensajes a través de una red. Proporcionan una forma de comunicación entre procesos (IPC). 

Los sockets se pueden utilizar en aplicaciones cliente-servidor, donde un lado actúa como servidor y espera conexiones de los clientes: eso es lo que haremos aquí (Raspberry Pi Pico es un servidor que espera conexiones de los clientes).

 

Descripción general del proyecto

Antes de ir directamente al proyecto, es importante esbozar qué hará nuestro servidor web para que sea más fácil entender cómo funciona todo

Crearemos una página web sencilla con dos botones para controlar el encendido y apagado del LED integrado de la Raspberry Pi Pico. La página también incluye otro botón para solicitar un nuevo valor aleatorio (esto se puede modificar fácilmente para solicitar lecturas del sensor).

Ejemplo básico de servidor web básico Raspberry Pi Pico

Aquí hay una explicación rápida de cómo funciona todo.

Al ingresar la dirección de Raspberry Pi Pico en su navegador web, está enviando una solicitud a Raspberry Pi Pico en la URL raíz (/). Al recibir dicha solicitud, responde con el HTML para crear la página web que vimos anteriormente.

 
Servidor web básico Raspberry Pi Pico cómo funciona solicitud respuesta
   

Al hacer clic en el botón 

“Light on”

 , se realiza una solicitud en la URL 

/lighton?.

 Al recibirla, se enciende el LED integrado y se envía la página web con el estado actualizado del LED.

Al hacer clic en el botón 

Apagar luz

 , se realiza una solicitud a la URL 

/lightoff?.

 Al hacerlo, se apaga el LED y se envía la página web con su estado actual.

 
Diagrama de funcionamiento del servidor web básico Raspberry Pi Pico
 

Finalmente, también tenemos un botón para solicitar un valor aleatorio a Raspberry Pi Pico. Este botón se puede modificar fácilmente para solicitar lecturas de sensores o cualquier otra información útil. Este botón envía una solicitud a la URL 

/value?.

 Cuando Pico recibe la solicitud, genera un nuevo valor aleatorio y envía la página HTML actualizada con dicho valor.

 
Servidor web básico Raspberry Pi Pico Solicitar un nuevo valor
   

La página HTML

A continuación puedes encontrar el HTML que usaremos para construir la página web:

 
<!DOCTYPE html>
<html>
<head>
<title>Pico Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Raspberry Pi Pico Web Server</h1>
<h2>Led Control</h2>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
<br>
<form action="./lightoff">
<input type="submit" value="Light off" />
</form>
<p>LED state: {state}</p>
<h2>Fetch New Value</h2>
<form action="./value">
<input type="submit" value="Fetch value" />
</form>
<p>Fetched value: {random_value}</p>
</body>
</html>
 

En este ejemplo particular, guardaremos el contenido del archivo HTML en una variable en nuestro script MicroPython (pero también se puede guardar en un archivo en el sistema de archivos Raspberry Pi Pico, no cubierto en este tutorial).

Esta estructura HTML crea una página web básica para controlar un LED y obtener un valor aleatorio, para interactuar con un servidor web Raspberry Pi Pico.

El

{state}

y

{random_value}

Las variables están destinadas a completarse dinámicamente con valores de la lógica del lado del servidor.

En resumen, este HTML crea tres formularios diferentes con botones.

 

Servidor web Raspberry Pi Pico: script de MicroPython

Crea un nuevo archivo en Thonny IDE y copie el siguiente código.

# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-web-server-micropython/

# Import necessary modules
import network
import socket
import time
import random
from machine import Pin

# Create an LED object on pin 'LED'
led = Pin('LED', Pin.OUT)

# Wi-Fi credentials
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'

# HTML template for the webpage
def webpage(random_value, state):
    html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>Pico Web Server</title>
            <meta name="viewport" content="width=device-width, initial-scale=1">
        </head>
        <body>
            <h1>Raspberry Pi Pico Web Server</h1>
            <h2>Led Control</h2>
            <form action="./lighton">
                <input type="submit" value="Light on" />
            </form>
            <br>
            <form action="./lightoff">
                <input type="submit" value="Light off" />
            </form>
            <p>LED state: {state}</p>
            <h2>Fetch New Value</h2>
            <form action="./value">
                <input type="submit" value="Fetch value" />
            </form>
            <p>Fetched value: {random_value}</p>
        </body>
        </html>
        """
    return str(html)

# Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
    if wlan.status() >= 3:
        break
    connection_timeout -= 1
    print('Waiting for Wi-Fi connection...')
    time.sleep(1)

# Check if connection is successful
if wlan.status() != 3:
    raise RuntimeError('Failed to establish a network connection')
else:
    print('Connection successful!')
    network_info = wlan.ifconfig()
    print('IP address:', network_info[0])

# Set up socket and start listening
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen()

print('Listening on', addr)

# Initialize variables
state = "OFF"
random_value = 0

# Main loop to listen for connections
while True:
    try:
        conn, addr = s.accept()
        print('Got a connection from', addr)
        
        # Receive and parse the request
        request = conn.recv(1024)
        request = str(request)
        print('Request content = %s' % request)

        try:
            request = request.split()[1]
            print('Request:', request)
        except IndexError:
            pass
        
        # Process the request and update variables
        if request == '/lighton?':
            print("LED on")
            led.value(1)
            state = "ON"
        elif request == '/lightoff?':
            led.value(0)
            state = 'OFF'
        elif request == '/value?':
            random_value = random.randint(0, 20)

        # Generate HTML response
        response = webpage(random_value, state)  

        # Send the HTTP response and close the connection
        conn.send('HTTP/1.0 200 OKrnContent-type: text/htmlrnrn')
        conn.send(response)
        conn.close()

    except OSError as e:
        conn.close()
        print('Connection closed')
 

Solo necesitas insertar tu SSID y contraseña en las siguientes variables y el código debería funcionar de inmediato.

# Wi-Fi credentials
ssid = 'REPLACE_WITH_YOUR_SSID' 
password = 'REPLACE_WITH_YOUR_PASSWORD'

¿Cómo funciona el Código?

 

Comienza importando los módulos necesarios, incluidos network

para Wi-Fi,

socket

para la comunicación entre cliente y servidor,

tiempo

por retrasos,

random

para generar números aleatorios, y pin desde machine

para control del pin GPIO.

import network
import socket
import time
import random
from machine import Pin

Declarar el Pin del LED

Crea un objeto Pin llamado led que corresponde al LED integrado de la Raspberry Pi Pico. Está configurado como un pin de salida. Interpretará 'LED' como el LED integrado.  
led = Pin('LED', Pin.OUT)
Establece las credenciales de Wi-Fi de la red a la que deseas conectarte. Modifica estas variables con sus propias credenciales.
 
# Wi-Fi credentials 
ssid = 'REPLACE_WITH_YOUR_SSID' 
password = 'REPLACE_WITH_YOUR_PASSWORD'

Creando la página web

 

Para generar la página web, creamos una función llamada webpage() que acepta como argumentos un valor aleatorio y el estado del LED. Generamos la página dentro de una función porque nos permite cambiar su contenido dinámicamente al momento de enviarla al cliente. De esta forma, podemos enviar la página con la información más reciente sobre el estado del GPIO o el valor aleatorio.

# HTML template for the webpage
def webpage(random_value, state):
    html = f"""
         <!DOCTYPE html>
         <html>
         <head>
              <title>Pico Web Server</title>
              <meta name="viewport" content="width=device-width, initial-scale=1">
         </head>
         <body>
              <h1>Raspberry Pi Pico Web Server</h1>
              <h2>Led Control</h2>
              <form action="./lighton">
                  <input type="submit" value="Light on" />
              </form>
              <br>
              <form action="./lightoff">
                  <input type="submit" value="Light off" />
              </form>
              <p>LED state: {state}</p>
              <h2>Fetch New Value</h2>
              <form action="./value">
                  <input type="submit" value="Fetch value" />
        </form>
        <p>Fetched value: {random_value}</p>
    </body>
    </html>
    """
return str(html)
 

Para comprender mejor cómo funciona esto y el uso de f-strings junto con llaves {} para incluir variables dentro de la cadena HTML, continúa leyendo.

Las comillas triples (""") se utilizan para crear una cadena de varias líneas. Esto permite formatear fácilmente el contenido HTML sin necesidad de concatenar múltiples cadenas. De esta forma, nuestro HTML es más legible, aunque si lo prefieres, puedes concatenar todo en una sola línea.

La f antes de las comillas triples indica que es una f-string, una forma de insertar expresiones dentro de literales de texto. En este caso, permite incluir directamente variables como random_value y state dentro del contenido de la cadena.

html = f"""
 

Las llaves {} dentro de una f-string actúan como marcadores de posición para variables. Las variables dentro de las llaves se reemplazan por sus valores reales durante el formateo de la cadena.

En resumen, las expresiones {state} y {random_value} dentro del contenido HTML son espacios reservados que se sustituyen por los valores actuales de las variables state y random_value.

<p>LED state: {state}</p>
<p>Fetched value: {random_value}</p>

Este formateo dinámico de cadenas facilita la incorporación de valores de variables directamente en el contenido HTML, ofreciendo una forma clara y legible de generar páginas web dinámicas.

Cuando llamamos a esta función, devolverá una página HTML con el valor aleatorio actual y el estado del LED.

Connecting to the Internet

 

Espera a que se establezca la conexión Wi-Fi. Se verifica el estado de la conexión, y si wlan.status() es mayor o igual a 3 (lo que significa que ya se conectó a la red o falló en el intento), el bucle se detiene. Este proceso espera un máximo de 10 segundos.

El método wlan.status, como su nombre indica, revisa el estado de la conexión Wi-Fi de la Raspberry Pi. Este método devuelve un número entero con el siguiente significado:

  • 0: El WLAN no está habilitado

  • 1: El WLAN está buscando redes

  • 2: El WLAN se está conectando a una red

  • 3: El WLAN está conectado a una red

  • 4: El WLAN falló al intentar conectarse a una red

Luego, se verifica si se logró o no la conexión (sabemos que status = 3 significa que está conectado). Si wlan.status() es distinto de 3, sabemos que falló en establecer la conexión.

De lo contrario, significa que tuvimos éxito. En caso de que la conexión sea exitosa, podemos obtener la información de red utilizando el método ifconfig().

Este método devuelve la siguiente tupla de información:

network_info[0]: The IP address assigned to the Pico on the network.
network_info[1]: The subnet mask.
network_info[2]: The gateway IP address.
network_info[3]: The DNS (Domain Name System) server IP address.
  Solo necesitamos la dirección IP, así que simplemente tomamos el primer elemento de la tupla (network_info[0]).
else:
      print('Connection successful!')
      network_info = wlan.ifconfig()
      print('IP address:', network_info[0])

Creando un servidor socket

Después de establecer la conexión con nuestra red, necesitamos crear un socket de escucha que esté atento a las solicitudes entrantes y envíe el texto HTML como respuesta.

Para entenderlo mejor, la siguiente imagen muestra un diagrama de cómo funcionan los sockets en la interacción servidor-cliente: Creating a socket server diagram

Configura un socket para escuchar en el puerto 80. Usa la dirección 0.0.0.0, que indica que estará escuchando en todas las interfaces de red disponibles.

La opción SO_REUSEADDR permite que el socket reuse la dirección, evitando problemas si intentas levantar el servidor web varias veces y la dirección ya está en uso.

En código Python, sería algo así:

addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr) s.listen()

La siguiente línea obtiene información sobre la dirección del socket, específicamente la dirección IP y el puerto donde está escuchando.

addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
 

Crea un socket usando socket.socket().

s = socket.socket()
Luego, enlaza el socket a una dirección (interfaz de red y número de puerto) usando el método bind(). El método bind() acepta una variable tipo tupla con la dirección IP y el número de puerto, que guardamos previamente en la variable addr:  
s.bind(addr)
  Pon el socket en modo escucha. Esto significa que ahora está listo para aceptar conexiones entrantes.
s.listen()

Inicializando las Variables

  Inicializa las variables para el estado del LED (state) y para el valor aleatorio (random_value).  
# Initialize variables
 state ="OFF"
random_value =0

Escuchando conexiones

Dentro del bucle while, escuchamos solicitudes y enviamos respuestas. Cuando un cliente se conecta, el servidor llama al método accept() para aceptar la conexión.

Al aceptar una conexión, se crea un nuevo objeto socket para enviar y recibir datos, que se guarda en la variable conn, y la dirección del cliente queda almacenada en la variable addr.

Luego, imprime la dirección del cliente que está guardada en la variable addr.
print('Got a connection from', addr)
Los datos se intercambian entre el cliente y el servidor usando los métodos send() y recv().
La siguiente línea obtiene la solicitud recibida en el socket recién creado y la guarda en la variable request.
request = conn.recv(1024)
 

El método recv() recibe los datos desde el socket del cliente (recuerda que creamos un nuevo objeto socket en la variable conn).

El argumento de recv() especifica la cantidad máxima de datos que se pueden recibir de una vez, en bytes.

La siguiente línea simplemente imprime el contenido de la solicitud (request):

 

Obtener el contenido de la solicitud Luego, obtenemos el contenido de la solicitud con request.split()[1]. Esto divide la cadena HTTP recibida en una lista de palabras y toma el segundo elemento (índice 1) de esa lista.

Generalmente, este elemento corresponde a la ruta de la solicitud HTTP, que es la información que necesitamos para saber qué botón se presionó en la interfaz web.

try:
request = request.split()[1]
print('Request:', request)
except IndexError:
pass
 

Procesar las solicitudes

Luego revisamos el contenido de la solicitud y actuamos según corresponda. Si la solicitud es para la ruta /lighton?, encendemos el LED y actualizamos la variable state a 'ON'.
if request == '/lighton?':
print("LED on")
led.value(1)
state = "ON"
  Si la solicitud es /lightoff?, apagamos el LED y actualizamos la variable state a 'OFF'.  
elif request == '/lightoff?':
led.value(0)
state = 'OFF'
Finalmente, si la solicitud es para la ruta /value?, generamos un nuevo valor aleatorio y lo guardamos en la variable random_value.
elif request == '/value?':
random_value = random.randint(0, 20)
Como mencionamos anteriormente, en lugar de generar un valor aleatorio, puedes obtener lecturas de sensores. Enviando la respuesta Después de procesar la solicitud, llamaremos a la función webpage() con random_value y state como argumentos para generar una página HTML con los valores actualizados. El contenido para generar la página web se guarda en la variable response.  
response = webpage(random_value, state)
  Finalmente, envía la respuesta al cliente del socket usando el método send():
conn.send('HTTP/1.0 200 OKrnContent-type: text/htmlrnrn')
conn.send(response)
 

Al final, cierra el socket creado.

conn.close()
 

Raspberry Pi Pico Web Server – Demonstration

Ejecuta el código anterior en tu Raspberry Pi Pico. Solo tienes que hacer clic en el botón verde 

de ejecución

 de Thonny IDE .

Botón verde de ejecución de Thonny IDE

La dirección IP de la Raspberry Pi se imprimirá después de unos segundos. En este caso, es 192.168.1.82.

Obtener la dirección IP de Raspberry Pi Pico Thonny IDE

Abra un navegador web en su red local e introduce la dirección IP de la Raspberry Pi Pico. Debería cargarse la siguiente página web.

Servidor web básico Raspberry Pi Pico en el navegador web

Puedes hacer clic en los botones 

de encendido

 y 

apagado de luz

 para encender y apagar el LED integrado de Raspberry Pi Pico.

También puedes hacer clic en ” 

Obtener valor”

 para solicitar un nuevo valor aleatorio generado por la Raspberry Pi Pico. Debería mostrar la página web con el valor más reciente.

Servidor web Raspberry Pi Pico Solicitar un nuevo valor
 

Puedes modificar fácilmente el servidor web para solicitar lecturas de sensores o cualquier otra información útil.

También se puede acceder al servidor web desde tu teléfono inteligente siempre que esté conectado a la misma red.

 
Servidor web Raspberry Pi Pico en smartphone
 

Si deseas que Raspberry Pi Pico ejecute el servidor web sin estar conectado a tu computadora, debes cargar el código como 

main.py

 al sistema de archivos de Raspberry Pi Pico. Para ello, después de copiar el código a un nuevo archivo, ve a 

Archivo

 > 

Guardar como

 y selecciona 

Raspberry Pi Pico

 .

 
Guardar archivos en Raspberry Pi Pico Thonny IDE
 

Asigna el nombre al archivo main.py y haz clic en Aceptar para guardarlo en la Raspberry Pi Pico. Ahora, se ejecutará al

arrancar

 sin necesidad de estar conectado a la computadora.

Micropython guarda el archivo main.py en Thonny IDE

Concluyendo

En este tutorial, aprendiste los fundamentos de la creación de un servidor web con Raspberry Pi Pico. Por ejemplo, creamos una página sencilla con botones para controlar un GPIO y una sección para solicitar un nuevo valor aleatorio a la placa.

Este es solo un ejemplo básico para que entiendas cómo funciona la creación de un servidor web. La idea es modificar el proyecto para controlar los GPIO y así activar relés, controlar motores y mostrar lecturas de sensores o cualquier otra información útil.

 

Preguntas frecuentes

¿Puede la Raspberry Pi Pico funcionar como servidor web?

Sí. Con MicroPython se puede crear un servidor web local en la Pico W para controlar salidas y obtener datos, por ejemplo una página que encienda y apague un LED y muestre valores generados por la placa.

¿Qué diferencia hay entre cliente y servidor?

El servidor es quien aloja la página y espera peticiones; el cliente es el navegador que las hace. En este proyecto la Pico actúa como servidor y cualquier dispositivo de la red local, como un teléfono, es el cliente.

¿Qué son los sockets en este contexto?

Son el mecanismo de programación que permite a la Pico abrir una conexión de red y quedarse escuchando peticiones. Es la base sobre la que se construye el servidor web en MicroPython.

¿Necesito conocer la dirección IP de la Pico?

Sí. La dirección IP que la placa obtiene en la red local es la que hay que escribir en el navegador para acceder a la página. Sin ella no hay forma de llegar al servidor.

¿Se puede ampliar este servidor para leer sensores?

Sí. El ejemplo usa valores aleatorios, pero se puede modificar fácilmente para controlar varias salidas y mostrar lecturas reales de sensores en lugar de números generados.

Aprende esto en un curso

Si prefieres verlo en vivo y con alguien que resuelva tus dudas, estos cursos presenciales de MCI Educación cubren el tema de este tutorial: