Communication Protocols

ESP32 excels at connectivity. This guide covers WiFi, Bluetooth, and serial protocols (I2C, SPI, UART, ESP-NOW).

WiFi

Station Mode (Connect to Network)

#include <WiFi.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";

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

    WiFi.mode(WIFI_STA);  // Station mode
    WiFi.begin(ssid, password);

    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println();
    Serial.println("Connected!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("Signal strength (RSSI): ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dBm");
}

void loop() {
    // Check connection status
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi disconnected! Reconnecting...");
        WiFi.reconnect();
        while (WiFi.status() != WL_CONNECTED) {
            delay(500);
        }
    }
    delay(10000);
}

WiFi Connection with Timeout and Retry

#include <WiFi.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";
const int WIFI_TIMEOUT_MS = 20000;
const int WIFI_RETRY_DELAY_MS = 5000;

bool connectToWiFi() {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    unsigned long startAttemptTime = millis();

    while (WiFi.status() != WL_CONNECTED &&
           millis() - startAttemptTime < WIFI_TIMEOUT_MS) {
        delay(100);
    }

    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi connection failed!");
        return false;
    }

    Serial.printf("Connected! IP: %s\n", WiFi.localIP().toString().c_str());
    return true;
}

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

    while (!connectToWiFi()) {
        Serial.println("Retrying in 5 seconds...");
        delay(WIFI_RETRY_DELAY_MS);
    }
}

Access Point Mode (Create Network)

#include <WiFi.h>

const char* ap_ssid = "ESP32-AP";
const char* ap_password = "12345678";  // Min 8 characters

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

    WiFi.mode(WIFI_AP);
    WiFi.softAP(ap_ssid, ap_password);

    Serial.println("Access Point Started");
    Serial.print("AP IP address: ");
    Serial.println(WiFi.softAPIP());
}

void loop() {
    Serial.printf("Connected stations: %d\n", WiFi.softAPgetStationNum());
    delay(5000);
}

Dual Mode (Station + Access Point)

#include <WiFi.h>

const char* sta_ssid = "HomeNetwork";
const char* sta_password = "HomePassword";
const char* ap_ssid = "ESP32-Config";
const char* ap_password = "12345678";

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

    // Configure both modes
    WiFi.mode(WIFI_AP_STA);

    // Start AP
    WiFi.softAP(ap_ssid, ap_password);
    Serial.printf("AP started: %s\n", WiFi.softAPIP().toString().c_str());

    // Connect to station
    WiFi.begin(sta_ssid, sta_password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.printf("\nStation connected: %s\n", WiFi.localIP().toString().c_str());
}

HTTP Client

#include <WiFi.h>
#include <HTTPClient.h>

void makeHTTPRequest() {
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi not connected!");
        return;
    }

    HTTPClient http;

    http.begin("http://httpbin.org/get");
    int httpCode = http.GET();

    if (httpCode > 0) {
        Serial.printf("HTTP Response code: %d\n", httpCode);

        if (httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);
        }
    } else {
        Serial.printf("HTTP request failed: %s\n",
                      http.errorToString(httpCode).c_str());
    }

    http.end();
}

// POST request
void makeHTTPPost() {
    HTTPClient http;

    http.begin("http://httpbin.org/post");
    http.addHeader("Content-Type", "application/json");

    String jsonPayload = "{\"sensor\":\"temperature\",\"value\":25.5}";
    int httpCode = http.POST(jsonPayload);

    if (httpCode > 0) {
        String response = http.getString();
        Serial.println(response);
    }

    http.end();
}

HTTPS Client

#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>

// Root CA certificate (example for httpbin.org)
const char* rootCACertificate = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADAn\n" \
"..." \
"-----END CERTIFICATE-----\n";

void makeHTTPSRequest() {
    WiFiClientSecure *client = new WiFiClientSecure;

    if (client) {
        client->setCACert(rootCACertificate);

        HTTPClient https;

        if (https.begin(*client, "https://httpbin.org/get")) {
            int httpCode = https.GET();

            if (httpCode > 0) {
                Serial.printf("HTTPS Response: %d\n", httpCode);
                String payload = https.getString();
                Serial.println(payload);
            }

            https.end();
        }

        delete client;
    }
}

