☀️Siang
ESP32 & ESP8266

ESP-NOW: Komunikasi Nirkabel Antar ESP32

TOKEN

Pelajari cara ESP32 berkomunikasi langsung satu sama lain tanpa router WiFi menggunakan protokol ESP-NOW — dari dasar hingga proyek jaringan sensor nirkabel

Artikel: Esp32 Espnow Artikel: Esp32 Espnow


1. Apa Itu ESP-NOW?

ESP-NOW adalah protokol komunikasi nirkabel yang dikembangkan oleh Espressif Systems, dirancang khusus untuk memungkinkan perangkat ESP32 dan ESP8266 berkomunikasi secara langsung (peer-to-peer) tanpa memerlukan koneksi WiFi tradisional ke router atau access point.

Protokol ini bekerja pada frekuensi 2.4 GHz menggunakan teknologi yang sama dengan WiFi (IEEE 802.11), tetapi dengan pendekatan yang jauh lebih ringan. ESP-NOW menghilangkan kebutuhan akan DHCP, TCP/IP stack, dan overhead jaringan WiFi biasa, sehingga menghasilkan latensi yang sangat rendah dan konsumsi daya yang minimal.

Diagram: Perbandingan WiFi Tradisional vs ESP-NOW
Perbandingan WiFi Tradisional vs ESP-NOW

⚡ ESP-NOW

Direct

Direct

Direct

ESP32 Node A

ESP32 Node B

ESP32 Node C

📡 WiFi Tradisional

WiFi

WiFi

ESP32 Node A

Router / AP

ESP32 Node B

Karakteristik Utama ESP-NOW

Parameter Spesifikasi
Frekuesi2.4 GHz (ISM Band)
Maksimum Payload250 byte per paket
Peer Maksimum20 perangkat terdaftar
Latensi~2 milidetik
Jarak Efektif~200m (open air), ~30m (indoor)
EnkripsiAES-128 (opsional, 6 peer terenkripsi)
Kecepatan Data1 Mbps (PHY rate)
KompatibilitasESP32, ESP8266, ESP32-S2, ESP32-S3, ESP32-C3
Koneksi WiFiBisa dijalankan bersamaan dengan WiFi STA
💡 Tips

ESP-NOW sangat cocok untuk proyek yang membutuhkan komunikasi cepat antar ESP32 tanpa infrastruktur jaringan. Misalnya: remote control drone, jaringan sensor pertanian, sistem notifikasi rumah, dan robot swarm. Bahkan, ESP-NOW bisa dijalankan bersamaan dengan WiFi STA, sehingga ESP32 bisa meneruskan data ke internet.

⚡
ESP-NOW
Peer-to-Peer
  • ✅ Tanpa Router
  • ✅ Latensi ~2ms
  • ✅ Sangat Hemat Daya
  • ✅ Payload 250 byte
  • ✅ Setup Instan
  • ❌ Range Terbatas
  • ❌ Tidak ada IP/TCP
Cepat & Ringan
📶
WiFi TCP/IP
Client-Server
  • ❌ Perlu Router
  • ❌ Latensi ~10-50ms
  • ❌ Konsumsi Daya Tinggi
  • ✅ Payload Tak Terbatas
  • ❌ Setup Kompleks
  • ✅ Range Lebih Jauh
  • ✅ Kompatibel HTTP/MQTT
Universal
📡
LoRa
Long Range
  • ✅ Tanpa Router
  • ❌ Latensi Tinggi
  • ✅ Sangat Hemat Daya
  • ❌ Payload ~50 byte
  • ❌ Perlu Modul Tambahan
  • ✅ Range 10+ km
  • ❌ Butuh LoRa Module
Jarak Jauh


2. Setup Peer ESP-NOW

Sebelum ESP32 dapat saling berkomunikasi via ESP-NOW, setiap perangkat harus mendaftarkan peer (perangkat tujuan) menggunakan MAC address-nya. Proses ini disebut pairing atau peer registration.

Langkah 1: Mendapatkan MAC Address ESP32

Setiap ESP32 memiliki MAC address unik 6-byte. Untuk mengetahuinya, upload kode berikut:

flowchart TB
    Send["esp_now_send()"] -->|"MAC + Data"| Recv["ESP-NOW Protocol"]
    Recv --> CB["onReceive() Callback"]
    CB --> Parse["Parse Struct"]
    Parse --> Process["Process Data"]
    Process --> Act["Aksi: LED, Motor, dll"]

    style Send fill:#0f2a1f,stroke:#3ecf8e,stroke-width:1.5px
    style Recv fill:#0f1d3a,stroke:#60a5fa,stroke-width:1.5px
    style CB fill:#2a1f0a,stroke:#f59e0b,stroke-width:1.5px
    style Act fill:#2a0f1e,stroke:#f472b6

