Home / References / ESP32 Library / AsyncUDP Library
Description
The broadcastTo() method is used to send UDP broadcast packets to all devices on a specific network segment or interface. This method allows you to transmit data to multiple receivers simultaneously without needing to specify individual IP addresses. Broadcast communication is essential for device discovery protocols, network announcements, configuration distribution, and real-time data sharing across local networks.
The method internally uses the broadcast address (255.255.255.255 for IPv4) to ensure packets reach all devices within the network broadcast domain. It supports both raw byte data and string data transmission, with optional network interface specification for multi-interface devices. The broadcastTo() method is particularly useful in IoT applications where you need to announce device presence, distribute configuration updates to multiple devices, or implement discovery protocols that allow devices to find each other automatically on the network.
This page is part of the Comprehensive Guide to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
Difference Between broadcastTo() and broadcast() Methods
The AsyncUDP library provides two distinct broadcasting methods, each designed for different use cases and offering different levels of control:
broadcastTo() Method:
- Port Flexibility: Allows you to specify any destination port number for the broadcast packet, giving you complete control over where the data is sent.
- Interface Control: Provides optional network interface specification (WiFi Station, Access Point, or Ethernet), enabling targeted broadcasting on specific network interfaces.
- Independence: Can be used without prior connection or binding to a specific port, making it suitable for standalone broadcast operations.
- Syntax:
udp.broadcastTo(data, length, port, interface)– Requires explicit port specification. - Ideal for: Device discovery protocols, network announcements, cross-port communication, and multi-interface scenarios.
broadcast() Method:
- Port Dependency: Uses the UDP socket’s local port (the port you’re listening on) as the destination port for broadcast packets.
- Simplified Usage: Automatically determines the broadcast port based on your socket configuration, reducing parameter requirements.
- Connection Required: Requires the UDP socket to have a local port established through prior
listen()orconnect()operations. - Syntax:
udp.broadcast(data, length)– Port is automatically determined from socket configuration. - Ideal for: Broadcasting responses on the same port you’re listening on, peer-to-peer communication, and simplified broadcast scenarios.
Technical Implementation Difference:
Internally, the broadcast() method is actually implemented as a wrapper around broadcastTo(). When you call broadcast(data, length), the library automatically calls broadcastTo(data, length, _pcb->local_port) where _pcb->local_port is the port your UDP socket is bound to. If no local port is set (i.e., _pcb->local_port is 0), the broadcast() method will return 0 and no data will be sent.
Choosing the Right Method:
Use broadcastTo() when:
- You need to broadcast to a different port than you’re listening on
- You want to specify which network interface to use for broadcasting
- You’re implementing device discovery where different services use different ports
- You need maximum flexibility and control over broadcast parameters
- You want to broadcast without setting up a listening socket first
Use broadcast() when:
- You want to broadcast on the same port you’re listening on
- You prefer simplified syntax with fewer parameters
- You’re implementing peer-to-peer communication where all devices use the same port
- You want the convenience of automatic port determination
- Your application has already established a listening port through
listen()
Syntax and Usage
The broadcastTo() method has multiple overloaded versions:
– Broadcast Raw Data:
size_t bytes = udp.broadcastTo(data, length, port, interface)Broadcasts binary data to specified port with optional interface selection.
– Broadcast String Data:
size_t bytes = udp.broadcastTo(text, port, interface)Broadcasts null-terminated string to specified port with optional interface selection.
– Broadcast Message Object:
size_t bytes = udp.broadcastTo(message, port, interface)Broadcasts AsyncUDPMessage object to specified port with optional interface selection.
For more ESP32 development resources and tutorials, visit the All About ESP32 Resources Hub on AvantMaker.com
Arguments
- data (uint8_t*) – Pointer to the raw binary data to broadcast. The data buffer must remain valid until the broadcast operation completes.
- length (size_t) – The number of bytes to broadcast from the data buffer. Maximum size is limited by CONFIG_TCP_MSS (usually 1460 bytes).
- text (const char*) – Null-terminated string to broadcast. The method automatically calculates the string length using strlen().
- message (AsyncUDPMessage&) – Reference to an AsyncUDPMessage object containing the data to broadcast. The message object handles data buffering internally.
- port (uint16_t) – The destination port number where broadcast packets should be sent. Valid range is 1-65535.
- interface (tcpip_adapter_if_t) – Optional network interface specification. Default is TCPIP_ADAPTER_IF_MAX (all interfaces). Can be TCPIP_ADAPTER_IF_STA (WiFi Station), TCPIP_ADAPTER_IF_AP (WiFi Access Point), or TCPIP_ADAPTER_IF_ETH (Ethernet).
Return Value
The broadcastTo() method returns a size_t value indicating the number of bytes successfully sent in the broadcast packet. A return value of 0 indicates that the broadcast operation failed, which can occur due to various reasons such as network interface not being available, insufficient memory for packet allocation, or network stack errors. A non-zero return value equals the number of bytes that were successfully transmitted to the network broadcast address. The method performs internal error checking and sets the lastErr() value which can be retrieved for detailed error diagnosis. Note that a successful return value only indicates that the packet was sent to the network layer; it does not guarantee that any specific device received the broadcast packet. Broadcast packets are sent using UDP which is inherently unreliable, so there’s no delivery confirmation or acknowledgment mechanism.
Example Code
COMPLETE TWO-DEVICE TESTING SYSTEM
This example provides TWO separate code files for comprehensive broadcastTo() testing
📡 Code #1: Coordinator
Role: Network Server
Quantity: Upload to 1 ESP32
Function: Manages network
🌟 Code #2: Nodes
Role: Network Clients
Quantity: Upload to 3-5 ESP32s
Function: Join network
📋 Setup: Use both codes together to create a complete IoT network with automatic device discovery and broadcast communication
Multi-Device IoT Network Discovery and Communication System
This example demonstrates how to use the broadcastTo() method to create a comprehensive IoT network where multiple ESP32 devices can discover each other, exchange information, and coordinate activities through broadcast communication. The system implements device discovery, heartbeat monitoring, status synchronization, and command broadcasting across the network.
CODE EXAMPLE #1: NETWORK COORDINATOR (SERVER)
Device Role: Network Coordinator/Server
Purpose: Manages the entire IoT network, discovers devices, distributes commands, and monitors network health
Upload to: One ESP32 device (this will be your main coordinator)
Key Functions:
- 📢 Broadcasts network announcements using
broadcastTo() - 🔍 Discovers and registers network nodes
- 📤 Distributes commands to all devices
- 💓 Monitors device heartbeats and health
- 📊 Maintains network statistics and topology
Multi-Device Testing Setup Instructions
Required Hardware: 3-6 ESP32 development boards on the same WiFi network
Step-by-Step Testing Guide:
- Upload Coordinator Code: Upload the code below to your first ESP32 (this will be the network coordinator)
- Upload Node Code: Upload the node code (provided after the main example) to 3-5 additional ESP32 boards
- Monitor Serial Outputs: Open Serial Monitor for all devices at 115200 baud
- Verify Network Discovery: Watch as devices automatically discover each other through broadcast announcements
- Test Communication: Observe broadcast commands, status updates, and heartbeat monitoring
- Test Network Resilience: Power off/on different devices to see how the network adapts
- Monitor Statistics: Check broadcast statistics and network topology information
What You’ll See:
- Automatic device discovery through broadcast announcements
- Real-time network topology updates as devices join/leave
- Broadcast command distribution and execution
- Heartbeat monitoring and device health status
- Network statistics and performance monitoring
Testing Scenarios:
- Device Discovery: New devices automatically announce their presence to the network
- Command Broadcasting: Coordinator can send commands to all devices simultaneously
- Status Synchronization: All devices share their status with the network periodically
- Network Monitoring: Real-time monitoring of network health and device availability
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This example demonstrates how to use the broadcastTo() method to create a
* comprehensive IoT network coordinator that manages device discovery, status
* monitoring, and command distribution through UDP broadcasts. The coordinator
* broadcasts periodic announcements, collects device information, and distributes
* commands to all network nodes.
*
* How to use this example:
* Upload this code to your first ESP32 to create the network coordinator. Then
* upload the node code (provided below) to additional ESP32 devices. The coordinator
* will automatically discover nodes, monitor their status, and coordinate network
* activities through broadcast communication.
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com, your premier destination for all things
* DIY, IoT, Smart Home, and STEM projects. We are dedicated
* to empowering makers, learners, and enthusiasts with
* the resources they need to bring their innovative ideas to life.
*/
#include <WiFi.h>
#include <AsyncUDP.h>
#include <ArduinoJson.h>
// WiFi credentials
const char* ssid = "your_SSID"; // Replace with your Wi-Fi SSID
const char* password = "your_PASSWORD"; // Replace with your Wi-Fi password
// Network configuration
const uint16_t DISCOVERY_PORT = 8888;
const uint16_t COMMAND_PORT = 8889;
const uint16_t STATUS_PORT = 8890;
const uint16_t HEARTBEAT_PORT = 8891;
// Coordinator configuration
struct CoordinatorConfig {
String deviceId;
String coordinatorName;
unsigned long systemStartTime = 0;
unsigned long totalBroadcastsSent = 0;
unsigned long totalPacketsReceived = 0;
unsigned long discoveryInterval = 30000; // Send discovery broadcasts every 30 seconds
unsigned long statusRequestInterval = 60000; // Request status from all devices every minute
unsigned long heartbeatInterval = 15000; // Check heartbeats every 15 seconds
unsigned long lastDiscoveryBroadcast = 0;
unsigned long lastStatusRequest = 0;
unsigned long lastHeartbeatCheck = 0;
} config;
// Network device management
struct NetworkDevice {
String deviceId;
String deviceName;
String deviceType;
IPAddress ipAddress;
unsigned long lastSeen;
unsigned long lastHeartbeat;
bool isActive;
int signalStrength;
String status;
unsigned long uptime;
float batteryLevel;
};
// Device tracking
const int MAX_DEVICES = 20;
NetworkDevice devices[MAX_DEVICES];
int deviceCount = 0;
// UDP instances for different communication channels
AsyncUDP discoveryUDP;
AsyncUDP commandUDP;
AsyncUDP statusUDP;
AsyncUDP heartbeatUDP;
// System statistics
struct SystemStats {
unsigned long networksDiscovered = 0;
unsigned long commandsSent = 0;
unsigned long statusUpdatesReceived = 0;
unsigned long heartbeatsReceived = 0;
unsigned long devicesOffline = 0;
} stats;
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 IoT Network Coordinator...");
// Generate unique coordinator ID
config.deviceId = "COORDINATOR_" + String((uint32_t)ESP.getEfuseMac(), HEX);
config.coordinatorName = "IoT Network Coordinator";
Serial.print("Coordinator ID: ");
Serial.println(config.deviceId);
Serial.print("Coordinator Name: ");
Serial.println(config.coordinatorName);
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("✅ WiFi connected successfully!");
Serial.print("Coordinator IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
config.systemStartTime = millis();
// Initialize UDP listeners
initializeUDPListeners();
// Send initial network announcement
broadcastNetworkAnnouncement();
Serial.println("🌐 IoT Network Coordinator is now active!");
}
void initializeUDPListeners() {
Serial.println("🔧 === Initializing UDP Communication Channels ===");
// Discovery channel listener
if (discoveryUDP.listen(DISCOVERY_PORT)) {
Serial.print("✅ Discovery channel listening on port ");
Serial.println(DISCOVERY_PORT);
discoveryUDP.onPacket([](AsyncUDPPacket packet) {
handleDiscoveryPacket(packet);
});
} else {
Serial.print("❌ Failed to initialize discovery channel on port ");
Serial.println(DISCOVERY_PORT);
}
// Command channel listener
if (commandUDP.listen(COMMAND_PORT)) {
Serial.print("✅ Command channel listening on port ");
Serial.println(COMMAND_PORT);
commandUDP.onPacket([](AsyncUDPPacket packet) {
handleCommandResponse(packet);
});
} else {
Serial.print("❌ Failed to initialize command channel on port ");
Serial.println(COMMAND_PORT);
}
// Status channel listener
if (statusUDP.listen(STATUS_PORT)) {
Serial.print("✅ Status channel listening on port ");
Serial.println(STATUS_PORT);
statusUDP.onPacket([](AsyncUDPPacket packet) {
handleStatusUpdate(packet);
});
} else {
Serial.print("❌ Failed to initialize status channel on port ");
Serial.println(STATUS_PORT);
}
// Heartbeat channel listener
if (heartbeatUDP.listen(HEARTBEAT_PORT)) {
Serial.print("✅ Heartbeat channel listening on port ");
Serial.println(HEARTBEAT_PORT);
heartbeatUDP.onPacket([](AsyncUDPPacket packet) {
handleHeartbeat(packet);
});
} else {
Serial.print("❌ Failed to initialize heartbeat channel on port ");
Serial.println(HEARTBEAT_PORT);
}
Serial.println("=== UDP Channel Initialization Complete ===");
}
void broadcastNetworkAnnouncement() {
DynamicJsonDocument doc(512);
doc["type"] = "coordinator_announcement";
doc["coordinator_id"] = config.deviceId;
doc["coordinator_name"] = config.coordinatorName;
doc["coordinator_ip"] = WiFi.localIP().toString();
doc["network_name"] = ssid;
doc["discovery_port"] = DISCOVERY_PORT;
doc["command_port"] = COMMAND_PORT;
doc["status_port"] = STATUS_PORT;
doc["heartbeat_port"] = HEARTBEAT_PORT;
doc["timestamp"] = millis();
doc["uptime"] = (millis() - config.systemStartTime) / 1000;
String message;
serializeJson(doc, message);
// Use broadcastTo() method to send announcement
size_t bytesSent = discoveryUDP.broadcastTo(message.c_str(), DISCOVERY_PORT);
if (bytesSent > 0) {
config.totalBroadcastsSent++;
stats.networksDiscovered++;
Serial.println("📡 === Network Announcement Broadcast ===");
Serial.print("Message sent: ");
Serial.print(bytesSent);
Serial.println(" bytes");
Serial.print("Content: ");
Serial.println(message);
Serial.println("==========================================");
} else {
Serial.println("❌ Failed to send network announcement");
}
}
void handleDiscoveryPacket(AsyncUDPPacket packet) {
config.totalPacketsReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
Serial.println("📥 === Discovery Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Message: ");
Serial.println(message);
// Parse JSON message
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, message);
if (error) {
Serial.print("❌ JSON parsing failed: ");
Serial.println(error.c_str());
return;
}
String messageType = doc["type"].as<String>();
if (messageType == "device_announcement") {
handleDeviceAnnouncement(doc, packet.remoteIP());
} else if (messageType == "device_discovery_request") {
respondToDiscoveryRequest(packet.remoteIP());
}
Serial.println("=== End Discovery Packet Processing ===");
}
void handleDeviceAnnouncement(DynamicJsonDocument& doc, IPAddress deviceIP) {
String deviceId = doc["device_id"].as<String>();
// Don't register ourselves
if (deviceId == config.deviceId) {
return;
}
Serial.println("🆕 === New Device Announcement ===");
Serial.print("Device ID: ");
Serial.println(deviceId);
// Find existing device or create new entry
int deviceIndex = findDeviceIndex(deviceId);
if (deviceIndex == -1 && deviceCount < MAX_DEVICES) {
deviceIndex = deviceCount++;
Serial.println("Creating new device entry");
} else if (deviceIndex != -1) {
Serial.println("Updating existing device entry");
} else {
Serial.println("⚠️ Device registry full, cannot add new device");
return;
}
// Update device information
devices[deviceIndex].deviceId = deviceId;
devices[deviceIndex].deviceName = doc["device_name"].as<String>();
devices[deviceIndex].deviceType = doc["device_type"].as<String>();
devices[deviceIndex].ipAddress = deviceIP;
devices[deviceIndex].lastSeen = millis();
devices[deviceIndex].lastHeartbeat = millis();
devices[deviceIndex].isActive = true;
devices[deviceIndex].signalStrength = doc["signal_strength"].as<int>();
devices[deviceIndex].uptime = doc["uptime"].as<unsigned long>();
devices[deviceIndex].batteryLevel = doc["battery_level"].as<float>();
devices[deviceIndex].status = "Active";
Serial.print("Device Name: ");
Serial.println(devices[deviceIndex].deviceName);
Serial.print("Device Type: ");
Serial.println(devices[deviceIndex].deviceType);
Serial.print("IP Address: ");
Serial.println(devices[deviceIndex].ipAddress);
Serial.println("=== Device Registration Complete ===");
// Send welcome message to new device
sendWelcomeMessage(deviceIndex);
}
void sendWelcomeMessage(int deviceIndex) {
DynamicJsonDocument doc(512);
doc["type"] = "welcome_message";
doc["coordinator_id"] = config.deviceId;
doc["coordinator_name"] = config.coordinatorName;
doc["device_id"] = devices[deviceIndex].deviceId;
doc["network_devices"] = deviceCount;
doc["network_uptime"] = (millis() - config.systemStartTime) / 1000;
doc["instructions"] = "Send status updates to port " + String(STATUS_PORT);
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Broadcast welcome message
size_t bytesSent = commandUDP.broadcastTo(message.c_str(), COMMAND_PORT);
if (bytesSent > 0) {
config.totalBroadcastsSent++;
Serial.println("📤 Welcome message sent to new device");
}
}
void broadcastStatusRequest() {
DynamicJsonDocument doc(256);
doc["type"] = "status_request";
doc["coordinator_id"] = config.deviceId;
doc["request_id"] = random(10000, 99999);
doc["timestamp"] = millis();
doc["response_port"] = STATUS_PORT;
String message;
serializeJson(doc, message);
// Use broadcastTo() method to request status from all devices
size_t bytesSent = commandUDP.broadcastTo(message.c_str(), COMMAND_PORT);
if (bytesSent > 0) {
config.totalBroadcastsSent++;
stats.commandsSent++;
Serial.println("📤 Status request broadcast sent to all devices");
Serial.print("Message: ");
Serial.println(message);
} else {
Serial.println("❌ Failed to send status request broadcast");
}
}
void handleStatusUpdate(AsyncUDPPacket packet) {
config.totalPacketsReceived++;
stats.statusUpdatesReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
Serial.println("📊 === Status Update Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.println(":");
Serial.print(packet.remotePort());
Serial.print("Content: ");
Serial.println(message);
// Parse status update
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, message);
if (!error) {
String deviceId = doc["device_id"].as<String>();
int deviceIndex = findDeviceIndex(deviceId);
if (deviceIndex != -1) {
devices[deviceIndex].status = doc["status"].as<String>();
devices[deviceIndex].uptime = doc["uptime"].as<unsigned long>();
devices[deviceIndex].batteryLevel = doc["battery_level"].as<float>();
devices[deviceIndex].signalStrength = doc["signal_strength"].as<int>();
devices[deviceIndex].lastSeen = millis();
Serial.print("Updated status for device: ");
Serial.println(devices[deviceIndex].deviceName);
}
}
Serial.println("=== End Status Update Processing ===");
}
void handleHeartbeat(AsyncUDPPacket packet) {
config.totalPacketsReceived++;
stats.heartbeatsReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Parse heartbeat
DynamicJsonDocument doc(256);
DeserializationError error = deserializeJson(doc, message);
if (!error) {
String deviceId = doc["device_id"].as<String>();
int deviceIndex = findDeviceIndex(deviceId);
if (deviceIndex != -1) {
devices[deviceIndex].lastHeartbeat = millis();
devices[deviceIndex].isActive = true;
Serial.print("💓 Heartbeat received from: ");
Serial.println(devices[deviceIndex].deviceName);
}
}
}
void checkDeviceHeartbeats() {
unsigned long currentTime = millis();
unsigned long heartbeatTimeout = 45000; // 45 seconds timeout
for (int i = 0; i < deviceCount; i++) {
if (devices[i].isActive && (currentTime - devices[i].lastHeartbeat) > heartbeatTimeout) {
devices[i].isActive = false;
devices[i].status = "Offline";
stats.devicesOffline++;
Serial.println("⚠️ === Device Heartbeat Timeout ===");
Serial.print("Device: ");
Serial.print(devices[i].deviceName);
Serial.print(" (");
Serial.print(devices[i].deviceId);
Serial.println(")");
Serial.print("Last heartbeat: ");
Serial.print((currentTime - devices[i].lastHeartbeat) / 1000);
Serial.println(" seconds ago");
Serial.println("Device marked as offline");
}
}
}
int findDeviceIndex(const String& deviceId) {
for (int i = 0; i < deviceCount; i++) {
if (devices[i].deviceId == deviceId) {
return i;
}
}
return -1;
}
void respondToDiscoveryRequest(IPAddress requesterIP) {
DynamicJsonDocument doc(512);
doc["type"] = "discovery_response";
doc["coordinator_id"] = config.deviceId;
doc["coordinator_name"] = config.coordinatorName;
doc["coordinator_ip"] = WiFi.localIP().toString();
doc["network_devices"] = deviceCount;
doc["network_uptime"] = (millis() - config.systemStartTime) / 1000;
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Broadcast discovery response
size_t bytesSent = discoveryUDP.broadcastTo(message.c_str(), DISCOVERY_PORT);
if (bytesSent > 0) {
config.totalBroadcastsSent++;
Serial.print("📤 Discovery response sent (");
Serial.print(bytesSent);
Serial.println(" bytes)");
}
}
void broadcastNetworkCommand(const String& command) {
DynamicJsonDocument doc(256);
doc["type"] = "network_command";
doc["coordinator_id"] = config.deviceId;
doc["command"] = command;
doc["command_id"] = random(10000, 99999);
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Use broadcastTo() method to send command to all devices
size_t bytesSent = commandUDP.broadcastTo(message.c_str(), COMMAND_PORT);
if (bytesSent > 0) {
config.totalBroadcastsSent++;
stats.commandsSent++;
Serial.println("📢 === Network Command Broadcast ===");
Serial.print("Command: ");
Serial.println(command);
Serial.print("Bytes sent: ");
Serial.println(bytesSent);
Serial.println("========================================");
} else {
Serial.println("❌ Failed to broadcast network command");
}
}
void handleCommandResponse(AsyncUDPPacket packet) {
config.totalPacketsReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
Serial.println("📥 === Command Response Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Response: ");
Serial.println(message);
Serial.println("===================================");
}
void printNetworkStatus() {
Serial.println("🌐 === NETWORK STATUS REPORT ===");
Serial.print("Coordinator: ");
Serial.print(config.coordinatorName);
Serial.print(" (");
Serial.print(config.deviceId);
Serial.println(")");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Network Uptime: ");
Serial.print((millis() - config.systemStartTime) / 1000);
Serial.println(" seconds");
Serial.print("Total Devices: ");
Serial.println(deviceCount);
Serial.print("Active Devices: ");
int activeCount = 0;
for (int i = 0; i < deviceCount; i++) {
if (devices[i].isActive) activeCount++;
}
Serial.println(activeCount);
Serial.println("=== DEVICE LIST ===");
for (int i = 0; i < deviceCount; i++) {
Serial.print(i + 1);
Serial.print(". ");
Serial.print(devices[i].deviceName);
Serial.print(" (");
Serial.print(devices[i].deviceId);
Serial.println(")");
Serial.print(" IP: ");
Serial.print(devices[i].ipAddress);
Serial.print(" | Status: ");
Serial.print(devices[i].status);
Serial.print(" | Signal: ");
Serial.print(devices[i].signalStrength);
Serial.println(" dBm");
Serial.print(" Battery: ");
Serial.print(devices[i].batteryLevel);
Serial.print("% | Uptime: ");
Serial.print(devices[i].uptime);
Serial.println(" seconds");
}
Serial.println("=== STATISTICS ===");
Serial.print("Broadcasts Sent: ");
Serial.println(config.totalBroadcastsSent);
Serial.print("Packets Received: ");
Serial.println(config.totalPacketsReceived);
Serial.print("Commands Sent: ");
Serial.println(stats.commandsSent);
Serial.print("Status Updates: ");
Serial.println(stats.statusUpdatesReceived);
Serial.print("Heartbeats: ");
Serial.println(stats.heartbeatsReceived);
Serial.println("===========================");
}
void loop() {
unsigned long currentTime = millis();
// Send periodic network announcements
if (currentTime - config.lastDiscoveryBroadcast >= config.discoveryInterval) {
config.lastDiscoveryBroadcast = currentTime;
broadcastNetworkAnnouncement();
}
// Request status updates from all devices
if (currentTime - config.lastStatusRequest >= config.statusRequestInterval) {
config.lastStatusRequest = currentTime;
broadcastStatusRequest();
}
// Check device heartbeats
if (currentTime - config.lastHeartbeatCheck >= config.heartbeatInterval) {
config.lastHeartbeatCheck = currentTime;
checkDeviceHeartbeats();
}
// Print network status every 2 minutes
static unsigned long lastStatusPrint = 0;
if (currentTime - lastStatusPrint >= 120000) {
lastStatusPrint = currentTime;
printNetworkStatus();
}
// Send test commands periodically
static unsigned long lastCommandBroadcast = 0;
if (currentTime - lastCommandBroadcast >= 90000) { // Every 90 seconds
lastCommandBroadcast = currentTime;
String commands[] = {"sync_time", "report_sensors", "update_config", "ping_all"};
String command = commands[random(0, 4)];
broadcastNetworkCommand(command);
}
// Monitor WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi connection lost! Attempting reconnection...");
WiFi.reconnect();
delay(5000);
}
// Small delay to prevent overwhelming the system
delay(100);
}CODE EXAMPLE #2: NETWORK NODE (CLIENT)
Device Role: Network Node/Client Device
Purpose: Participates in the IoT network as a node device that communicates with the coordinator
Upload to: 3-5 additional ESP32 devices (these will be your network nodes)
Key Functions:
- 🔍 Automatically discovers the network coordinator
- 📢 Announces device presence using
broadcastTo() - 🎮 Processes and responds to network commands
- 📊 Sends status updates and sensor data
- 💓 Transmits heartbeat signals for health monitoring
- 🔄 Handles network reconnection and resilience
IoT Network Node Device Code
Upload this code to 3-5 additional ESP32 devices to create network nodes that will automatically discover the coordinator, announce their presence, and participate in the broadcast communication network. Each node responds to broadcast commands and sends periodic status updates.
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This is the node code for creating IoT network devices that communicate with
* the coordinator through UDP broadcasts. Upload this code to multiple ESP32
* devices to create a comprehensive IoT network with automatic device discovery,
* status monitoring, and command execution.
*
* Testing Instructions:
* 1. Upload the coordinator code to one ESP32
* 2. Upload this node code to 3-5 additional ESP32 devices
* 3. All devices will automatically discover each other through broadcasts
* 4. Monitor all Serial outputs to see the network communication
* 5. Nodes will respond to coordinator commands and send status updates
*/
#include <WiFi.h>
#include <AsyncUDP.h>
#include <ArduinoJson.h>
// WiFi credentials (must match coordinator)
const char* ssid = "your_SSID"; // Replace with your Wi-Fi SSID
const char* password = "your_PASSWORD"; // Replace with your Wi-Fi password
// Network configuration (must match coordinator)
const uint16_t DISCOVERY_PORT = 8888;
const uint16_t COMMAND_PORT = 8889;
const uint16_t STATUS_PORT = 8890;
const uint16_t HEARTBEAT_PORT = 8891;
// Node configuration
struct NodeConfig {
String deviceId;
String deviceName;
String deviceType;
String coordinatorId = "";
IPAddress coordinatorIP;
unsigned long systemStartTime = 0;
unsigned long totalBroadcastsSent = 0;
unsigned long totalPacketsReceived = 0;
unsigned long announcementInterval = 45000; // Announce every 45 seconds
unsigned long statusUpdateInterval = 75000; // Send status every 75 seconds
unsigned long heartbeatInterval = 20000; // Send heartbeat every 20 seconds
unsigned long lastAnnouncement = 0;
unsigned long lastStatusUpdate = 0;
unsigned long lastHeartbeat = 0;
bool coordinatorFound = false;
} nodeConfig;
// UDP instances
AsyncUDP discoveryUDP;
AsyncUDP commandUDP;
AsyncUDP statusUDP;
AsyncUDP heartbeatUDP;
// Node status and sensor simulation
struct NodeStatus {
String currentStatus = "Initializing";
float batteryLevel = 85.0;
int signalStrength = -45;
unsigned long commandsProcessed = 0;
unsigned long statusUpdatesSent = 0;
unsigned long heartbeatsSent = 0;
float temperature = 22.5;
float humidity = 65.0;
bool sensorActive = true;
} nodeStatus;
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 IoT Network Node...");
// Generate unique node ID and name
uint32_t chipId = (uint32_t)ESP.getEfuseMac();
nodeConfig.deviceId = "NODE_" + String(chipId, HEX);
nodeConfig.deviceName = "IoT Node " + String(chipId & 0xFFFF, HEX);
nodeConfig.deviceType = "Sensor Node";
Serial.print("Node ID: ");
Serial.println(nodeConfig.deviceId);
Serial.print("Node Name: ");
Serial.println(nodeConfig.deviceName);
Serial.print("Node Type: ");
Serial.println(nodeConfig.deviceType);
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("✅ WiFi connected successfully!");
Serial.print("Node IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
nodeConfig.systemStartTime = millis();
nodeStatus.currentStatus = "Active";
nodeStatus.signalStrength = WiFi.RSSI();
// Initialize UDP listeners
initializeUDPListeners();
// Send initial device announcement
delay(2000); // Wait a bit before announcing
broadcastDeviceAnnouncement();
Serial.println("🌟 IoT Network Node is now active!");
}
void initializeUDPListeners() {
Serial.println("🔧 === Initializing UDP Communication Channels ===");
// Discovery channel listener
if (discoveryUDP.listen(DISCOVERY_PORT)) {
Serial.print("✅ Discovery channel listening on port ");
Serial.println(DISCOVERY_PORT);
discoveryUDP.onPacket([](AsyncUDPPacket packet) {
handleDiscoveryPacket(packet);
});
} else {
Serial.print("❌ Failed to initialize discovery channel on port ");
Serial.println(DISCOVERY_PORT);
}
// Command channel listener
if (commandUDP.listen(COMMAND_PORT)) {
Serial.print("✅ Command channel listening on port ");
Serial.println(COMMAND_PORT);
commandUDP.onPacket([](AsyncUDPPacket packet) {
handleNetworkCommand(packet);
});
} else {
Serial.print("❌ Failed to initialize command channel on port ");
Serial.println(COMMAND_PORT);
}
// Status channel (for coordinator responses)
if (statusUDP.listen(STATUS_PORT)) {
Serial.print("✅ Status channel listening on port ");
Serial.println(STATUS_PORT);
statusUDP.onPacket([](AsyncUDPPacket packet) {
handleStatusResponse(packet);
});
}
// Heartbeat channel (for coordinator monitoring)
if (heartbeatUDP.listen(HEARTBEAT_PORT)) {
Serial.print("✅ Heartbeat channel listening on port ");
Serial.println(HEARTBEAT_PORT);
}
Serial.println("=== UDP Channel Initialization Complete ===");
}
void broadcastDeviceAnnouncement() {
updateSensorData(); // Update sensor readings
DynamicJsonDocument doc(512);
doc["type"] = "device_announcement";
doc["device_id"] = nodeConfig.deviceId;
doc["device_name"] = nodeConfig.deviceName;
doc["device_type"] = nodeConfig.deviceType;
doc["device_ip"] = WiFi.localIP().toString();
doc["signal_strength"] = nodeStatus.signalStrength;
doc["battery_level"] = nodeStatus.batteryLevel;
doc["uptime"] = (millis() - nodeConfig.systemStartTime) / 1000;
doc["status"] = nodeStatus.currentStatus;
doc["temperature"] = nodeStatus.temperature;
doc["humidity"] = nodeStatus.humidity;
doc["sensor_active"] = nodeStatus.sensorActive;
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Use broadcastTo() method to announce device presence
size_t bytesSent = discoveryUDP.broadcastTo(message.c_str(), DISCOVERY_PORT);
if (bytesSent > 0) {
nodeConfig.totalBroadcastsSent++;
Serial.println("📡 === Device Announcement Broadcast ===");
Serial.print("Message sent: ");
Serial.print(bytesSent);
Serial.println(" bytes");
Serial.print("Content: ");
Serial.println(message);
Serial.println("==========================================");
} else {
Serial.println("❌ Failed to send device announcement");
}
}
void handleDiscoveryPacket(AsyncUDPPacket packet) {
nodeConfig.totalPacketsReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
Serial.println("📥 === Discovery Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
// Parse JSON message
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, message);
if (error) {
Serial.print("❌ JSON parsing failed: ");
Serial.println(error.c_str());
return;
}
String messageType = doc["type"].as<String>();
if (messageType == "coordinator_announcement") {
handleCoordinatorAnnouncement(doc, packet.remoteIP());
} else if (messageType == "discovery_response") {
handleDiscoveryResponse(doc, packet.remoteIP());
}
Serial.println("=== End Discovery Packet Processing ===");
}
void handleCoordinatorAnnouncement(DynamicJsonDocument& doc, IPAddress coordinatorIP) {
String coordinatorId = doc["coordinator_id"].as<String>();
String coordinatorName = doc["coordinator_name"].as<String>();
Serial.println("🎯 === Coordinator Found ===");
Serial.print("Coordinator ID: ");
Serial.println(coordinatorId);
Serial.print("Coordinator Name: ");
Serial.println(coordinatorName);
Serial.print("Coordinator IP: ");
Serial.println(coordinatorIP);
// Register coordinator information
nodeConfig.coordinatorId = coordinatorId;
nodeConfig.coordinatorIP = coordinatorIP;
nodeConfig.coordinatorFound = true;
Serial.println("✅ Coordinator registered successfully");
Serial.println("============================");
// Send discovery request to get network information
sendDiscoveryRequest();
}
void sendDiscoveryRequest() {
DynamicJsonDocument doc(256);
doc["type"] = "device_discovery_request";
doc["device_id"] = nodeConfig.deviceId;
doc["device_name"] = nodeConfig.deviceName;
doc["requesting_info"] = true;
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Use broadcastTo() method to request network information
size_t bytesSent = discoveryUDP.broadcastTo(message.c_str(), DISCOVERY_PORT);
if (bytesSent > 0) {
nodeConfig.totalBroadcastsSent++;
Serial.println("📤 Discovery request sent to coordinator");
}
}
void handleDiscoveryResponse(DynamicJsonDocument& doc, IPAddress responseIP) {
Serial.println("📋 === Discovery Response Received ===");
Serial.print("Network Devices: ");
Serial.println(doc["network_devices"].as<int>());
Serial.print("Network Uptime: ");
Serial.print(doc["network_uptime"].as<unsigned long>());
Serial.println(" seconds");
Serial.println("=====================================");
}
void handleNetworkCommand(AsyncUDPPacket packet) {
nodeConfig.totalPacketsReceived++;
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
Serial.println("🎮 === Network Command Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Command: ");
Serial.println(message);
// Parse command
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, message);
if (!error) {
String messageType = doc["type"].as<String>();
if (messageType == "network_command") {
processNetworkCommand(doc);
} else if (messageType == "status_request") {
sendStatusUpdate();
} else if (messageType == "welcome_message") {
handleWelcomeMessage(doc);
}
}
Serial.println("=== End Command Processing ===");
}
void processNetworkCommand(DynamicJsonDocument& doc) {
String command = doc["command"].as<String>();
String coordinatorId = doc["coordinator_id"].as<String>();
int commandId = doc["command_id"].as<int>();
nodeStatus.commandsProcessed++;
Serial.println("⚡ === Processing Network Command ===");
Serial.print("Command: ");
Serial.println(command);
Serial.print("Command ID: ");
Serial.println(commandId);
Serial.print("From Coordinator: ");
Serial.println(coordinatorId);
String response = "Unknown command";
if (command == "sync_time") {
response = "Time synchronized to " + String(millis());
} else if (command == "report_sensors") {
updateSensorData();
response = "Temp: " + String(nodeStatus.temperature) + "°C, Humidity: " + String(nodeStatus.humidity) + "%";
} else if (command == "update_config") {
response = "Configuration updated successfully";
} else if (command == "ping_all") {
response = "Ping response from " + nodeConfig.deviceName;
}
// Send command response
sendCommandResponse(commandId, command, response);
Serial.print("Response: ");
Serial.println(response);
Serial.println("================================");
}
void sendCommandResponse(int commandId, const String& command, const String& response) {
DynamicJsonDocument doc(512);
doc["type"] = "command_response";
doc["device_id"] = nodeConfig.deviceId;
doc["device_name"] = nodeConfig.deviceName;
doc["command_id"] = commandId;
doc["command"] = command;
doc["response"] = response;
doc["timestamp"] = millis();
doc["execution_time"] = random(10, 200); // Simulate execution time
String message;
serializeJson(doc, message);
// Use broadcastTo() method to send response
size_t bytesSent = commandUDP.broadcastTo(message.c_str(), COMMAND_PORT);
if (bytesSent > 0) {
nodeConfig.totalBroadcastsSent++;
Serial.print("📤 Command response sent (");
Serial.print(bytesSent);
Serial.println(" bytes)");
}
}
void sendStatusUpdate() {
updateSensorData();
DynamicJsonDocument doc(512);
doc["type"] = "status_update";
doc["device_id"] = nodeConfig.deviceId;
doc["device_name"] = nodeConfig.deviceName;
doc["device_type"] = nodeConfig.deviceType;
doc["status"] = nodeStatus.currentStatus;
doc["uptime"] = (millis() - nodeConfig.systemStartTime) / 1000;
doc["battery_level"] = nodeStatus.batteryLevel;
doc["signal_strength"] = WiFi.RSSI();
doc["temperature"] = nodeStatus.temperature;
doc["humidity"] = nodeStatus.humidity;
doc["sensor_active"] = nodeStatus.sensorActive;
doc["commands_processed"] = nodeStatus.commandsProcessed;
doc["free_heap"] = ESP.getFreeHeap();
doc["timestamp"] = millis();
String message;
serializeJson(doc, message);
// Use broadcastTo() method to send status update
size_t bytesSent = statusUDP.broadcastTo(message.c_str(), STATUS_PORT);
if (bytesSent > 0) {
nodeConfig.totalBroadcastsSent++;
nodeStatus.statusUpdatesSent++;
Serial.println("📊 === Status Update Broadcast ===");
Serial.print("Message sent: ");
Serial.print(bytesSent);
Serial.println(" bytes");
Serial.println("=================================");
} else {
Serial.println("❌ Failed to send status update");
}
}
void sendHeartbeat() {
DynamicJsonDocument doc(256);
doc["type"] = "heartbeat";
doc["device_id"] = nodeConfig.deviceId;
doc["device_name"] = nodeConfig.deviceName;
doc["timestamp"] = millis();
doc["sequence"] = nodeStatus.heartbeatsSent + 1;
doc["signal_strength"] = WiFi.RSSI();
doc["battery_level"] = nodeStatus.batteryLevel;
String message;
serializeJson(doc, message);
// Use broadcastTo() method to send heartbeat
size_t bytesSent = heartbeatUDP.broadcastTo(message.c_str(), HEARTBEAT_PORT);
if (bytesSent > 0) {
nodeConfig.totalBroadcastsSent++;
nodeStatus.heartbeatsSent++;
Serial.print("💓 Heartbeat sent (");
Serial.print(nodeStatus.heartbeatsSent);
Serial.println(")");
}
}
void handleWelcomeMessage(DynamicJsonDocument& doc) {
Serial.println("🎉 === Welcome Message Received ===");
Serial.print("Coordinator: ");
Serial.println(doc["coordinator_name"].as<String>());
Serial.print("Network Devices: ");
Serial.println(doc["network_devices"].as<int>());
Serial.print("Instructions: ");
Serial.println(doc["instructions"].as<String>());
Serial.println("Welcome to the IoT network!");
Serial.println("==================================");
}
void handleStatusResponse(AsyncUDPPacket packet) {
// Handle any status-related responses from coordinator
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
Serial.println("📨 Status response received from coordinator");
Serial.print("Response: ");
Serial.println(message);
}
void updateSensorData() {
// Simulate realistic sensor data changes
unsigned long currentTime = millis();
// Temperature simulation (20-30°C with slow variation)
nodeStatus.temperature = 25.0 + sin(currentTime / 60000.0) * 3.0 + (random(-50, 50) / 100.0);
// Humidity simulation (40-80% with slow variation)
nodeStatus.humidity = 60.0 + cos(currentTime / 45000.0) * 15.0 + (random(-100, 100) / 100.0);
// Battery level simulation (slowly decreasing)
nodeStatus.batteryLevel = max(20.0f, nodeStatus.batteryLevel - 0.001f);
// Signal strength update
nodeStatus.signalStrength = WiFi.RSSI();
// Sensor status (occasionally go offline)
if (random(0, 1000) < 5) { // 0.5% chance
nodeStatus.sensorActive = !nodeStatus.sensorActive;
nodeStatus.currentStatus = nodeStatus.sensorActive ? "Active" : "Sensor Offline";
}
}
void printNodeStatus() {
Serial.println("🌟 === NODE STATUS REPORT ===");
Serial.print("Node: ");
Serial.print(nodeConfig.deviceName);
Serial.print(" (");
Serial.print(nodeConfig.deviceId);
Serial.println(")");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Status: ");
Serial.println(nodeStatus.currentStatus);
Serial.print("Uptime: ");
Serial.print((millis() - nodeConfig.systemStartTime) / 1000);
Serial.println(" seconds");
Serial.print("Coordinator Found: ");
Serial.println(nodeConfig.coordinatorFound ? "Yes" : "No");
if (nodeConfig.coordinatorFound) {
Serial.print("Coordinator IP: ");
Serial.println(nodeConfig.coordinatorIP);
}
Serial.println("=== SENSOR DATA ===");
Serial.print("Temperature: ");
Serial.print(nodeStatus.temperature);
Serial.println("°C");
Serial.print("Humidity: ");
Serial.print(nodeStatus.humidity);
Serial.println("%");
Serial.print("Battery Level: ");
Serial.print(nodeStatus.batteryLevel);
Serial.println("%");
Serial.print("Signal Strength: ");
Serial.print(nodeStatus.signalStrength);
Serial.println(" dBm");
Serial.print("Sensor Active: ");
Serial.println(nodeStatus.sensorActive ? "Yes" : "No");
Serial.println("=== COMMUNICATION STATS ===");
Serial.print("Broadcasts Sent: ");
Serial.println(nodeConfig.totalBroadcastsSent);
Serial.print("Packets Received: ");
Serial.println(nodeConfig.totalPacketsReceived);
Serial.print("Commands Processed: ");
Serial.println(nodeStatus.commandsProcessed);
Serial.print("Status Updates Sent: ");
Serial.println(nodeStatus.statusUpdatesSent);
Serial.print("Heartbeats Sent: ");
Serial.println(nodeStatus.heartbeatsSent);
Serial.print("Free Heap: ");
Serial.print(ESP.getFreeHeap());
Serial.println(" bytes");
Serial.println("============================");
}
void loop() {
unsigned long currentTime = millis();
// Send periodic device announcements
if (currentTime - nodeConfig.lastAnnouncement >= nodeConfig.announcementInterval) {
nodeConfig.lastAnnouncement = currentTime;
broadcastDeviceAnnouncement();
}
// Send periodic status updates
if (currentTime - nodeConfig.lastStatusUpdate >= nodeConfig.statusUpdateInterval) {
nodeConfig.lastStatusUpdate = currentTime;
sendStatusUpdate();
}
// Send periodic heartbeats
if (currentTime - nodeConfig.lastHeartbeat >= nodeConfig.heartbeatInterval) {
nodeConfig.lastHeartbeat = currentTime;
sendHeartbeat();
}
// Print node status every 90 seconds
static unsigned long lastStatusPrint = 0;
if (currentTime - lastStatusPrint >= 90000) {
lastStatusPrint = currentTime;
printNodeStatus();
}
// Monitor WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi connection lost! Attempting reconnection...");
nodeStatus.currentStatus = "WiFi Reconnecting";
WiFi.reconnect();
delay(5000);
if (WiFi.status() == WL_CONNECTED) {
nodeStatus.currentStatus = "Active";
Serial.println("✅ WiFi reconnected successfully");
}
}
// Small delay to prevent overwhelming the system
delay(100);
}Expected Output and Testing Results
On the Coordinator Device, you should see:
- Periodic network announcements using
broadcastTo() - Device discovery and registration messages
- Status request broadcasts and responses
- Heartbeat monitoring and device health tracking
- Network topology updates and statistics
On the Node Devices, you should see:
- Automatic coordinator discovery through broadcast listening
- Periodic device announcements using
broadcastTo() - Command processing and response broadcasting
- Status updates and heartbeat transmissions
- Network communication statistics
Key Testing Points:
- Broadcast Functionality: Verify that
broadcastTo()successfully sends data to all devices on the network - Device Discovery: Confirm that nodes can discover the coordinator through broadcast announcements
- Command Distribution: Test that commands sent via
broadcastTo()reach all nodes simultaneously - Network Resilience: Check network recovery when devices are powered off/on or lose connectivity
- Performance Monitoring: Monitor broadcast success rates and timing to ensure reliable communication
- Interface Specification: Test with different network interfaces if available (STA, AP, Ethernet)
For more ESP32 development resources and tutorials, visit AvantMaker.com
ESP32 Library Index
- ESP32 WiFi Library
- ESP32 WiFiClient Library
- ESP32 HTTPClient Library
- ESP32 WiFiClientSecure Library
- ESP32 WebServer Library
- ESP32 AsyncUDP Librarry
- Connection Management
- Data Transimission
- Broadcast Multicast
- Network Information
- Which ESP32 Boards are Recommended for Learners
- How to Copy Codes from AvantMaker.com
- What is SPIFFS and how to upload files to it?
- What is LIttleFS and how to upload files to it?
Ready to experiment and explore more about ESP32? Visit our website’s All About ESP32 Resources Hub, packed with tutorials, guides, and tools to inspire your maker journey. Experiment, explore, and elevate your skills with everything you need to master this powerful microcontroller platform!