固件 0.1.19~0.1.21-c5:配网热点(SoftAP + 网页)、风扇 40 ℃ 以下断电
- 0.1.19 配网热点:没配 WiFi / 连续 60 s 连不上时自己开 SoftAP,192.168.4.1 网页里加删 WiFi、改 MQTT; 配置拼成 wifi / mqtt 命令走唯一的命令处理器(新链路号 3 CMD_LINK_AP),MQTT 仍不收配置命令 - 0.1.20 热点口令固定 88888888 - 0.1.21 风扇:板温 >=40 ℃ 上电、<38 ℃ 断电,40~65 ℃ 线性调速;fan 命令加可选 sec(下限到点自动交回) - mqtt 命令加 keep_pass;net 回应加 ap;status 的 fan 加 left - 新增 test_prov(13 例),test_t_thermal +3;29 ctest 全绿 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
+64
-5
@@ -18,7 +18,9 @@
|
||||
|
||||
---- 失联不动作(§10.2 / §10.8) -----------------------------------------
|
||||
WiFi 断、broker 断,本文件只做一件事:**重连**(WiFi 指数退避,MQTT 由 esp-mqtt 每 10 s 重试)。
|
||||
没有任何「连不上就……」的分支会碰到输出 —— 五台手机照常供电。 */
|
||||
没有任何「连不上就……」的分支会碰到输出 —— 五台手机照常供电。
|
||||
0.1.19 起多一件:WiFi 连续 60 s 连不上就**开配网热点**(prov.h),STA 照常在后台重连,
|
||||
连上了热点自己关。热点同样不碰输出。 */
|
||||
#include <string.h>
|
||||
|
||||
#include "cmd_queue.h"
|
||||
@@ -39,6 +41,8 @@
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "phonerail.h"
|
||||
#include "prov.h"
|
||||
#include "prov_esp.h"
|
||||
#include "tasks.h"
|
||||
#include "ulink.h"
|
||||
|
||||
@@ -91,6 +95,9 @@ static uint32_t s_attempt;
|
||||
static mlink_tele_t s_tele;
|
||||
static volatile bool s_tele_inflight;
|
||||
static bool s_up;
|
||||
static volatile bool s_slow; /* 有人在配网网页上:重连间隔不短于 PROV_SLOW_MS(prov.h) */
|
||||
static uint32_t s_ap_try_ms; /* 上次开 / 关热点是什么时候(没成功时别每拍都试) */
|
||||
static bool s_ap_tried;
|
||||
|
||||
/* 发件队列(见文件头):执行器 / esp-mqtt 任务往里拷,t_link 取出来交给 esp-mqtt。
|
||||
深度 4 × 1.5 KB:遥测 1 s 一条、回应偶尔一条,t_link 至少每 100 ms 来取一次;
|
||||
@@ -343,6 +350,16 @@ static void wifi_set_sta(uint8_t idx)
|
||||
ST_EDIT(s_st.wifi_idx = idx);
|
||||
}
|
||||
|
||||
/* 发起一次连接。驱动当场拒了(配网网页正在扫描时会)就不会有断开事件来接着排下一次 ——
|
||||
重连链在这里断掉 = 板子永远不回网,所以自己排一次。 */
|
||||
static void sta_connect(void)
|
||||
{
|
||||
if (esp_wifi_connect() != ESP_OK) {
|
||||
esp_timer_stop(s_retry);
|
||||
esp_timer_start_once(s_retry, 3000u * 1000u);
|
||||
}
|
||||
}
|
||||
|
||||
static void retry_cb(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
@@ -350,7 +367,7 @@ static void retry_cb(void *arg)
|
||||
if (s_st.wifi != NET_UP && n > 0) {
|
||||
const uint8_t i = s_idx < n ? s_idx : 0;
|
||||
wifi_set_sta(i);
|
||||
esp_wifi_connect();
|
||||
sta_connect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +391,10 @@ static void on_wifi(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
if (!was_up && n > 1) {
|
||||
s_idx = (uint8_t)((s_idx + 1) % n);
|
||||
}
|
||||
const uint32_t ms = mlink_backoff_ms(s_attempt++ / (uint32_t)n);
|
||||
uint32_t ms = mlink_backoff_ms(s_attempt++ / (uint32_t)n);
|
||||
if (s_slow && ms < PROV_SLOW_MS) {
|
||||
ms = PROV_SLOW_MS; /* 每试一次热点都要离开信道扫一圈,试密了网页就卡(prov.h) */
|
||||
}
|
||||
ESP_LOGW(TAG, "WiFi 断开,原因 %u,%u ms 后连「%s」", (unsigned)d->reason, (unsigned)ms,
|
||||
s_cur.wifi[s_idx < n ? s_idx : 0].ssid);
|
||||
esp_timer_stop(s_retry);
|
||||
@@ -407,10 +427,33 @@ static void wifi_apply(void)
|
||||
}
|
||||
wifi_set_sta(s_idx);
|
||||
ST_EDIT(s_st.wifi = NET_CONNECTING);
|
||||
esp_wifi_connect();
|
||||
sta_connect();
|
||||
ESP_LOGI(TAG, "连 WiFi「%s」(%u/%d)", s_cur.wifi[s_idx].ssid, (unsigned)s_idx + 1, n); /* 只打 SSID,不打口令 */
|
||||
}
|
||||
|
||||
/* ---- 配网热点(t_link 里调):判据在 prov.c,开关在 prov_esp.c ------------- */
|
||||
|
||||
static void prov_poll(void)
|
||||
{
|
||||
const uint32_t now = hal_time_now_ms();
|
||||
const prov_in_t in = { .n_wifi = netcfg_wifi_count(&s_cur), .wifi_up = s_st.wifi == NET_UP,
|
||||
.ap_sta = prov_esp_sta_count(), .touched = prov_esp_take_touch() };
|
||||
const prov_out_t o = prov_step(&in, now);
|
||||
s_slow = o.hold;
|
||||
if (o.ap != prov_esp_on() && (!s_ap_tried || (uint32_t)(now - s_ap_try_ms) >= 10000u)) {
|
||||
s_ap_tried = true;
|
||||
s_ap_try_ms = now;
|
||||
prov_esp_set(o.ap); /* 没成功就 10 s 后再来,不是每拍都试 */
|
||||
}
|
||||
const bool on = prov_esp_on();
|
||||
if (on == o.ap) {
|
||||
s_ap_tried = false;
|
||||
}
|
||||
if (on != s_st.ap_on || (uint8_t)in.ap_sta != s_st.ap_sta || (uint8_t)o.why != s_st.ap_why) {
|
||||
ST_EDIT(s_st.ap_on = on; s_st.ap_sta = (uint8_t)in.ap_sta; s_st.ap_why = (uint8_t)o.why);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 对外 ---------------------------------------------------------------- */
|
||||
|
||||
hal_err_t mlink_esp_init(void)
|
||||
@@ -444,6 +487,7 @@ hal_err_t mlink_esp_init(void)
|
||||
ESP_LOGE(TAG, "网络栈起不来 —— WiFi 链路不可用");
|
||||
return HAL_ERR_STATE;
|
||||
}
|
||||
esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); /* 配网热点用;平时模式是 STA,它闲着 */
|
||||
const wifi_init_config_t wi = WIFI_INIT_CONFIG_DEFAULT();
|
||||
if (esp_wifi_init(&wi) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "WiFi 驱动起不来 —— WiFi 链路不可用");
|
||||
@@ -454,10 +498,14 @@ hal_err_t mlink_esp_init(void)
|
||||
esp_wifi_set_storage(WIFI_STORAGE_RAM); /* 凭据只存我们自己的那份,驱动别再存一份 */
|
||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||
esp_wifi_start();
|
||||
prov_init(hal_time_now_ms());
|
||||
prov_esp_init(ap_netif, mlink_id());
|
||||
ST_EDIT(snprintf(s_st.ap_ssid, sizeof(s_st.ap_ssid), "%s", prov_esp_ssid());
|
||||
snprintf(s_st.ap_pass, sizeof(s_st.ap_pass), "%s", prov_esp_pass()));
|
||||
s_up = true;
|
||||
ESP_LOGI(TAG, "板子 ID %s,topic %s/…", mlink_id(), mlink_topic(MLINK_T_CMD));
|
||||
if (!have) {
|
||||
ESP_LOGW(TAG, "还没配网:经 USB 发 wifi / mqtt 两条命令(tools/prlink.py)");
|
||||
ESP_LOGW(TAG, "还没配网:连热点「%s」开网页,或经 USB 发 wifi / mqtt(tools/prlink.py)", prov_esp_ssid());
|
||||
}
|
||||
wifi_apply();
|
||||
return HAL_OK;
|
||||
@@ -481,14 +529,25 @@ void mlink_esp_poll(void)
|
||||
if (!(wifi_same && mqtt_same)) {
|
||||
mqtt_stop();
|
||||
}
|
||||
/* 没连着的时候:刚加 / 刚改口令的那一组先试 —— 人正等着看它连不连得上(配网网页尤其)。 */
|
||||
uint8_t first = s_idx;
|
||||
for (int i = 0; i < netcfg_wifi_count(&next); i++) {
|
||||
const int k = netcfg_wifi_find(&s_cur, next.wifi[i].ssid);
|
||||
if (k < 0 || strcmp(s_cur.wifi[k].pass, next.wifi[i].pass) != 0) {
|
||||
first = (uint8_t)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s_cur = next;
|
||||
if (wifi_same) {
|
||||
s_idx = (uint8_t)j;
|
||||
ST_EDIT(s_st.wifi_idx = s_idx);
|
||||
} else {
|
||||
s_idx = first;
|
||||
wifi_apply();
|
||||
}
|
||||
}
|
||||
prov_poll();
|
||||
/* MQTT 的生命周期只在这里管:WiFi 有地址、配了 broker、还没建客户端 ⇒ 建。
|
||||
之后掉线重连由 esp-mqtt 自己做(network.reconnect_timeout_ms,默认 10 s)。 */
|
||||
if (s_mqtt == NULL && s_st.wifi == NET_UP && s_cur.uri[0] != '\0') {
|
||||
|
||||
在新工单中引用
屏蔽一个用户