Program Pengirim (Sender)

Diagram

ESP-NOW

📄 Data Plaintext

AES-128\nEncrypt\n(LMK+PMK)

🔒 Ciphertext

AES-128\nDecrypt\n(LMK+PMK)

📄 Data Plaintext

flowchart TB
    GW["🌐 Gateway Node"]
    
    GW --> N1["Node 1"]
    GW --> N2["Node 2"]
    GW --> N3["Node 3"]
    
    N1 <-->|"Relay"| N2
    N2 <-->|"Relay"| N3
    N1 <-->|"Direct"| N3
    
    style GW fill:#2a1f0a,stroke:#f59e0b,stroke-width:2px
    style N1 fill:#0f2a1f,stroke:#3ecf8e
    style N2 fill:#0f1d3a,stroke:#60a5fa
    style N3 fill:#1a0f2e,stroke:#a78bfa
flowchart TB
    subgraph nodes["📡 Sensor Nodes"]
        N1["Node 1\nDHT11"] 
        N2["Node 2\nBMP280"]
        N3["Node 3\nLDR"]
    end
    
    nodes -->|"ESP-NOW"| GW["Gateway ESP32"]
    GW -->|"WiFi"| MQTT["MQTT Broker\n(Mosquitto)"]
    MQTT --> DB["InfluxDB"]
    DB --> Grafana["📊 Grafana\nDashboard"]

    style nodes fill:#0f2a1f,stroke:#3ecf8e,stroke-width:2px
    style GW fill:#2a1f0a,stroke:#f59e0b,stroke-width:2px
    style MQTT fill:#0f1d3a,stroke:#60a5fa
    style DB fill:#1a0f2e,stroke:#a78bfa
    style Grafana fill:#2a0f1e,stroke:#f472b6,stroke-width:2px

Komponen yang Dibutuhkan

Program Node Sensor

C++ — node_sensor.ino

// ==================================================
// Proyek WSN: Node Sensor dengan ESP-NOW
// Kirim data suhu & kelembaban ke gateway
// BeebaneLabs - https://beebanelabs.pages.dev
// ==================================================

#include "esp_now.h"
#include "WiFi.h"
#include "DHT.h"

// === KONFIGURASI NODE ===
#define NODE_ID        1         // Ubah: 1, 2, atau 3
#define NODE_NAME      "Ruang Tamu"  // Nama lokasi sensor
#define DHT_PIN        4         // GPIO sensor DHT
#define DHT_TYPE       DHT11
#define LED_PIN        2         // LED indikator
#define INTERVAL_KIRIM 15000     // Kirim setiap 15 detik

// MAC Address Gateway (GANTI DENGAN YANG BENAR!)
uint8_t gatewayMAC[] = {0xA4, 0xCF, 0x12, 0xE8, 0x45, 0xA0};

// === Struct Data ===
typedef struct struct_wsn_data {
  uint8_t node_id;
  char node_name[16];
  float suhu;
  float kelembaban;
  float heat_index;
  int8_t wifi_rssi;
  uint32_t uptime;
  uint32_t packet_num;
} struct_wsn_data;

struct_wsn_data dataSensor;
DHT dht(DHT_PIN, DHT_TYPE);

// Statistik
uint32_t totalKirim = 0;
uint32_t totalBerhasil = 0;
unsigned long waktuTerakhir = 0;

void kedipLED(int kali, int delayMs) {
  for (int i = 0; i < kali; i++) {
    digitalWrite(LED_PIN, HIGH);
    delay(delayMs);
    digitalWrite(LED_PIN, LOW);
    delay(delayMs);
  }
}

void onSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  if (status == ESP_NOW_SEND_SUCCESS) {
    totalBerhasil++;
    kedipLED(1, 100);
  }
  float pdr = totalKirim > 0 ?
    (float)totalBerhasil / totalKirim * 100.0 : 0;
  Serial.printf("[SEND #%lu] %s | PDR: %.1f%%\n",
    totalKirim,
    status == ESP_NOW_SEND_SUCCESS ? "OK" : "GAGAL",
    pdr);
}

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

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  if (esp_now_init() != ESP_OK) {
    Serial.println("[FATAL] ESP-NOW init gagal!");
    while (true) { kedipLED(5, 100); delay(1000); }
  }

  esp_now_register_send_cb(onSent);

  esp_now_peer_info_t peerInfo = {};
  memcpy(peerInfo.peer_addr, gatewayMAC, 6);
  peerInfo.channel = 1;
  peerInfo.encrypt = false;

  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("[FATAL] Gagal daftar gateway!");
    while (true) { kedipLED(10, 50); delay(1000); }
  }

  strcpy(dataSensor.node_name, NODE_NAME);
  dataSensor.node_id = NODE_ID;

  Serial.println("╔═══════════════════════════════════════╗");
  Serial.printf( "║  WSN Node #%d: %-18s ║\n", NODE_ID, NODE_NAME);
  Serial.println("║  BeebaneLabs ESP-NOW Sensor Node     ║");
  Serial.println("╚═══════════════════════════════════════╝");
  kedipLED(3, 200);
}

