ESP-NOW: бездротовий пульт між двома ESP32 без роутера
Протокол ESP-NOW дозволяє платам обмінюватися короткими повідомленнями напряму з затримкою в кілька мілісекунд. Робимо кнопку-пульт і приймач зі світлодіодом.
Що таке ESP-NOW
ESP-NOW — власний протокол Espressif поверх 2.4 ГГц радіо. Плати обмінюються пакетами до 250 байт напряму за MAC-адресою, без точки доступу й без з'єднання:
- затримка — одиниці мілісекунд;
- дальність — десятки метрів у приміщенні, 100+ м на відкритому просторі;
- ідеально для пультів, датчиків на батарейках і зв'язку «багато датчиків → один шлюз».
Компоненти
- 2 × ESP32 DevKit
- Світлодіод + резистор 330 Ом (або вбудований LED на GPIO 2)
- Кнопка — підійде вбудована кнопка BOOT (GPIO 0)
Крок 1. Дізнаємося MAC приймача
Прошийте в плату-приймач код нижче — він виведе свою MAC-адресу в Serial Monitor.
Приймач (receiver)
#include <WiFi.h>
#include <esp_now.h>
typedef struct {
uint8_t pressed;
float chipTemp;
} Message;
const int LED_PIN = 2;
// Сигнатура для ядра arduino-esp32 3.x
void onReceive(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
if (len != sizeof(Message)) return;
Message msg;
memcpy(&msg, data, sizeof(msg));
digitalWrite(LED_PIN, msg.pressed ? HIGH : LOW);
const uint8_t *m = info->src_addr;
Serial.printf("From %02X:%02X:%02X:%02X:%02X:%02X pressed=%d chip=%.1f°C\n",
m[0], m[1], m[2], m[3], m[4], m[5], msg.pressed, msg.chipTemp);
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
WiFi.mode(WIFI_STA);
Serial.print("Receiver MAC: ");
Serial.println(WiFi.macAddress());
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW init failed");
return;
}
esp_now_register_recv_cb(onReceive);
}
void loop() {}
Запишіть адресу на кшталт 24:6F:28:AA:BB:CC.
Крок 2. Передавач (sender)
Підставте MAC приймача в receiverMac:
#include <WiFi.h>
#include <esp_now.h>
uint8_t receiverMac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC}; // ← ваш MAC
typedef struct {
uint8_t pressed;
float chipTemp;
} Message;
const int BUTTON_PIN = 0; // кнопка BOOT
int lastState = HIGH;
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW init failed");
return;
}
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, receiverMac, 6);
peer.channel = 0; // поточний канал
peer.encrypt = false;
if (esp_now_add_peer(&peer) != ESP_OK) {
Serial.println("Failed to add peer");
}
}
void loop() {
int state = digitalRead(BUTTON_PIN);
if (state != lastState) {
lastState = state;
Message msg = { (uint8_t)(state == LOW), temperatureRead() };
esp_err_t res = esp_now_send(receiverMac, (uint8_t *)&msg, sizeof(msg));
Serial.println(res == ESP_OK ? "sent" : "send error");
delay(30); // простий антидребезг
}
}
Перевірка
Натисніть BOOT на передавачі — світлодіод на приймачі засвітиться, а в його Serial Monitor з'являться рядки з MAC відправника і температурою чипа.
Важливі нюанси
- Структура повідомлення має бути однаковою на обох платах — інакше
lenне збігатиметься. - Канал Wi-Fi. Якщо приймач одночасно підключений до роутера, ESP-NOW працює на каналі роутера. Передавач теж має бути на ньому (виставте
peer.channelабоesp_wifi_set_channel()). - Ядро 2.x використовує іншу сигнатуру колбеку:
void onReceive(const uint8_t *mac, const uint8_t *data, int len). - Для шифрування задайте
peer.encrypt = trueта ключіesp_now_set_pmk()/peer.lmk.
Куди розвивати
- Датчик на батарейці: прокинувся → надіслав по ESP-NOW (≈50 мс) → заснув. Це в рази економніше за Wi-Fi.
- Шлюз «ESP-NOW → MQTT»: одна плата приймає дані з десятків датчиків і пересилає їх у Home Assistant.