ESP-NOW
bezdrátová komunikace
Kromě standardní komunikace pomocí WiFi a Bluetooth implementoval Esprressif jednoduchý komunikační protokol ESP-NOW. Využívá stejný hardware jako WiFi (2,4 GHz), ale je podstatně jednodušší, má menší režii, tedy i spotřebu. Hodí se tedy pro přenos menšího množství dat mezi zařízeními s mikrokontrolery ESP.
K čemu to je?
Vše začalo tím, že jsem pro robota potřeboval realizovat dálkové ovládání.
U předchozího robota používám jako řídicí procesor STM32 a k němu připojené
dálkové ovládání (přijímač) z RC autíčka. Nechtělo se mi kupovat další dálkové
ovládání a místa v robotovi také není nikdy nazbyt.
Sáhl jsem tedy po ESP32 (se kterým už nějaké zkušenosti mám). Už jsem zkoušel
realizovat dálkové řízení přes wifi. Funguje to, ale buď je potřeba wifi síť, nebo
esp musí jet v režimu AP. Jako ovladač jde použít mobil (tablet), ale je to takové
neohrabané.
Proto jsem začal zkoumat esp-now s tím, že bych si ovladač udělal svůj.
Informačních zdrojů a příkladů je na internetu nepřeberně, ale z mého
pohledu (jako obvykle), vše zbytečně složité pro počáteční pochopení, jak to
celé funguje.
Postupně jsem se tím, trošku prokousal a zde prezentuji své výsledky. Je to
maximálně zjednodušené (aby to pochopil každý láma), bez nároku na technickou
přesnost. Cílem je funkční dálkové ovládání (ne dokonalé ovládnutí této technologie).
Dále bych upozornil, že v sdk od Espressif se podpora ESP-NOW dost mění. Protože
používám poměrně starou verzi sdk (razím stále heslo, když to funguje, tak na to
nesahej), možná příklady s použitím novější verze budou potřeba trochu upravit.
Příklady jsou jen příklady a jsou psány, co nejjednodušeji, aby byla zřejmá
funkčnost bez ošetření všech chyb.
První komunikace
Nejjednodušší je jednosměrná komunikace mezi dvěma esp mikrokontrolery. Jeden
vysílá a druhý přijímá. V nejjednodušší variantě vysílač používá tzv.
broadcast (posílá všem posluchačům) a každý přijímač v dosahu tato data dostává.
Komunikace tedy není nijak směrovaná ani zabezpečená.
Zdrojový kód vysílače:
Adresná jednosměrná komunikace
Mírné vylepšení je tom, že vysílací strana nepoužívá broadcast, ale
vysílání je určeno jen pro přijímač se zadanou MAC adresou.
Výhodou je, že případné další přijímače si těchto dat nevšímají.
Druhým benefiten je, že vysílač se dozví, zda byla jeho zpráva doručena.
Přijímač po přijetí adresné zprávy automaticky potvrdí její přijetí.
Tím vysílací strana ví, zda byla data doručena.
Zdrojový kód vysílače:
Zdrojový kód přijímače:
Adresná obousměrná komunikace
Pokud potřebujeme předávat data oběma směry, tak doplníme chybějící části
kódu z předchozího příkladu, tj. ve výsledku máme na obou stranách stejný kód,
kromě cílové MAC adresy.
Zdrojový kód vysílače:
Zdrojový kód přijímače:
Automatické "párování"
Přechozí příklad už má jen jeden nedostatek, je nutné znát MAC adresu/y
daného zařízení. Pokud realizujeme komunikaci mezi dvěma zařízeními, celkem
to nevadí. Ale pokud potřebujeme zaměňovat komunikační zařízení, např. různé
přijímače dálkového ovládání s jedním vysílačem, pak je to nepříjemné.
V ukázce je realizováno automatické "napárování" zařízení po zapnutí. Kód
je připraven i pro možnost "trvalého" uložení adresy v přijímací straně
(bude pak reagovat jen s napárovaným vysílačem).
Průběh párování:
1. Po zapnutí vysílač vysílá broadcast zprávu "PAIR"
2. Pokud přijímací strana zachytí tuto zprávu, uloží si MAC adresu vysílače
a odpoví na tuto adresu zprávou "ACK"
3. Vysílač po si obržení potvrzovací zprávy zapamatuje MAC adresu přijímače, který mu
odpověděl
4. Vysílač přestane vysílat broadcast a začně vysílat na adresu přijímače
5. Pokud vysílač nedostane informaci o úspěšném doručení zprávy (přijímač je vypnut
nebo je mimo dosah), začńe opět vysílat broadcast "PAIR"
6. Pokud přijímací strana po delší dobu nedostane zprávu nebo se mu nepodaří
úspěšně odeslat zprávu vysílači (vysílač je vypnut nebo mimo dosah) čeká na opětovné spárování.
Zdrojový kód vysílače:
Full-Tx.ino
debug.h
espnow-tx.cpp
espnow-tx.h
#include "espnow-tx.h"
EspNow espnow;
void setup() {
Serial.begin(115200);
espnow.init();
Serial.println("Ready");
}
void loop() {
char s[32];
sprintf(s, "%4ld", millis() / 1000);
espnow.sendData(s);
// Serial.println(s);
delay(1000);
}
EspNow espnow;
void setup() {
Serial.begin(115200);
espnow.init();
Serial.println("Ready");
}
void loop() {
char s[32];
sprintf(s, "%4ld", millis() / 1000);
espnow.sendData(s);
// Serial.println(s);
delay(1000);
}
#ifndef DEBUG_H
#define DEBUG_H
#define DEBUG
#ifdef DEBUG
#define DEBUG_BEGIN(...) { Serial.begin(__VA_ARGS__); }
#define DEBUG_PRINT(...) { Serial.print(__VA_ARGS__); }
#define DEBUG_PRINTF(...) { Serial.printf(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { Serial.println(__VA_ARGS__); }
#else
#define DEBUG_BEGIN(...) {}
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTF(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
#endif
#define DEBUG_H
#define DEBUG
#ifdef DEBUG
#define DEBUG_BEGIN(...) { Serial.begin(__VA_ARGS__); }
#define DEBUG_PRINT(...) { Serial.print(__VA_ARGS__); }
#define DEBUG_PRINTF(...) { Serial.printf(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { Serial.println(__VA_ARGS__); }
#else
#define DEBUG_BEGIN(...) {}
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTF(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
#endif
#include "espnow-tx.h"
EspNow* _espnow;
const uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const char ACK[] = "ACK";
const char PAIR[] = "PAIR";
void PrintMAC(const uint8_t* addr) {
DEBUG_PRINTF("%02x:%02x:%02x:%02x:%02x:%02x\n\r", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
// Callback when data is received
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
_espnow->receiveData(mac, incomingData, len);
}
// Callback when data is sent
void OnDataSent(const uint8_t* mac_addr, esp_now_send_status_t s) {
DEBUG_PRINT(" Send status: ");
DEBUG_PRINTLN(s == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (s != ESP_NOW_SEND_SUCCESS) _espnow->status = EspNow::NOT_CONNECTED;
}
void EspNow::init() {
EEPROM.begin(16);
EEPROM.readBytes(MAC_ADDR, destinationAddress, MAC_LEN);
PrintMAC(destinationAddress);
status = NOT_CONNECTED;
dataReady = NO_DATA;
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
return;
}
// Registrace callback po prijeti dat
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
// Registrace callback po odeslani dat
esp_now_register_send_cb(OnDataSent);
addPeer(broadcastAddress);
_espnow = this;
}
void EspNow::receiveData(const uint8_t* mac, const uint8_t* incomingData, int len) {
if (memcmp(incomingData, ACK, sizeof(ACK)) == 0) {
memcpy(destinationAddress, mac, MAC_LEN);
if (status == NOT_CONNECTED) {
addPeer(destinationAddress);
DEBUG_PRINT("Paired to ");
PrintMAC(destinationAddress);
status = CONNECTED;
}
} else {
if (status == CONNECTED && memcmp(destinationAddress, mac, MAC_LEN) == 0) {
memcpy((void*)data, incomingData, (len > MAX_LEN) ? MAX_LEN : len);
dataReady = DATA_READY;
}
}
}
int EspNow::getData(void* payload, int len) {
if (dataReady == DATA_READY) {
memcpy(payload, (const void*)data, len);
dataReady = NO_DATA;
return 1;
} else {
return 0;
}
}
int EspNow::sendData(void* payload, int len) {
esp_err_t result;
if (status == CONNECTED) {
result = esp_now_send(destinationAddress, (uint8_t*)payload, len);
DEBUG_PRINT("Send data: ");
DEBUG_PRINTLN((char*)payload);
} else {
result = esp_now_send(broadcastAddress, (uint8_t*)PAIR, sizeof(PAIR));
DEBUG_PRINTLN("Send broadcast PAIR");
}
if (result == ESP_OK) {
DEBUG_PRINT("Data sent");
} else {
DEBUG_PRINTLN("Error sending the data");
status = NOT_CONNECTED;
}
return status;
}
int EspNow::sendData(char* s) {
return sendData((uint8_t*)s, strlen(s));
}
void EspNow::addPeer(const uint8_t* mac) {
if (!esp_now_is_peer_exist(mac)) {
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, mac, MAC_LEN);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
DEBUG_PRINTLN("Failed to add peer");
return;
} else {
DEBUG_PRINTLN("Add peer ok");
}
}
}
EspNow* _espnow;
const uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const char ACK[] = "ACK";
const char PAIR[] = "PAIR";
void PrintMAC(const uint8_t* addr) {
DEBUG_PRINTF("%02x:%02x:%02x:%02x:%02x:%02x\n\r", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
// Callback when data is received
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
_espnow->receiveData(mac, incomingData, len);
}
// Callback when data is sent
void OnDataSent(const uint8_t* mac_addr, esp_now_send_status_t s) {
DEBUG_PRINT(" Send status: ");
DEBUG_PRINTLN(s == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (s != ESP_NOW_SEND_SUCCESS) _espnow->status = EspNow::NOT_CONNECTED;
}
void EspNow::init() {
EEPROM.begin(16);
EEPROM.readBytes(MAC_ADDR, destinationAddress, MAC_LEN);
PrintMAC(destinationAddress);
status = NOT_CONNECTED;
dataReady = NO_DATA;
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
return;
}
// Registrace callback po prijeti dat
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
// Registrace callback po odeslani dat
esp_now_register_send_cb(OnDataSent);
addPeer(broadcastAddress);
_espnow = this;
}
void EspNow::receiveData(const uint8_t* mac, const uint8_t* incomingData, int len) {
if (memcmp(incomingData, ACK, sizeof(ACK)) == 0) {
memcpy(destinationAddress, mac, MAC_LEN);
if (status == NOT_CONNECTED) {
addPeer(destinationAddress);
DEBUG_PRINT("Paired to ");
PrintMAC(destinationAddress);
status = CONNECTED;
}
} else {
if (status == CONNECTED && memcmp(destinationAddress, mac, MAC_LEN) == 0) {
memcpy((void*)data, incomingData, (len > MAX_LEN) ? MAX_LEN : len);
dataReady = DATA_READY;
}
}
}
int EspNow::getData(void* payload, int len) {
if (dataReady == DATA_READY) {
memcpy(payload, (const void*)data, len);
dataReady = NO_DATA;
return 1;
} else {
return 0;
}
}
int EspNow::sendData(void* payload, int len) {
esp_err_t result;
if (status == CONNECTED) {
result = esp_now_send(destinationAddress, (uint8_t*)payload, len);
DEBUG_PRINT("Send data: ");
DEBUG_PRINTLN((char*)payload);
} else {
result = esp_now_send(broadcastAddress, (uint8_t*)PAIR, sizeof(PAIR));
DEBUG_PRINTLN("Send broadcast PAIR");
}
if (result == ESP_OK) {
DEBUG_PRINT("Data sent");
} else {
DEBUG_PRINTLN("Error sending the data");
status = NOT_CONNECTED;
}
return status;
}
int EspNow::sendData(char* s) {
return sendData((uint8_t*)s, strlen(s));
}
void EspNow::addPeer(const uint8_t* mac) {
if (!esp_now_is_peer_exist(mac)) {
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, mac, MAC_LEN);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
DEBUG_PRINTLN("Failed to add peer");
return;
} else {
DEBUG_PRINTLN("Add peer ok");
}
}
}
#ifndef ESPNOW_H
#define ESPNOW_H
#include <Arduino.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <EEPROM.h>
#include "debug.h"
#define MAC_LEN 6
#define MAC_ADDR 0
class EspNow {
public:
enum {NOT_CONNECTED = -1, CONNECTED = 0, PAIRING = 1};
enum {NO_DATA = 0, DATA_READY = 1};
volatile int status;
void init();
int sendData(char*);
int sendData(void* = NULL, int = 0);
int getStatus();
int getData(void*, int);
void receiveData(const uint8_t* mac, const uint8_t* incomingData, int len);
private:
static const int MAX_LEN = 32;
volatile uint8_t data[MAX_LEN];
volatile int dataReady;
uint8_t destinationAddress[MAC_LEN];
void addPeer(const uint8_t* mac);
};
#endif
#define ESPNOW_H
#include <Arduino.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <EEPROM.h>
#include "debug.h"
#define MAC_LEN 6
#define MAC_ADDR 0
class EspNow {
public:
enum {NOT_CONNECTED = -1, CONNECTED = 0, PAIRING = 1};
enum {NO_DATA = 0, DATA_READY = 1};
volatile int status;
void init();
int sendData(char*);
int sendData(void* = NULL, int = 0);
int getStatus();
int getData(void*, int);
void receiveData(const uint8_t* mac, const uint8_t* incomingData, int len);
private:
static const int MAX_LEN = 32;
volatile uint8_t data[MAX_LEN];
volatile int dataReady;
uint8_t destinationAddress[MAC_LEN];
void addPeer(const uint8_t* mac);
};
#endif
Zdrojový kód přijímače:
Full-Rx.ino
debug.h
espnow-rx.cpp
espnow-rx.h
#include "espnow-rx.h"
EspNow espnow;
void setup() {
Serial.begin(115200);
espnow.init();
Serial.println("Ready");
}
void loop() {
char s[32];
if (espnow.getData(s, 32)) {
Serial.printf("Received: %s\r\n", s);
}
}
EspNow espnow;
void setup() {
Serial.begin(115200);
espnow.init();
Serial.println("Ready");
}
void loop() {
char s[32];
if (espnow.getData(s, 32)) {
Serial.printf("Received: %s\r\n", s);
}
}
#ifndef DEBUG_H
#define DEBUG_H
#define DEBUG
#ifdef DEBUG
#define DEBUG_BEGIN(...) { Serial.begin(__VA_ARGS__); }
#define DEBUG_PRINT(...) { Serial.print(__VA_ARGS__); }
#define DEBUG_PRINTF(...) { Serial.printf(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { Serial.println(__VA_ARGS__); }
#else
#define DEBUG_BEGIN(...) {}
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTF(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
#endif
#define DEBUG_H
#define DEBUG
#ifdef DEBUG
#define DEBUG_BEGIN(...) { Serial.begin(__VA_ARGS__); }
#define DEBUG_PRINT(...) { Serial.print(__VA_ARGS__); }
#define DEBUG_PRINTF(...) { Serial.printf(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { Serial.println(__VA_ARGS__); }
#else
#define DEBUG_BEGIN(...) {}
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTF(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
#endif
#include "espnow-rx.h"
EspNow* _espnow;
const uint32_t TIMEOUT = 2000;
const uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const char ACK[] = "ACK";
const char PAIR[] = "PAIR";
void PrintMAC(const uint8_t* addr) {
DEBUG_PRINTF("%02x:%02x:%02x:%02x:%02x:%02x\n\r", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
// Callback volany po prijeti dat
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
_espnow->receiveData(mac, incomingData, len);
}
// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t s) {
DEBUG_PRINT(" Send status: ");
DEBUG_PRINTLN(s == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (s != ESP_NOW_SEND_SUCCESS) _espnow->status = EspNow::NOT_CONNECTED;
}
void EspNow::init() {
EEPROM.begin(16);
EEPROM.readBytes(MAC_ADDR, destinationAddress, MAC_LEN);
PrintMAC(destinationAddress);
// status = NOT_CONNECTED;
status = PAIRING;
dataReady = NO_DATA;
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
return;
}
// Registrace callback po prijeti dat
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
// Registrace callback po odeslani dat
esp_now_register_send_cb(OnDataSent);
_espnow = this;
}
void EspNow::receiveData(const uint8_t* mac, const uint8_t* incomingData, int len) {
if (/*memcmp(esp_now_recv_info.des_addr, broadcastAddress, MAC_LEN) == 0 &&*/ memcmp(incomingData, (uint8_t*)PAIR, sizeof(PAIR)) == 0) {
if (status == PAIRING) {
memcpy(destinationAddress, mac, MAC_LEN);
// EEPROM.writeBytes(MAC_ADDR, destinationAddress, MAX_LEN);
status = NOT_CONNECTED;
}
if (status == NOT_CONNECTED) {
if (memcmp(mac, destinationAddress, MAC_LEN) == 0) {
addPeer(destinationAddress);
esp_err_t result = esp_now_send(destinationAddress, (uint8_t*)ACK, sizeof(ACK));
if (result == ESP_OK) {
DEBUG_PRINT("Pair ok");
lastData = millis();
status = CONNECTED;
} else {
DEBUG_PRINTLN("Error sending the data");
}
}
}
} else {
if (status == CONNECTED && memcmp(destinationAddress, mac, MAC_LEN) == 0) {
memcpy((void*)data, incomingData, (len > MAX_LEN) ? MAX_LEN : len);
dataReady = DATA_READY;
lastData = millis();
}
}
}
int EspNow::getData(void* payload, int len) {
if (dataReady == DATA_READY) {
memcpy(payload, (const void*)data, len);
dataReady = NO_DATA;
return 1;
} else {
if (millis() - lastData > TIMEOUT && status == CONNECTED) {
status = NOT_CONNECTED;
}
return 0;
}
}
void EspNow::pair() {
status = PAIRING;
memset(destinationAddress, 0, MAC_LEN);
}
int EspNow::sendData(void* payload, int len) {
if (status == CONNECTED) {
esp_err_t result = esp_now_send(destinationAddress, (uint8_t*)payload, len);
DEBUG_PRINT("Send data: ");
DEBUG_PRINTLN((char*)payload);
if (result == ESP_OK) {
DEBUG_PRINT("Data sent");
} else {
DEBUG_PRINTLN("Error sending the data");
status = NOT_CONNECTED;
}
}
return status;
}
int EspNow::sendData(char* s) {
return sendData((uint8_t*)s, strlen(s));
}
void EspNow::addPeer(uint8_t* mac) {
if (!esp_now_is_peer_exist(mac)) {
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, mac, MAC_LEN);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
DEBUG_PRINTLN("Failed to add peer");
return;
} else {
DEBUG_PRINTLN("Add peer ok");
}
}
}
EspNow* _espnow;
const uint32_t TIMEOUT = 2000;
const uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const char ACK[] = "ACK";
const char PAIR[] = "PAIR";
void PrintMAC(const uint8_t* addr) {
DEBUG_PRINTF("%02x:%02x:%02x:%02x:%02x:%02x\n\r", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
// Callback volany po prijeti dat
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
_espnow->receiveData(mac, incomingData, len);
}
// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t s) {
DEBUG_PRINT(" Send status: ");
DEBUG_PRINTLN(s == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (s != ESP_NOW_SEND_SUCCESS) _espnow->status = EspNow::NOT_CONNECTED;
}
void EspNow::init() {
EEPROM.begin(16);
EEPROM.readBytes(MAC_ADDR, destinationAddress, MAC_LEN);
PrintMAC(destinationAddress);
// status = NOT_CONNECTED;
status = PAIRING;
dataReady = NO_DATA;
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
return;
}
// Registrace callback po prijeti dat
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
// Registrace callback po odeslani dat
esp_now_register_send_cb(OnDataSent);
_espnow = this;
}
void EspNow::receiveData(const uint8_t* mac, const uint8_t* incomingData, int len) {
if (/*memcmp(esp_now_recv_info.des_addr, broadcastAddress, MAC_LEN) == 0 &&*/ memcmp(incomingData, (uint8_t*)PAIR, sizeof(PAIR)) == 0) {
if (status == PAIRING) {
memcpy(destinationAddress, mac, MAC_LEN);
// EEPROM.writeBytes(MAC_ADDR, destinationAddress, MAX_LEN);
status = NOT_CONNECTED;
}
if (status == NOT_CONNECTED) {
if (memcmp(mac, destinationAddress, MAC_LEN) == 0) {
addPeer(destinationAddress);
esp_err_t result = esp_now_send(destinationAddress, (uint8_t*)ACK, sizeof(ACK));
if (result == ESP_OK) {
DEBUG_PRINT("Pair ok");
lastData = millis();
status = CONNECTED;
} else {
DEBUG_PRINTLN("Error sending the data");
}
}
}
} else {
if (status == CONNECTED && memcmp(destinationAddress, mac, MAC_LEN) == 0) {
memcpy((void*)data, incomingData, (len > MAX_LEN) ? MAX_LEN : len);
dataReady = DATA_READY;
lastData = millis();
}
}
}
int EspNow::getData(void* payload, int len) {
if (dataReady == DATA_READY) {
memcpy(payload, (const void*)data, len);
dataReady = NO_DATA;
return 1;
} else {
if (millis() - lastData > TIMEOUT && status == CONNECTED) {
status = NOT_CONNECTED;
}
return 0;
}
}
void EspNow::pair() {
status = PAIRING;
memset(destinationAddress, 0, MAC_LEN);
}
int EspNow::sendData(void* payload, int len) {
if (status == CONNECTED) {
esp_err_t result = esp_now_send(destinationAddress, (uint8_t*)payload, len);
DEBUG_PRINT("Send data: ");
DEBUG_PRINTLN((char*)payload);
if (result == ESP_OK) {
DEBUG_PRINT("Data sent");
} else {
DEBUG_PRINTLN("Error sending the data");
status = NOT_CONNECTED;
}
}
return status;
}
int EspNow::sendData(char* s) {
return sendData((uint8_t*)s, strlen(s));
}
void EspNow::addPeer(uint8_t* mac) {
if (!esp_now_is_peer_exist(mac)) {
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, mac, MAC_LEN);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
DEBUG_PRINTLN("Failed to add peer");
return;
} else {
DEBUG_PRINTLN("Add peer ok");
}
}
}
#ifndef ESPNOW_H
#define ESPNOW_H
#include <Arduino.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <EEPROM.h>
#include "debug.h"
#define MAC_LEN 6
#define MAC_ADDR 0
class EspNow {
public:
enum {NOT_CONNECTED = -1, CONNECTED = 0, PAIRING = 1};
enum {NO_DATA = 0, DATA_READY = 1};
volatile int status;
void init();
void pair();
int sendData(char*);
int sendData(void* = NULL, int = 0);
int getStatus();
int getData(void*, int);
void receiveData(const uint8_t* mac, const uint8_t* incomingData, int len);
private:
static const int MAX_LEN = 32;
volatile uint8_t data[MAX_LEN];
volatile int dataReady;
uint8_t destinationAddress[MAC_LEN];
uint32_t lastData;
void addPeer(uint8_t* mac);
};
#endif
#define ESPNOW_H
#include <Arduino.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <EEPROM.h>
#include "debug.h"
#define MAC_LEN 6
#define MAC_ADDR 0
class EspNow {
public:
enum {NOT_CONNECTED = -1, CONNECTED = 0, PAIRING = 1};
enum {NO_DATA = 0, DATA_READY = 1};
volatile int status;
void init();
void pair();
int sendData(char*);
int sendData(void* = NULL, int = 0);
int getStatus();
int getData(void*, int);
void receiveData(const uint8_t* mac, const uint8_t* incomingData, int len);
private:
static const int MAX_LEN = 32;
volatile uint8_t data[MAX_LEN];
volatile int dataReady;
uint8_t destinationAddress[MAC_LEN];
uint32_t lastData;
void addPeer(uint8_t* mac);
};
#endif
Použitá literatura a odkazy na internetu
[1] Popis ESP-NOW