void loop() {
  unsigned long sekarang = millis();

  if (sekarang - waktuTerakhir >= INTERVAL_KIRIM) {
    waktuTerakhir = sekarang;
    totalKirim++;

    // Baca sensor
    dataSensor.suhu = dht.readTemperature();
    dataSensor.kelembaban = dht.readHumidity();
    dataSensor.uptime = sekarang / 1000;
    dataSensor.packet_num = totalKirim;
    dataSensor.wifi_rssi = 0;  // Placeholder

    // Validasi
    if (isnan(dataSensor.suhu)) {
      dataSensor.suhu = -99.0;
      dataSensor.kelembaban = -99.0;
    }

    dataSensor.heat_index = dht.computeHeatIndex(
      dataSensor.suhu, dataSensor.kelembaban, false);

    // Kirim ke gateway
    esp_err_t result = esp_now_send(
      gatewayMAC,
      (uint8_t *) &dataSensor,
      sizeof(dataSensor)
    );

    Serial.printf("[%lu] %s | %.1f°C | %.1f%% | HI: %.1f°C\n",
      totalKirim, NODE_NAME, dataSensor.suhu,
      dataSensor.kelembaban, dataSensor.heat_index);
  }
}

Program Gateway (Penerima + MQTT)

C++ — gateway_wsn.ino

// ==================================================
// Proyek WSN: Gateway ESP-NOW -> MQTT
// Terima data dari semua node, kirim ke MQTT
// BeebaneLabs - https://beebanelabs.pages.dev
// ==================================================

#include "esp_now.h"
#include "WiFi.h"
#include "PubSubClient.h"

// === WiFi Config ===
const char* WIFI_SSID = "NamaWiFiAnda";
const char* WIFI_PASS = "PasswordWiFi";

// === MQTT Config ===
const char* MQTT_SERVER = "test.mosquitto.org";
const int   MQTT_PORT   = 1883;
const char* MQTT_TOPIC  = "wsn/gateway/data";
const char* CLIENT_ID   = "wsn_gateway_01";

// === Struct (sama dengan node) ===
typedef struct struct_wsn_data {
  uint8_t node_id;
  char node_name[16];
  float suhu;
  float kelembaban;
  float heat_index;
  int8_t wifi_rssi;
  uint32_t uptime;
  uint32_t packet_num;
} struct_wsn_data;

WiFiClient espClient;
PubSubClient mqtt(espClient);

// Buffer untuk data dari multiple node
struct_wsn_data nodeData[10];  // Max 10 node
bool nodeOnline[10] = {false};

void setupWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("WiFi: Connecting");
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (++attempts > 40) {
      Serial.println(" GAGAL!");
      ESP.restart();
    }
  }
  Serial.printf(" OK! IP: %s\n", WiFi.localIP().toString().c_str());
}

void hubungkanMQTT() {
  while (!mqtt.connected()) {
    Serial.print("MQTT: Connecting...");
    if (mqtt.connect(CLIENT_ID)) {
      Serial.println(" OK!");
    } else {
      Serial.printf(" FAIL (rc=%d)\n", mqtt.state());
      delay(3000);
    }
  }
}

void onReceive(const uint8_t *mac_addr, const uint8_t *data, int len) {
  if (len != sizeof(struct_wsn_data)) {
    Serial.printf("[WARN] Ukuran data tidak sesuai: %d\n", len);
    return;
  }

  struct_wsn_data rxData;
  memcpy(&rxData, data, sizeof(rxData));

  // Simpan data
  if (rxData.node_id < 10) {
    nodeData[rxData.node_id] = rxData;
    nodeOnline[rxData.node_id] = true;
  }

  // Format MAC
  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("[RX] Node %d (%s) | %.1f°C | %.1f%% | #%lu\n",
    rxData.node_id, rxData.node_name, rxData.suhu,
    rxData.kelembaban, rxData.packet_num);

  // Kirim ke MQTT
  if (mqtt.connected()) {
    char payload[256];
    snprintf(payload, sizeof(payload),
      "{\"node_id\":%d,\"node_name\":\"%s\","
      "\"suhu\":%.1f,\"kelembaban\":%.1f,"
      "\"heat_index\":%.1f,\"uptime\":%lu,"
      "\"packet\":%lu,\"mac\":\"%s\"}",
      rxData.node_id, rxData.node_name,
      rxData.suhu, rxData.kelembaban,
      rxData.heat_index, rxData.uptime,
      rxData.packet_num, macStr);

    // Publish ke topik per-node
    char topic[64];
    snprintf(topic, sizeof(topic), "wsn/node/%d/data", rxData.node_id);

    if (mqtt.publish(topic, payload)) {
      Serial.printf("[MQTT] Published ke %s\n", topic);
    } else {
      Serial.println("[MQTT] Gagal publish!");
    }

    // Juga publish ke topik utama
    mqtt.publish(MQTT_TOPIC, payload);
  }
}

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

  Serial.println("╔═══════════════════════════════════════╗");
  Serial.println("║  WSN Gateway - ESP-NOW -> MQTT       ║");
  Serial.println("║  BeebaneLabs                          ║");
  Serial.println("╚═══════════════════════════════════════╝");

  setupWiFi();

  mqtt.setServer(MQTT_SERVER, MQTT_PORT);
  mqtt.setBufferSize(512);
  hubungkanMQTT();

  // Inisialisasi ESP-NOW (setelah WiFi)
  if (esp_now_init() != ESP_OK) {
    Serial.println("[FATAL] ESP-NOW init gagal!");
    ESP.restart();
  }

  esp_now_register_recv_cb(onReceive);

  Serial.println("[OK] Gateway siap menerima data dari node sensor!");
}

