You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测ESP-NOW从设备与主设备的连接断开状态?

ESP-NOW主设备在线状态检测与触发逻辑实现

ESP-NOW本身没有原生的主从连接状态监测机制,要实现主设备在线时执行指定函数、离线时切换到备用逻辑,最可靠的方案是基于心跳包的超时检测,以下是具体实现思路和代码示例:

核心思路

  • 主设备定时发送心跳包(固定间隔,比如1~5秒),告知从设备自身在线状态
  • 从设备维护一个心跳超时计数器:
    • 收到心跳包时重置计数器
    • 若计数器超过设定阈值(比如3个心跳周期),判定主设备离线,触发离线逻辑
    • 计数器未超时则判定主设备在线,执行指定业务函数

代码实现(Arduino框架)

1. 公共定义(主从设备共享)

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

// 定义心跳包标识和超时阈值
#define HEARTBEAT_SIGNAL 0xAA
#define HEARTBEAT_INTERVAL 2000  // 心跳发送间隔(毫秒)
#define HEARTBEAT_TIMEOUT 6000   // 超时时间(3个心跳周期)

// 数据结构体:区分心跳包和业务数据
typedef struct {
  uint8_t type;  // 0xAA=心跳,0xBB=业务数据
  // 业务数据字段(根据需求添加)
  float sensor_data;
} DataPacket;

DataPacket send_packet;
DataPacket recv_packet;

// 从设备用:记录最后一次收到心跳的时间
unsigned long last_heartbeat_time = 0;
bool master_online = true;

// 主设备用:定时器发送心跳
Ticker heartbeat_ticker;

2. 主设备代码

// 从设备MAC地址(替换为你的从设备MAC)
uint8_t slave_mac[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};

// 发送心跳包函数
void send_heartbeat() {
  send_packet.type = HEARTBEAT_SIGNAL;
  esp_now_send(slave_mac, (uint8_t *)&send_packet, sizeof(send_packet));
}

// ESP-NOW发送回调(可选,用于确认发送状态)
void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  // 可在这里处理发送失败的情况(比如重试)
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // 初始化ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW初始化失败");
    return;
  }
  esp_now_register_send_cb(on_data_sent);

  // 添加从设备为peer
  esp_now_peer_info_t peer_info = {};
  memcpy(peer_info.peer_addr, slave_mac, 6);
  peer_info.channel = 0;
  peer_info.encrypt = false;
  if (esp_now_add_peer(&peer_info) != ESP_OK) {
    Serial.println("添加peer失败");
    return;
  }

  // 启动定时器定时发送心跳
  heartbeat_ticker.attach_ms(HEARTBEAT_INTERVAL, send_heartbeat);
}

void loop() {
  // 主设备在线时执行的业务逻辑
  // 比如发送业务数据
  send_packet.type = 0xBB;
  send_packet.sensor_data = analogRead(A0) * (3.3 / 4095.0);
  esp_now_send(slave_mac, (uint8_t *)&send_packet, sizeof(send_packet));
  delay(1000);  // 业务数据发送间隔,根据需求调整
}

3. 从设备代码

// ESP-NOW接收回调
void on_data_recv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
  memcpy(&recv_packet, data, sizeof(recv_packet));
  
  if (recv_packet.type == HEARTBEAT_SIGNAL) {
    // 收到心跳,更新时间并标记主设备在线
    last_heartbeat_time = millis();
    master_online = true;
  } else if (recv_packet.type == 0xBB) {
    // 处理业务数据
    Serial.print("收到业务数据:");
    Serial.println(recv_packet.sensor_data);
  }
}

// 主设备在线时执行的函数
void run_online_logic() {
  // 替换为你的在线业务逻辑
  Serial.println("主设备在线,执行在线函数");
  digitalWrite(LED_BUILTIN, HIGH);
}

// 主设备离线时执行的函数
void run_offline_logic() {
  // 替换为你的离线业务逻辑
  Serial.println("主设备离线,执行离线函数");
  digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  WiFi.mode(WIFI_STA);

  // 初始化ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW初始化失败");
    return;
  }
  esp_now_register_recv_cb(on_data_recv);
}

void loop() {
  // 检测心跳超时
  if (millis() - last_heartbeat_time > HEARTBEAT_TIMEOUT) {
    if (master_online) {
      // 从在线切换到离线,触发离线逻辑
      master_online = false;
      run_offline_logic();
    }
  } else {
    if (!master_online) {
      // 从离线切换到在线,触发在线逻辑
      master_online = true;
      run_online_logic();
    }
    // 主设备在线时持续执行在线逻辑(或按需调用)
    run_online_logic();
  }
  
  delay(100);  // 降低循环频率,节省资源
}

关键细节说明

  • 心跳间隔与超时阈值:根据实际环境调整,干扰大的场景可增大间隔和阈值,避免误判
  • 发送回调处理:主设备可通过on_data_sent回调检测发送失败,若多次失败可主动标记自身状态(或重试)
  • 加密配对:若需要安全传输,可开启ESP-NOW加密功能,添加peer时设置encrypt = true并配置密钥
  • 资源优化:从设备的循环中加入短延迟,避免CPU占用过高

内容的提问来源于stack exchange,提问作者Kunaal Kiran Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:06:53