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.