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

ESP32 Arduino环境httpSecureClient在核心0运行无故返回-1错误

问题根因

  • 核心问题是非线程安全的网络对象跨核心调用+WiFi资源抢占:ESP32 Arduino框架的WiFiClientSecure、HTTPClient库本身不支持多线程并发访问,你声明了全局的ApiClient、ApiHttpClient对象,在双核心下交替访问时会出现资源状态错乱,同时核心1运行的MQTT连接和核心0的HTTP请求共享同一个WiFi硬件资源,没有互斥机制的情况下会出现资源抢占,导致偶发连接失败返回错误码-1。
  • 次因是任务优先级设置不合理:你给心跳任务设置的优先级为25,高于ESP32系统默认WiFi协议栈任务的优先级(通常为15左右),高优先级的用户任务会抢占WiFi协议栈的CPU时间,导致网络包收发异常。
  • 其他潜在问题:请求前未检查WiFi连接状态、全局网络对象复用未清理上次请求残留状态。

修复方案

1. 替换全局网络对象为任务局部对象

不要在全局声明WiFiClientSecure和HTTPClient,将两个对象放到sendHeartBeat函数内部创建,每次请求结束后自动销毁,避免跨调用的状态残留。

2. 增加WiFi资源互斥锁

全局创建互斥量,所有网络操作(心跳HTTP请求、MQTT收发操作)执行前先获取互斥锁,执行完成后释放锁,避免WiFi资源并发抢占。

3. 调整任务优先级+增加WiFi连接检查

将心跳任务优先级降到5以下,每次发送请求前先判断当前WiFi是否处于连接状态,未连接则跳过本次请求。

4. 增加错误重试逻辑

返回错误码-1时,延迟100ms重试1~2次,覆盖偶发的网络波动场景。

示例修改代码

// 全局仅声明互斥量,不要声明网络对象
SemaphoreHandle_t wifiSemaphore;

// 初始化阶段创建互斥量
void setup() {
  // ...其他初始化代码
  wifiSemaphore = xSemaphoreCreateMutex();
  // 创建心跳任务,优先级改为3
  xTaskCreatePinnedToCore(sendHeartBeat, "Send Heartbeat", 20000, NULL, 3, &heartBeatTask, 0);
}

void sendHeartBeat(void *param) {
  for(;;) {
    // 先检查WiFi连接
    if(WiFi.status() != WL_CONNECTED) {
      vTaskDelay(pdMS_TO_TICKS(1000));
      continue;
    }
    // 拿WiFi互斥锁,最多等5秒
    if(xSemaphoreTake(wifiSemaphore, pdMS_TO_TICKS(5000)) == pdTRUE) {
      // 网络对象放到局部创建
      WiFiClientSecure ApiClient;
      HTTPClient ApiHttpClient;
      StaticJsonDocument<256> doc;
      doc["mac"] = deviceMacAddress;
      doc["key"] = DEVICE_SECRET;
      doc["type"] = DIGITAL_HQ_SOFTWARE_TYPE;
      String heartbeatData;
      serializeJson(doc, heartbeatData);
      ApiClient.setInsecure(); 
      Serial.println("Sending Heartbeat");
      
      int responseCode = -1;
      // 最多重试2次
      for(int retry=0; retry<2 && responseCode!=200; retry++) {
        if(ApiHttpClient.begin(ApiClient, DIGITAL_HQ_HEARTBEAT_ENDPOINT)) {
          ApiHttpClient.addHeader("Content-Type", "application/json");
          ApiHttpClient.setUserAgent(DIGITAL_HQ_USER_AGENT);
          responseCode = ApiHttpClient.POST(heartbeatData);
          ApiHttpClient.end();
        }
        if(responseCode != 200) {
          vTaskDelay(pdMS_TO_TICKS(100));
        }
      }

      if (responseCode != 200) {
          failedApiCalls ++;
      }
      Serial.print("ResponseCode from heartbeat: ");
      Serial.println(responseCode);
      // 释放互斥锁
      xSemaphoreGive(wifiSemaphore);
    }
    // 心跳间隔,按你实际需求修改
    vTaskDelay(pdMS_TO_TICKS(30000));
  }
}

注意:核心1的MQTT操作也要对应加互斥锁,每次MQTT publish/subscribe执行前拿锁,执行完成后释放,否则还是会出现资源抢占问题。

内容的提问来源于stack exchange,提问作者Robin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:39:03