En este tutorial veremos cómo conseguir que una Raspberry Pi y un ESP32 se comuniquen utilizando el protocolo UDP. Cuando los dispositivos están conectados a la misma red WiFi, pueden comunicarse de manera muy sencilla mediante el intercambio de paquetes de datos utilizando el protocolo UDP. Como tanto la Raspberry Pi y el ESP32 tienen conectividad WiFi a bordo, es bastante sencillo de configurar un protocolo UDP entre los dos.
En este ejemplo, la Raspberry Pi actuará como servidor y el ESP32 como cliente.
N.B.: Este tutorial puede transponerse fácilmente a un ESP8266 (código de cliente extra al final del artículo).
Hardware
- Ordenador
- Raspberry Pi
- NodeMCU ESP32 x1 o superior (o ESP8266)
- Cable USB A macho
Código del servidor Raspberry Pi
Para comunicarnos utilizando el protocolo UDP, simplemente crearemos el servidor udp, que podrá leer y escribir en el puerto localPort. La biblioteca socket se utiliza para abrir una conexión entre dos dispositivos.
El constructor de socket espera dos parámetros, la familia de direcciones (en este caso direcciones de Internet) y el tipo de socket (en este caso UDP).
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ## Internet,UDP
El socket debe estar enlazado a un puerto de la máquina sock.bind((hostname, localPort)). Poniendo un carácter vacío en lugar de hostname (equivalente a 0.0.0.0) permite enlazar el socket a todas las interfaces locales.
#!/usr/bin/env python # -*- coding: utf-8 -*- #Libraries import socket #https://wiki.python.org/moin/UdpCommunication #Parameters localPort=8888 bufferSize=1024 #Objects sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ## Internet,UDP # function init def init(): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #enable broadcasting mode sock.bind(('', localPort)) print("UDP server : {}:{}".format(get_ip_address(),localPort)) # function main def main(): while True: data, addr = sock.recvfrom(1024) # get data print("received message: {} from {}\n".format(data,addr)) sock.sendto("RPi received OK",addr) # write data # function get_ip_address def get_ip_address(): """get host ip address""" ip_address = ''; s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8",80)) ip_address = s.getsockname()[0] s.close() return ip_address if __name__ == '__main__': init() main()
N.B.: La función get_ip_address() implementa un método para obtener la dirección IP de la Raspberry Pi abriendo un socket temporalmente. También puede utilizar la biblioteca os con el comando ifconfig.
Anota la dirección IP y el puerto de la Raspberry Pi para poder copiarlos en el código del cliente:
- Dirección IP: 192.168.1.46
- Número de puerto: 8888
ESP32 Código de cliente UDP
En el código del cliente, vamos a conectarnos al servidor utilizando la dirección IP y el puerto anotados anteriormente (en este caso 192.168.1.46:8888).
N.B.: No olvides cambiar los valores de ssid y password para que el ESP32 se conecte a la misma red que la Raspberry Pi.
#include <WiFi.h> #include <WiFiUdp.h> WiFiUDP udp; char packetBuffer[255]; unsigned int localPort = 9999; char *serverip = "192.168.1.46"; unsigned int serverport = 8888; const char *ssid = "******"; const char *password = "********"; void setup() { Serial.begin(115200); // Connect to Wifi network. WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } udp.begin(localPort); Serial.printf("UDP Client : %s:%i \n", WiFi.localIP().toString().c_str(), localPort); } void loop() { int packetSize = udp.parsePacket(); if (packetSize) { Serial.print(" Received packet from : "); Serial.println(udp.remoteIP()); int len = udp.read(packetBuffer, 255); Serial.printf("Data : %s\n", packetBuffer); Serial.println(); } delay(500); Serial.print("[Client Connected] "); Serial.println(WiFi.localIP()); udp.beginPacket(serverip, serverport); char buf[30]; unsigned long testID = millis(); sprintf(buf, "ESP32 send millis: %lu", testID); udp.printf(buf); udp.endPacket(); }
Resultados
Cuando las dos tarjetas se conectan al WiFi, podemos ver que se intercambia información entre las dos tarjetas. Entonces es posible controlar un dispositivo conectado al cliente desde el servidor o viceversa.
N.B.: En general, las direcciones IP se asignan automáticamente. Como las direcciones se definen «duramente» en el código, es preferible configurar tus dispositivos para que tengan una dirección IP estática en lugar de dinámica. Esto le evitará tener que modificar el código cada vez que se enciendan.
Bonus: Comunicación UDP entre Raspberry Pi y dos clientes ESP32
Una vez establecida la comunicación, es posible añadir varios clientes. En este ejemplo, añadimos un cliente ESP8266
Código cliente UDP ESP8266
Es fácil transformar el código del ESP32 para adaptarlo al ESP8266 modificando el nombre de la librería Wifi. También cambiamos el valor del puerto 9696
N.B.: Cuando añada un cliente, asegúrese de que tiene un emparejamiento de direcciones de
#include <ESP8266WiFi.h> #include <WiFiUdp.h> WiFiUDP udp; char packetBuffer[255]; unsigned int localPort = 9696; char *serverip = "192.168.1.46"; unsigned int serverport = 8888; const char *ssid = "******"; const char *password = "******"; void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } udp.begin(localPort); Serial.printf("UDP Client : %s:%i \n", WiFi.localIP().toString().c_str(), localPort); } void loop() { int packetSize = udp.parsePacket(); if (packetSize) { Serial.print(" Received packet from : "); Serial.println(udp.remoteIP()); int len = udp.read(packetBuffer, 255); Serial.printf("Data : %s\n", packetBuffer); Serial.println(); } delay(500); Serial.print("[Client Connected] "); Serial.println(WiFi.localIP()); udp.beginPacket(serverip, serverport); char buf[30]; unsigned long testID = millis(); sprintf(buf, "ESP8266 send millis: %lu", testID); udp.printf(buf); udp.endPacket(); }
Resultadoss
Podemos ver que las direcciones y los valores intercambiados por ESP32 y ESP8266 son diferentes.
Aplicaciones
- Crear una red de ordenadores y/o microcontroladores para gestionar diferentes dispositivos o sensores.