// Skip certificate verification (not recommended for production)
void makeInsecureHTTPS() {
    WiFiClientSecure *client = new WiFiClientSecure;
    client->setInsecure();  // Don't verify certificate

    HTTPClient https;
    https.begin(*client, "https://example.com");
    int httpCode = https.GET();
    // ...
    https.end();
    delete client;
}

Simple Web Server

#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);

void handleRoot() {
    String html = "<html><body>";
    html += "<h1>ESP32 Web Server</h1>";
    html += "<p>Temperature: 25.5°C</p>";
    html += "<p><a href='/led/on'>Turn LED ON</a></p>";
    html += "<p><a href='/led/off'>Turn LED OFF</a></p>";
    html += "</body></html>";

    server.send(200, "text/html", html);
}

void handleLedOn() {
    digitalWrite(2, HIGH);
    server.send(200, "text/plain", "LED is ON");
}

void handleLedOff() {
    digitalWrite(2, LOW);
    server.send(200, "text/plain", "LED is OFF");
}

void handleNotFound() {
    server.send(404, "text/plain", "Not found");
}

void setup() {
    Serial.begin(115200);
    pinMode(2, OUTPUT);

    // Connect to WiFi (see previous examples)
    WiFi.begin("ssid", "password");
    while (WiFi.status() != WL_CONNECTED) delay(500);

    // Configure routes
    server.on("/", handleRoot);
    server.on("/led/on", handleLedOn);
    server.on("/led/off", handleLedOff);
    server.onNotFound(handleNotFound);

    server.begin();
    Serial.printf("Server started at http://%s\n",
                  WiFi.localIP().toString().c_str());
}

void loop() {
    server.handleClient();
}

WebSocket Server

#include <WiFi.h>
#include <WebSocketsServer.h>

WebSocketsServer webSocket = WebSocketsServer(81);

void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
    switch (type) {
        case WStype_DISCONNECTED:
            Serial.printf("[%u] Disconnected\n", num);
            break;

        case WStype_CONNECTED:
            {
                IPAddress ip = webSocket.remoteIP(num);
                Serial.printf("[%u] Connected from %s\n", num, ip.toString().c_str());
            }
            break;

        case WStype_TEXT:
            Serial.printf("[%u] Received: %s\n", num, payload);

            // Echo back
            webSocket.sendTXT(num, "Received: " + String((char*)payload));

            // Broadcast to all clients
            webSocket.broadcastTXT("Broadcast: " + String((char*)payload));
            break;
    }
}

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

    // Connect to WiFi...

    webSocket.begin();
    webSocket.onEvent(webSocketEvent);

    Serial.println("WebSocket server started on port 81");
}

void loop() {
    webSocket.loop();
}

mDNS (Local DNS)

#include <WiFi.h>
#include <ESPmDNS.h>

void setup() {
    // Connect to WiFi...

    // Start mDNS
    if (MDNS.begin("esp32")) {
        Serial.println("mDNS responder started");
        Serial.println("Access at: http://esp32.local");

        // Advertise services
        MDNS.addService("http", "tcp", 80);
    }
}

Bluetooth

ESP32 supports both Classic Bluetooth and BLE (Bluetooth Low Energy).

Bluetooth Serial (Classic)

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Enable it in menuconfig
#endif

BluetoothSerial SerialBT;

void setup() {
    Serial.begin(115200);
    SerialBT.begin("ESP32-BT");  // Bluetooth device name
    Serial.println("Bluetooth started! Pair with 'ESP32-BT'");
}

void loop() {
    // Forward Serial to Bluetooth
    if (Serial.available()) {
        SerialBT.write(Serial.read());
    }

    // Forward Bluetooth to Serial
    if (SerialBT.available()) {
        Serial.write(SerialBT.read());
    }

    delay(20);
}

BLE Server (Peripheral)

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;

class MyServerCallbacks : public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
        deviceConnected = true;
        Serial.println("Device connected");
    }

    void onDisconnect(BLEServer* pServer) {
        deviceConnected = false;
        Serial.println("Device disconnected");
        pServer->startAdvertising();  // Restart advertising
    }
};

