下面给你一套"用这个模组(ESPC5-12 / ESP32-C5)做 SOS Wi-Fi 报警器"的可量产方案:硬件最小系统 + 按键触发 + 配网 + HTTP 上报 + 低功耗/可靠性。文档里明确:模组工作电压 3.3V、支持 TCP/IP/HTTP、建议电源能力≥500mA(启动 RF 校准峰值电流很大)。
1) 产品定义与流程
**触发方式:**按下 SOS 按钮(可做短按/长按两种逻辑)
动作:
-
设备从 deep-sleep 唤醒(或常开运行)
-
连接已保存的 Wi-Fi(STA)
-
调用你的 HTTP 接口上报一次(或连发 N 次保证到达)
-
可选:闪灯/蜂鸣提示成功/失败
-
进入 deep-sleep 等待下次按键
2) 硬件设计(最小可用 + 量产建议)
A. 供电
-
3.3V 供电:模组工作电压 DC 3.3V(3.0~3.6V)。
-
电源能力:文档强调模组启动时峰值电流可能 >500mA,建议电源≥500mA。
- 如果你用电池:建议用同步降压/升降压(比"升到5V再1117降到3.3V"更省电更稳)。
-
去耦/储能(很关键):在模组 3V3 引脚附近放:
-
0.1uF + 1uF(贴近引脚)
-
10uF~47uF(同电源域)
-
电池供电再加 100uF(视内阻与走线)
-
B. 按键(SOS)
-
用任意一个 GPIO 做按键输入(带上拉/下拉),建议:
-
GPIO 输入 + 内部上拉,按键接地
-
外加 RC 消抖:100nF + 100k(或仅软件消抖)
-
-
低功耗唤醒 :用该 GPIO 配置为 EXT0/EXT1 唤醒源(按键拉低唤醒最常见)
C. 指示(可选但强烈建议)
-
1 个 LED(成功/失败)
-
1 个蜂鸣器(提示用户"已发送/发送失败")
D. 天线/摆放(一定按手册来)
ESPC5-12 是 PCB 天线模组,手册给了天线区布局原则:天线附近不要有金属、走线、外壳;可以在天线下方挖空/禁布铜等方案。
你之前"信号不太好"的问题,很多就是这条没做对。
3) 配网与参数存储(建议两种模式)
方案 1:BLE/SoftAP 配网(用户友好)
-
首次开机:进入配网模式(SoftAP 或 BLE 配网)
-
保存:SSID/Password、设备ID、上报URL、Token
-
后续:按键直接上报,无需手机
方案 2:串口配置(工程/产测友好)
-
通过 UART/USB 下载、串口命令写 NVS(手册支持 UART/USB 下载)。
-
适合量产烧录 & 产测写入 token / server 地址
4) HTTP 上报接口设计("标准 HTTP"且可扩展)
推荐 HTTP POST + JSON(最通用),例子:
POST /api/sos
Headers:
-
Content-Type: application/json -
Authorization: Bearer <token>(或X-Device-Token)
Body(示例):
{
"device_id": "C5-12-001122",
"event": "SOS",
"ts": 1768484374000,
"battery_mv": 3920,
"wifi_rssi": -63,
"seq": 123
}
服务端返回:
200 OK+{"ok":true,"event_id":"..."}
为什么要 seq?
防重复、做幂等(设备重试多次也不会生成多条报警)。
5) 固件实现要点(稳定、快、低功耗)
关键优化点
-
连接超时:Wi-Fi 连接超时 8~12 秒;HTTP 超时 5~8 秒
-
重试策略:HTTP 失败重试 2~3 次;仍失败则缓存"待上报"到 NVS(下次按键再补发)
-
省电 :成功后立刻
esp_deep_sleep_start();平时 deep-sleep -
RF 校准电流:启动瞬间电流大,所以电源和储能要足(手册已提醒)。
6) ESP-IDF 示例代码(按键唤醒→连网→HTTP POST→睡眠)
下面是"核心骨架",你把 URL/Token/证书、按键 GPIO 改成你的即可。
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_sleep.h"
#include "esp_http_client.h"
#include "cJSON.h"
static const char *TAG = "sos";
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
// ====== 改成你的按键GPIO(示例:GPIO 9)======
#define SOS_BTN_GPIO 9
// ====== 改成你的服务端 ======
#define SOS_URL "http://example.com/api/sos"
#define DEVICE_ID "C5-12-001122"
#define TOKEN "YOUR_TOKEN"
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
// 这里可以做重连次数限制
esp_wifi_connect();
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
static esp_err_t wifi_start_sta(const char *ssid, const char *pass) {
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));
wifi_config_t wifi_config = { 0 };
strncpy((char*)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
strncpy((char*)wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; // 按需改
wifi_config.sta.pmf_cfg.capable = true;
wifi_config.sta.pmf_cfg.required = false;
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
// 等待连接成功(超时)
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT,
pdFALSE, pdTRUE, pdMS_TO_TICKS(12000));
return (bits & WIFI_CONNECTED_BIT) ? ESP_OK : ESP_FAIL;
}
static esp_err_t http_post_sos(int battery_mv, int rssi, int seq) {
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "device_id", DEVICE_ID);
cJSON_AddStringToObject(root, "event", "SOS");
cJSON_AddNumberToObject(root, "battery_mv", battery_mv);
cJSON_AddNumberToObject(root, "wifi_rssi", rssi);
cJSON_AddNumberToObject(root, "seq", seq);
char *json = cJSON_PrintUnformatted(root);
esp_http_client_config_t config = {
.url = SOS_URL,
.timeout_ms = 8000,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
// Token 放 header
char auth[256];
snprintf(auth, sizeof(auth), "Bearer %s", TOKEN);
esp_http_client_set_header(client, "Authorization", auth);
esp_http_client_set_post_field(client, json, strlen(json));
esp_err_t err = esp_http_client_perform(client);
int status = esp_http_client_get_status_code(client);
esp_http_client_cleanup(client);
cJSON_Delete(root);
free(json);
if (err == ESP_OK && status >= 200 && status < 300) return ESP_OK;
ESP_LOGW(TAG, "HTTP err=%s status=%d", esp_err_to_name(err), status);
return ESP_FAIL;
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
// 1) 配置按键唤醒(低电平唤醒示例)
// 具体EXT0/EXT1选型按你的GPIO是否支持而定,这里只给思路:
// esp_sleep_enable_ext0_wakeup(SOS_BTN_GPIO, 0);
// 2) 从NVS读取ssid/pass(这里用示例)
const char *ssid = "YourWiFi";
const char *pass = "YourPass";
// 3) 连接Wi-Fi
if (wifi_start_sta(ssid, pass) != ESP_OK) {
ESP_LOGE(TAG, "wifi connect fail -> sleep");
esp_deep_sleep_start();
}
// 4) 读取RSSI/电池(示例:你自己实现 ADC 采集)
int rssi = -60;
int battery_mv = 3900;
int seq = 1; // 从NVS自增更好
// 5) HTTP 上报(重试)
esp_err_t ok = ESP_FAIL;
for (int i = 0; i < 3; i++) {
if (http_post_sos(battery_mv, rssi, seq) == ESP_OK) { ok = ESP_OK; break; }
vTaskDelay(pdMS_TO_TICKS(500));
}
ESP_LOGI(TAG, "report %s -> sleep", ok == ESP_OK ? "OK" : "FAIL");
esp_deep_sleep_start();
}
7) 你下一步给我 3 个参数,我就能把"接口与固件"收敛成可直接交付版本
-
你的 HTTP 接口形式:
GET还是POST?URL 路径和参数名怎么定义? -
是否需要 HTTPS(TLS)?如果需要:证书校验是"系统根证书"还是"固定证书/指纹"?
-
按键逻辑:短按立即报警?还是长按 2 秒才触发(防误触)?
