Neste tutorial, veremos como fazer com que um Raspberry Pi e um ESP32 se comuniquem usando o protocolo UDP. Quando os dispositivos estão ligados à mesma rede WiFi, podem comunicar de forma muito simples através da troca de pacotes de dados utilizando o protocolo UDP. Como tanto o Raspberry Pi quanto o ESP32 têm conetividade WiFi integrada, é bastante simples configurar um protocolo UDP entre os dois.
Neste exemplo, o Raspberry Pi actuará como servidor e o ESP32 como cliente.
N.B.: Este tutorial pode ser facilmente transposto para um ESP8266 (código de cliente bónus no final do artigo).
Hardware
- Computador
 - Raspberry Pi
 - NodeMCU ESP32 x1 ou superior (ou ESP8266)
 - Cabo USB A macho
 
Código do servidor Raspberry Pi
Para comunicar utilizando o protocolo UDP, vamos simplesmente criar o servidor udp, que será capaz de ler e escrever na porta localPort. A biblioteca socket é utilizada para abrir uma ligação entre dois dispositivos.
O construtor do socket espera dois parâmetros, a família de endereços (neste caso, endereços Internet) e o tipo de socket (neste caso, UDP).
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ## Internet,UDP
O socket deve ser ligado a uma porta na máquina sock.bind((hostname, localPort)) Colocar um carácter vazio no lugar do hostname (equivalente a 0.0.0.0) permite que o socket seja ligado a todas as interfaces locais.
#!/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.: A função get_ip_address() implementa um método para obter o endereço IP do Raspberry Pi abrindo um socket temporariamente. Também é possível usar a biblioteca os com o comando ifconfig.
Anote o endereço IP e a porta do Raspberry Pi para que possa copiá-los para o código do cliente:
- Endereço IP: 192.168.1.46
 - Número do porto: 8888
 
Código do cliente UDP do ESP32
No código do cliente, vamos ligar-nos ao servidor utilizando o endereço IP e a porta anteriormente indicados (neste caso, 192.168.1.46:8888).
Nota: Não se esqueça de alterar os valores ssid e password para que o ESP32 se ligue à mesma rede que o 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
Quando as duas placas se ligam ao WiFi, podemos ver que há uma troca de informações entre as duas placas. É então possível controlar um dispositivo ligado ao cliente a partir do servidor ou vice-versa.


N.B.: Os endereços IP são geralmente atribuídos automaticamente. Como os endereços são definidos de forma “rígida” no código, é preferível configurar os seus dispositivos de modo a que tenham um endereço IP estático e não dinâmico. Deste modo, não é necessário modificar o código de cada vez que o aparelho é ligado.
Bónus: Comunicação UDP entre o Raspberry Pi e dois clientes ESP32
Uma vez estabelecida a comunicação, é possível adicionar vários clientes. Neste exemplo, adicionamos um cliente ESP8266
Código de cliente UDP ESP8266
É fácil transformar o código do ESP32 para o adaptar ao ESP8266, modificando o nome da biblioteca Wifi. Também alteramos o valor da porta 9696
Nota: Quando adicionar um cliente, certifique-se de que este tem um emparelhamento de endereços 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 os endereços e os valores trocados pelo ESP32 e pelo ESP8266 são diferentes.


Aplicações
- Crear una red de ordenadores y/o microcontroladores para gestionar diferentes dispositivos o sensores.