class MyCallbacks : public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic* pCharacteristic) {
        String value = pCharacteristic->getValue();
        if (value.length() > 0) {
            Serial.print("Received: ");
            Serial.println(value.c_str());
        }
    }
};

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

    // Initialize BLE
    BLEDevice::init("ESP32-BLE");

    // Create server
    pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyServerCallbacks());

    // Create service
    BLEService* pService = pServer->createService(SERVICE_UUID);

    // Create characteristic
    pCharacteristic = pService->createCharacteristic(
        CHARACTERISTIC_UUID,
        BLECharacteristic::PROPERTY_READ |
        BLECharacteristic::PROPERTY_WRITE |
        BLECharacteristic::PROPERTY_NOTIFY
    );

    pCharacteristic->setCallbacks(new MyCallbacks());
    pCharacteristic->addDescriptor(new BLE2902());

    // Start service
    pService->start();

    // Start advertising
    BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->setScanResponse(true);
    pAdvertising->start();

    Serial.println("BLE server started");
}

void loop() {
    if (deviceConnected) {
        // Send notification
        static int counter = 0;
        String value = String(counter++);
        pCharacteristic->setValue(value.c_str());
        pCharacteristic->notify();
        delay(1000);
    }
}

BLE Client (Central)

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEClient.h>

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

static BLEAddress* pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
        Serial.printf("Found: %s\n", advertisedDevice.toString().c_str());

        if (advertisedDevice.haveServiceUUID() &&
            advertisedDevice.isAdvertisingService(BLEUUID(SERVICE_UUID))) {
            Serial.println("Found our service!");
            BLEDevice::getScan()->stop();
            pServerAddress = new BLEAddress(advertisedDevice.getAddress());
            doConnect = true;
        }
    }
};

bool connectToServer() {
    BLEClient* pClient = BLEDevice::createClient();

    Serial.println("Connecting to server...");
    pClient->connect(*pServerAddress);

    BLERemoteService* pRemoteService = pClient->getService(BLEUUID(SERVICE_UUID));
    if (pRemoteService == nullptr) {
        Serial.println("Failed to find service");
        pClient->disconnect();
        return false;
    }

    pRemoteCharacteristic = pRemoteService->getCharacteristic(BLEUUID(CHARACTERISTIC_UUID));
    if (pRemoteCharacteristic == nullptr) {
        Serial.println("Failed to find characteristic");
        pClient->disconnect();
        return false;
    }

    Serial.println("Connected!");
    return true;
}

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

    BLEDevice::init("");

    BLEScan* pBLEScan = BLEDevice::getScan();
    pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
    pBLEScan->setActiveScan(true);
    pBLEScan->start(30);  // Scan for 30 seconds
}

void loop() {
    if (doConnect) {
        if (connectToServer()) {
            connected = true;
        }
        doConnect = false;
    }

    if (connected) {
        // Read value
        String value = pRemoteCharacteristic->readValue();
        Serial.printf("Read value: %s\n", value.c_str());
        delay(1000);
    }
}

I2C (Inter-Integrated Circuit)

Two-wire communication for sensors, displays, and more.

I2C Scanner

#include <Wire.h>

void setup() {
    Serial.begin(115200);
    Wire.begin();  // Default: SDA=21, SCL=22

    Serial.println("I2C Scanner");
    scanI2C();
}

void scanI2C() {
    byte error, address;
    int deviceCount = 0;

    Serial.println("Scanning...");

    for (address = 1; address < 127; address++) {
        Wire.beginTransmission(address);
        error = Wire.endTransmission();

        if (error == 0) {
            Serial.printf("Device found at 0x%02X\n", address);
            deviceCount++;
        }
    }

    Serial.printf("Found %d device(s)\n", deviceCount);
}

void loop() {
    delay(5000);
    scanI2C();
}

I2C with Custom Pins

#include <Wire.h>

#define SDA_PIN 16
#define SCL_PIN 17

void setup() {
    Wire.begin(SDA_PIN, SCL_PIN);
    // Or with frequency
    Wire.begin(SDA_PIN, SCL_PIN, 400000);  // 400kHz
}

I2C Reading Example (Generic)

#include <Wire.h>

#define DEVICE_ADDRESS 0x68

uint8_t readRegister(uint8_t reg) {
    Wire.beginTransmission(DEVICE_ADDRESS);
    Wire.write(reg);
    Wire.endTransmission(false);  // Repeated start

    Wire.requestFrom(DEVICE_ADDRESS, (uint8_t)1);
    return Wire.read();
}

