Language: EN

esp8266-protocolo-udp

How to communicate an ESP8266 or ESP32 via UDP protocol

We continue with the posts about ESP8266 and ESP32 seeing how to establish a connection using UDP protocol as an alternative focused on the speed of communication.

We will refer to the ESP8266, but the same code is compatible for the ESP32, adjusting the name of the libraries. At the end you have the code for both the ESP8266 and the ESP32.

We have seen several posts about ways to communicate the ESP8266 with the client. We have seen the web forms as a simple (and somewhat outdated) solution, and the more modern connections Ajax, the websockets, and the asynchronous websockets.

All these solutions work using HTTP over TCP. But sometimes, we forget that UDP communications also exist. In a very summarized way, we remember that UDP (Universal Datagram Protocol) communications do not require the packets necessary to create the connection and error checking.

In a UDP communication the server sends packets without waiting for an acknowledgment from the client. If a packet is lost, the client cannot request it to be resent. Therefore, TCP is useful for applications that require reliability in communication. While UDP is useful for fast transmissions, even faster than a Websocket.

And in the case of a microprocessor like the ESP8266, UDP communication fits in many cases. In addition, UDP communications represent a lower load for the server since it avoids a good part of the required packets.

For example, if we are sending an animation to a series of LEDs, or the position control of a robot. In these cases of “almost continuous” communication, I don’t care so much about the acknowledgment, but about the speed. If a packet is lost, it will be immediately replaced by the next one.

Code Example

Fortunately, implementing UDP communication on the ESP8266 is very simple thanks to the ‘WiFiUDP.h’ library. Let’s see it with an example.

First, the main loop of the program looks like this.

We will see that the only relevant points are that we have included the necessary files, and the functions ‘ConnectUDP()’ and ‘GetUDP_Packet()’ that we will see below.

We also have commented out the function ‘SendUDP_Packet(“abcde”)’ which would illustrate sending a String via UDP. We won’t use it in this example, but it’s there.

#include <ESP8266WiFi.h>
#include <WiFiUDP.h>

#include "config.h"  // Replace with your network data
#include "UDP.hpp"
#include "ESP8266_Utils.hpp"
#include "ESP8266_Utils_UDP.hpp"

void setup() 
{
  Serial.begin(115200);

  ConnectWiFi_STA();
  ConnectUDP();
}

void loop() 
{
  GetUDP_Packet();
  
  //SendUDP_Packet("abcde");
}

On the other hand, we have the file ‘UDP.hpp’, in which we have put all the functions related to the UDP of our program.

In this file, we have instantiated a ‘WiFiUDP’ object, the ports on which the connection will work, and defined the ‘ProcessPacket(String response)’ function that collects the response we want to give to a UDP request.

// UDP variables
WiFiUDP UDP;

unsigned int localPort = 8888;
unsigned int remotePort = 8889;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

void ProcessPacket(String response)
{
   Serial.println(response);
}

Finally, we have the file ‘ESP8266_Utils_UDP.hpp’ in which, following the philosophy of this series of posts, we have defined a series of common functions that we can reuse between programs.

Here we have the ‘ConnectUDP()’ function that establishes the UDP connection, the ‘SendUDP_ACK()’ functions that sends an acknowledgment, ‘SendUDP_Packet(String content)’ that sends a String via UDP, and the ‘GetUDP_Packet(bool sendACK = true)’ function that receives a UDP packet and processes it with the function we have defined in the previous file.

boolean ConnectUDP() {
  Serial.println();
  Serial.println("Starting UDP");

  // in UDP error, block execution
  if (UDP.begin(localPort) != 1) 
  {
    Serial.println("Connection failed");
    while (true) { delay(1000); } 
  }

  Serial.println("UDP successful");
}

void SendUDP_ACK()
{
  UDP.beginPacket(UDP.remoteIP(), remotePort);
  UDP.write("ACK");
  UDP.endPacket();
}

void SendUDP_Packet(String content)
{
  UDP.beginPacket(UDP.remoteIP(), remotePort);
  UDP.write(content.c_str());
  UDP.endPacket();
}

void GetUDP_Packet(bool sendACK = true)
{
  int packetSize = UDP.parsePacket();
  if (packetSize)
  {
    // read the packet into packetBufffer
    UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);

    Serial.println();
    Serial.print("Received packet of size ");
    Serial.print(packetSize);
    Serial.print(" from ");
    Serial.print(UDP.remoteIP());
    Serial.print(":");
    Serial.println(UDP.remotePort());
    Serial.print("Payload: ");
    Serial.write((uint8_t*)packetBuffer, (size_t)packetSize);
    Serial.println();
    ProcessPacket(String(packetBuffer));

    //// send a reply, to the IP address and port that sent us the packet we received
    if(sendACK) SendUDP_ACK();
  }
  delay(10);
}

We upload everything to our ESP8266, and let’s test our UDP communication. For this, we have two small Python scripts available.

The ‘recieveUDP.py’ script that receives a UDP packet and displays it on the screen.

import socket

UDP_PORT = 8889

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', UDP_PORT))

while True:
  data, addr = sock.recvfrom(1024)
  print("received message:")
  print(data.decode('utf-8'))  

The ‘sendUDP.py’ file that sends an example packet via UDP.

import socket

UDP_IP = '192.168.43.237'
UDP_PORT = 8888
UDP_PAYLOAD = 'abcdef'

def yes_or_no(question):
    reply = str(input(question)).lower().strip()
    if reply[0] == 'y':
        return 0
    elif reply[0] == 'n':
        return 1
    else:
        return yes_or_no("Please Enter (y/n) ")
    
while True:
  try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.sendto(bytes(UDP_PAYLOAD, "utf-8"), (UDP_IP, UDP_PORT))    
    sock.close()
    print("UDP target IP:", UDP_IP)
    print("UDP target port:", UDP_PORT)
    print("message:", UDP_PAYLOAD)
    if(yes_or_no('Send again (y/n): ')):
      break
  except:
    pass

Result

First, we launch ‘recieveUDP.py’, which remains listening, and then ‘sendUDP.py’. We see in the console that the packet is sent correctly.

arduino-esp8266-udp-send

In the serial port of Arduino we can check that, indeed, the ESP8266 receives the packet.

arduino-esp8266-udp-serial-port

Finally, since in the receive function of the ESP8266 we have indicated that we want it to send an ACK signal, we see that the Python script receives the acknowledgment message.

arduino-esp8266-udp-ack

Everything works correctly! Easy, very useful, and often forgotten, UDP connections are another way to communicate a client with the ESP8266.

Of course, instead of a simple String with “abced”, we will normally work with a JSON file that contains the information we want, as we saw in this post.

In fact, in the next post we will start using JSON files in the ESP8266 to consume a REST API. See you soon!

Download the code

All the code in this post is available for download on Github.

github-full

Version for ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Version for ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples