固件 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]>
这个提交包含在:
zhou yang
2026-10-06 14:35:44 +08:00
共同撰写人 Claude Opus 5.5
父节点 3bf4548c62
当前提交 ece65f7c19
共修改 24 个文件,包含 1925 行新增和 324 行删除
+28 -6
查看文件
@@ -1,4 +1,4 @@
/* 网络的三条命令(A14 / C1,需求 IF-19):`wifi` / `mqtt` 写配置(**只收 USB**),`net` 读状态;
/* 网络的三条命令(A14 / C1,需求 IF-19):`wifi` / `mqtt` 写配置(**只收 USB 与配网热点**),`net` 读状态;
外加 C2 的 `ota`(下载固件,两条链路都收)。
`net` 的回应里**永远没有密码**,只有 `pass_set` / `mpass_set`(netcfg.h「密码永不外泄」)。 */
@@ -7,9 +7,11 @@
#include "cmd_priv.h"
#include "netcfg.h"
#include "ota.h"
#include "prov.h"
/* 配置命令只收 USB(cmd.h 链路那一段)。宿主机测试用的 CMD_LINK_TEST 视同 USB。 */
static bool usb_only_ok(const ctx_t *c) { return c->link != CMD_LINK_WIFI; }
/* 配置命令不收 MQTT(cmd.h 链路那一段):USB 与配网热点都是「人在板子旁边」。
宿主机测试用的 CMD_LINK_TEST 视同 USB。 */
static bool local_ok(const ctx_t *c) { return c->link != CMD_LINK_WIFI; }
static cmd_err_t get_str(const ctx_t *c, const char *key, bool required, const char **out)
{
@@ -27,7 +29,7 @@ static cmd_err_t get_str(const ctx_t *c, const char *key, bool required, const c
cmd_err_t do_wifi(ctx_t *c)
{
if (!usb_only_ok(c)) {
if (!local_ok(c)) {
c->bad = CMD_WIFI;
return CMD_ERR_LINK;
}
@@ -69,7 +71,7 @@ cmd_err_t do_wifi(ctx_t *c)
cmd_err_t do_mqtt(ctx_t *c)
{
if (!usb_only_ok(c)) {
if (!local_ok(c)) {
c->bad = CMD_MQTT;
return CMD_ERR_LINK;
}
@@ -77,11 +79,23 @@ cmd_err_t do_mqtt(ctx_t *c)
const char *user = NULL;
const char *mpass = NULL;
int64_t tele = 0;
bool keep = false;
const int gt = cj_get_int(c->o, "tele_ms", &tele);
if (get_str(c, "uri", true, &uri) != CMD_OK || get_str(c, "user", false, &user) != CMD_OK ||
get_str(c, "pass", false, &mpass) != CMD_OK || gt < 0) {
get_str(c, "pass", false, &mpass) != CMD_OK || gt < 0 ||
cj_get_bool(c->o, "keep_pass", &keep) < 0) {
return CMD_ERR_ARG;
}
/* `"keep_pass":true`(0.1.19)= 口令沿用已存的那份:配网网页看不到旧口令(永不回显),
只想改地址时不该逼人重输。同时又给了 `pass` 是自相矛盾,拒。 */
static netcfg_t cur; /* ≈560 B,不放栈上(只有执行器任务进来) */
if (keep) {
if (mpass[0] != '\0') {
return CMD_ERR_ARG;
}
netcfg_get(&cur);
mpass = cur.mpass;
}
if (tele < 0 || tele > NETCFG_TELE_MAX_MS ||
!netcfg_mqtt_ok(uri, user, mpass, (uint32_t)tele)) {
c->bad = tele;
@@ -139,6 +153,14 @@ cmd_err_t do_net(ctx_t *c)
cfg.mpass[0] ? "true" : "false", (unsigned long)cfg.tele_ms,
(unsigned long)st.wifi_drops, (unsigned long)st.mqtt_drops,
(unsigned long)st.tele_sent, (unsigned long)st.tele_skipped);
/* 配网热点(prov.h)。`pass` 是**热点自己的**口令,不是上面那两个「永不外泄」的:
人得先知道它才连得上热点,而读到它的前提是已经在 USB / MQTT 上了。 */
cj_w(w, ",\"ap\":{\"on\":%s,\"why\":\"%s\",\"sta\":%u,\"ssid\":", st.ap_on ? "true" : "false",
prov_why_str((prov_why_t)st.ap_why), (unsigned)st.ap_sta);
w_str(w, st.ap_ssid);
cj_w(w, ",\"pass\":");
w_str(w, st.ap_pass);
cj_w(w, "}");
return CMD_OK;
}