void writeRegister(uint8_t reg, uint8_t value) {
    Wire.beginTransmission(DEVICE_ADDRESS);
    Wire.write(reg);
    Wire.write(value);
    Wire.endTransmission();
}

void readMultipleBytes(uint8_t reg, uint8_t* buffer, size_t length) {
    Wire.beginTransmission(DEVICE_ADDRESS);
    Wire.write(reg);
    Wire.endTransmission(false);

    Wire.requestFrom(DEVICE_ADDRESS, length);
    for (size_t i = 0; i < length; i++) {
        buffer[i] = Wire.read();
    }
}

Multiple I2C Buses

ESP32 has two I2C controllers:

#include <Wire.h>

TwoWire I2C_1 = TwoWire(0);  // First I2C bus
TwoWire I2C_2 = TwoWire(1);  // Second I2C bus

void setup() {
    I2C_1.begin(21, 22);  // SDA, SCL
    I2C_2.begin(16, 17);  // Different pins

    // Use like normal
    I2C_1.beginTransmission(0x68);
    I2C_2.beginTransmission(0x3C);
}

SPI (Serial Peripheral Interface)

High-speed communication for displays, SD cards, etc.

SPI Basics

#include <SPI.h>

// Default VSPI pins:
// MOSI: 23
// MISO: 19
// CLK:  18
// CS:   5 (user defined)

#define CS_PIN 5

void setup() {
    Serial.begin(115200);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);

    SPI.begin();
}

void spiTransfer(uint8_t* data, size_t length) {
    digitalWrite(CS_PIN, LOW);
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

    for (size_t i = 0; i < length; i++) {
        data[i] = SPI.transfer(data[i]);
    }

    SPI.endTransaction();
    digitalWrite(CS_PIN, HIGH);
}

uint8_t readRegister(uint8_t reg) {
    uint8_t value;

    digitalWrite(CS_PIN, LOW);
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

    SPI.transfer(reg | 0x80);  // Read flag
    value = SPI.transfer(0x00);

    SPI.endTransaction();
    digitalWrite(CS_PIN, HIGH);

    return value;
}

void writeRegister(uint8_t reg, uint8_t value) {
    digitalWrite(CS_PIN, LOW);
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

    SPI.transfer(reg & 0x7F);  // Write flag (clear MSB)
    SPI.transfer(value);

    SPI.endTransaction();
    digitalWrite(CS_PIN, HIGH);
}

SPI Modes

Mode | CPOL | CPHA | Clock Idle | Data Sample
-----|------|------|------------|-------------
  0  |  0   |  0   |    LOW     | Rising edge
  1  |  0   |  1   |    LOW     | Falling edge
  2  |  1   |  0   |    HIGH    | Falling edge
  3  |  1   |  1   |    HIGH    | Rising edge

Custom SPI Pins

#include <SPI.h>

// Custom pins
#define MOSI_PIN 13
#define MISO_PIN 12
#define CLK_PIN  14
#define CS_PIN   15

SPIClass hspi(HSPI);