void loop() {
  if (!mqtt.connected()) {
    hubungkanMQTT();
  }
  mqtt.loop();

  // Status check setiap 30 detik
  static unsigned long lastStatus = 0;
  if (millis() - lastStatus > 30000) {
    lastStatus = millis();
    Serial.println("═══════════════════════════════════");
    Serial.println("       STATUS NODE AKTIF          ");
    for (int i = 0; i < 10; i++) {
      if (nodeOnline[i]) {
        Serial.printf("  Node %d: %-14s | %.1f°C | %.1f%%\n",
          nodeData[i].node_id, nodeData[i].node_name,
          nodeData[i].suhu, nodeData[i].kelembaban);
      }
    }
    Serial.printf("  Heap bebas: %lu bytes\n", ESP.getFreeHeap());
    Serial.println("═══════════════════════════════════");
  }
}
Output Serial Monitor (Gateway): ╔═══════════════════════════════════════╗ ║ WSN Gateway - ESP-NOW -> MQTT ║ ╚═══════════════════════════════════════╝ WiFi: Connecting... OK! IP: 192.168.1.100 MQTT: Connecting... OK! [OK] Gateway siap menerima data dari node sensor! [RX] Node 1 (Ruang Tamu) | 28.5°C | 72.0% | #1 [MQTT] Published ke wsn/node/1/data [RX] Node 2 (Gudang) | 31.2°C | 80.5% | #1 [MQTT] Published ke wsn/node/2/data [RX] Node 3 (Kebun) | 29.8°C | 65.3% | #1 [MQTT] Published ke wsn/node/3/data
💡 Tips Pengembangan

Untuk produksi, tambahkan fitur: 1) Deep sleep pada node sensor untuk menghemat baterai, 2) Auto-discovery node baru, 3) Dashboard Grafana untuk visualisasi, 4) Alert Telegram saat suhu melewati threshold, 5) OTA update firmware via ESP-NOW.



9. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang ESP-NOW:

Pertanyaan 1: Berapa maksimum payload (data) yang bisa dikirim dalam satu paket ESP-NOW?

a) 128 byte
b) 250 byte
c) 512 byte
d) 1024 byte

Pertanyaan 2: Untuk mengirim data ke semua perangkat ESP-NOW dalam range (broadcast), MAC address apa yang digunakan?

a) 00:00:00:00:00:00
b) FF:FF:FF:FF:FF:FF
c) AA:BB:CC:DD:EE:FF
d) ESP-NOW tidak mendukung broadcast

Pertanyaan 3: Berapa maksimum peer terenkripsi yang bisa didaftarkan pada satu ESP32?

a) 4 peer
b) 6 peer
c) 10 peer
d) 20 peer

Pertanyaan 4: Apa yang WAJIB dilakukan di KEDUA ESP32 agar komunikasi ESP-NOW unicast berhasil?

a) Menggunakan SSID WiFi yang sama
b) Saling mendaftarkan MAC address sebagai peer
c) Menginstal library MQTT yang sama
d) Menggunakan sensor yang identik

Pertanyaan 5: Keunggulan utama ESP-NOW dibanding WiFi TCP/IP biasa adalah...

a) Payload tidak terbatas dan bisa mengirim file besar
b) Bisa terhubung ke internet langsung tanpa router
c) Latensi sangat rendah dan tidak perlu router WiFi
d) Mendukung komunikasi jarak 10+ km

← Sebelumnya Panduan Lengkap ESP32 Selanjutnya → Artikel Lainnya
🔍 Zoom
100%
🎨 Tema