void setup() {
    hspi.begin(CLK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
    pinMode(CS_PIN, OUTPUT);
}

void loop() {
    digitalWrite(CS_PIN, LOW);
    hspi.transfer(0x00);
    digitalWrite(CS_PIN, HIGH);
}

Multiple SPI Devices

#include <SPI.h>

#define CS_DEVICE_A 5
#define CS_DEVICE_B 15

void setup() {
    SPI.begin();
    pinMode(CS_DEVICE_A, OUTPUT);
    pinMode(CS_DEVICE_B, OUTPUT);
    digitalWrite(CS_DEVICE_A, HIGH);
    digitalWrite(CS_DEVICE_B, HIGH);
}

void readDeviceA() {
    digitalWrite(CS_DEVICE_A, LOW);
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
    // ... transfer
    SPI.endTransaction();
    digitalWrite(CS_DEVICE_A, HIGH);
}

void readDeviceB() {
    digitalWrite(CS_DEVICE_B, LOW);
    SPI.beginTransaction(SPISettings(4000000, LSBFIRST, SPI_MODE1));  // Different settings
    // ... transfer
    SPI.endTransaction();
    digitalWrite(CS_DEVICE_B, HIGH);
}

UART (Serial Communication)

ESP32 has three UART controllers.

Hardware Serial

// UART0: GPIO 1 (TX), GPIO 3 (RX) - Used for programming/debug
// UART1: GPIO 10 (TX), GPIO 9 (RX) - Often conflicting with flash
// UART2: GPIO 17 (TX), GPIO 16 (RX) - User available

#include <HardwareSerial.h>

HardwareSerial Serial2(2);  // UART2

void setup() {
    Serial.begin(115200);  // USB/Debug
    Serial2.begin(9600, SERIAL_8N1, 16, 17);  // RX, TX
}

void loop() {
    // Forward between USB and UART2
    if (Serial.available()) {
        Serial2.write(Serial.read());
    }
    if (Serial2.available()) {
        Serial.write(Serial2.read());
    }
}

Custom UART Pins

#include <HardwareSerial.h>

HardwareSerial mySerial(1);  // UART1

void setup() {
    // Custom pins for UART1
    mySerial.begin(9600, SERIAL_8N1, 25, 26);  // RX=25, TX=26
}

Reading GPS Data (Example)

#include <HardwareSerial.h>

HardwareSerial GPS(2);

void setup() {
    Serial.begin(115200);
    GPS.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
    if (GPS.available()) {
        String line = GPS.readStringUntil('\n');
        if (line.startsWith("$GPRMC")) {
            Serial.println(line);
            // Parse GPS data...
        }
    }
}

ESP-NOW

Peer-to-peer communication without WiFi network. Low latency, up to 250 bytes per message.

ESP-NOW Sender

#include <esp_now.h>
#include <WiFi.h>

// Receiver MAC address
uint8_t receiverMAC[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};

typedef struct {
    int id;
    float temperature;
    float humidity;
} SensorData;

SensorData dataToSend;

void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.printf("Send status: %s\n",
                  status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

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

    WiFi.mode(WIFI_STA);
    Serial.printf("Sender MAC: %s\n", WiFi.macAddress().c_str());

    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW init failed");
        return;
    }

    esp_now_register_send_cb(onDataSent);

    // Register peer
    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));
    memcpy(peerInfo.peer_addr, receiverMAC, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;

    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }

    Serial.println("ESP-NOW initialized");
}

void loop() {
    dataToSend.id = 1;
    dataToSend.temperature = 25.5;
    dataToSend.humidity = 60.2;

    esp_err_t result = esp_now_send(receiverMAC, (uint8_t*)&dataToSend, sizeof(dataToSend));

    if (result == ESP_OK) {
        Serial.println("Sent successfully");
    } else {
        Serial.println("Send error");
    }

    delay(2000);
}

ESP-NOW Receiver

#include <esp_now.h>
#include <WiFi.h>

typedef struct {
    int id;
    float temperature;
    float humidity;
} SensorData;

SensorData receivedData;

void onDataReceived(const uint8_t *mac_addr, const uint8_t *data, int len) {
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
             mac_addr[0], mac_addr[1], mac_addr[2],
             mac_addr[3], mac_addr[4], mac_addr[5]);

    Serial.printf("Received from: %s\n", macStr);

    memcpy(&receivedData, data, sizeof(receivedData));

    Serial.printf("ID: %d, Temp: %.1f, Humidity: %.1f\n",
                  receivedData.id, receivedData.temperature, receivedData.humidity);
}

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

    WiFi.mode(WIFI_STA);
    Serial.printf("Receiver MAC: %s\n", WiFi.macAddress().c_str());

    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW init failed");
        return;
    }

    esp_now_register_recv_cb(onDataReceived);

    Serial.println("ESP-NOW receiver ready");
}

void loop() {
    // Data received via callback
    delay(10);
}

Get MAC Address

Run this to find your ESP32's MAC address:

#include <WiFi.h>

void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    Serial.printf("MAC Address: %s\n", WiFi.macAddress().c_str());
}

void loop() {}

Protocol Comparison

ProtocolSpeedDistanceWiringPowerUse Case
WiFiHighLong (30m+)NoneHighInternet, cloud
BLEMedium~10mNoneLowSensors, wearables
BT ClassicMedium~10mNoneMediumAudio, serial
ESP-NOWMedium~200mNoneLowP2P, sensors
I2C400kHz1m2 wiresLowSensors, EEPROM
SPI80MHz0.3m4+ wiresLowDisplays, SD cards
UART5Mbps15m2-3 wiresLowGPS, serial devices

Next: Power Management →