联网功能 - hongligongsi/Consumables-storage-temperature-and-humidity GitHub Wiki

联网功能

联网由 NetworkManager 单例统管,实现在 src/network.cpp, 全部在主循环 loop() 内轮询,不阻塞 50 ms PID 热控节拍。

能力 依赖 默认
WiFi 配网 WiFiManager(非阻塞 AP 门户) 开
Web 管理页 / REST API WebServer,标准端口 80 随 WiFi
MQTT PubSubClient 关
NTP 校时 configTzTime,时区与服务器可配置 开
OTA 升级 ArduinoOTA + ESPmDNS 开

这些开关都能在屏幕的设置页里改(见 系统设置逐项说明),也可经 POST /api/settings 远程改。改完即时生效,无需重启。

配网

首次上电或凭据失效时,设备开出热点:

  • SSID:FilamentChamber-Setup
  • 密码:无

手机连上后自动跳转定制配网页(不支持 5 GHz)。页面提供附近 WiFi 扫描 列表、信号百分比、开放/加密状态、SSID 手动输入、密码显示/隐藏、连接状态与失败 原因,以及「保存并连接」按钮。门户启动后先进行异步预扫描并缓存结果,正常页面 浏览不会把扫描等待放进 50 ms 温控循环;3 分钟无操作自动关闭并重试。

配网成功并关闭 WiFiManager 门户后 WebServer 才启动,因此管理页可使用标准 80 端口。浏览器直接访问 http://chamber.local/;mDNS 不可用时改用设备 IP。

忘记密码 / 换网络

curl -X POST http://<设备IP>/api/wifi/reset

设备清空凭据后重启,重新进入 FilamentChamber-Setup 门户。也可在设置页执行 「恢复出厂配置」。

Web 管理页

打开 http://chamber.local/ 可查看实时温湿度、WiFi 信号、SSID、IP、运行时间、 固件版本与断线诊断,并可配置 NTP/时区、MQTT、OTA 和静态 IPv4,以及语言、屏幕亮度、 RGB 最大亮度与「RGB 跟随屏幕休眠」、发热板限流/风扇风速/温度保护。页面每 3 秒刷新 一次,不依赖外部 CDN。

页面源码在 include/web_page.h(PROGMEM raw string), 离线预览稿为 tools/web_management_preview.html。

REST API

基址 http://<设备IP>。读请求最短间隔 100 ms,写请求最短间隔 500 ms;超限 返回 HTTP 429。所有文本在输出 JSON 前进行转义,设置写入会先校验并确认 NVS 保存成功,失败时不改变运行配置。

GET /api/state

实时状态。字段为 null 表示对应传感器读数无效。

{
  "material": "PLA", "materialIndex": 0, "state": "Printing", "fault": "none",
  "netAlert": "none",
  "lastFault": "BoardOverTemp", "faultCount": 3, "lastFaultEpoch": 1760000000,
  "chamberC": 38.50, "heaterBoardC": 55.20, "humidity": 22.10,
  "currentA": 4.30, "voltageV": 24.10,
  "exhaustPercent": 40, "heatPercent": 65, "heaterFan": 100,
  "light": false, "systemEnabled": true, "pirMotion": true,
  "time": "14:32:05", "ip": "192.168.1.50", "net": "online",
  "ssid": "HomeWiFi", "rssi": -55, "uptimeSeconds": 3600,
  "firmware": "1.0.0", "disconnectCount": 1,
  "lastDisconnectReason": "NO_AP_FOUND", "lastDisconnectReasonCode": 201
}

state 取值:Idle / Detecting / Preheat / Printing / Cooling / Fault。net 为 online / offline。

rssi 为 STA 的接收信号强度(dBm),未联网时为 null。它与屏上主屏的 4 格信号条 同源:后者由 NetworkManager::rssiDbm() 取值、pure::rssiBars() 折算(≥ -55 四格、 ≥ -65 三格、≥ -75 两格、更弱一格),与 Web 管理页的 setBars 用同一套阈值。

fault 为故障原因码短名,非故障态恒为 none,其余取值为 AhtLost / NtcLost / BoardOverTemp / ChamberOverTemp / OverCurrent / InaLost(含义见 故障码与网络告警)。

lastFault / faultCount / lastFaultEpoch 为 NVS 故障记忆(排障历史,与 fault 的「当前是否在故障」互不相干):最近一次锁定的故障码短名(含已解除的,从未锁过为 none)、累计锁定次数、最近一次锁定时刻(epoch 秒,时钟不可用时为 0)。热类故障 断电重启后会恢复 Fault 锁定,详见 故障码与网络告警。

netAlert 为网络告警码短名,无告警恒为 none。与故障走的是两条互不相干的通道: 网络问题只提示不停机,不进故障页、不锁状态机,离线打印照常。

码 短名 含义 触发条件
W-01 WifiAuthFail WiFi 认证失败 认证/关联类断开原因连续 10 次(密码错或加密方式不匹配)
W-02 WifiNoAp 找不到 WiFi NO_AP_FOUND 连续 10 次(SSID 错或超出覆盖范围)
W-03 MqttAuthFail MQTT 认证失败 CONNACK 返回 4/5(broker 拒绝匿名或凭据错)连续 10 次
W-04 MqttUnreachable MQTT 连接超时 其余失败原因连续 10 次(地址/端口/网络不通;含 rc=2 客户端 ID 冲突)

阈值 10 次是为了滤掉路由器重启、信号抖动这类短时断开:一次路由器重启往往拖出 好几个断开事件,3 次挡不住;10 次(MQTT 每 5 s 重试一次,约 50 s;WiFi 侧约 1~2 分钟)才能确认是真连不上。连上即自动清除;功能开关关闭、离线运行、首次配网 (从未存过凭据)都不算异常。改过 MQTT 参数后旧告警立即作废清零。WiFi 告警优先 于 MQTT —— 前者是根因,后者多半是连带结果。

两点行为限制需知悉:其一,MQTT 的重连在加热中会被跳过(预热/打印或加热占空比 非 0 时不重连,避免与 PID 抢资源),因此打印过程中 broker 掉线,W-03/W-04 要等打印 结束、重连恢复尝试并连续失败 10 次后才会出现;其二,告警本身发不进 MQTT —— state 主题虽带 netAlert 字段,但 broker 连不上(W-03/W-04)时发布不出去,WiFi 断了(W-01/W-02)时整个网络都不可用,所以远程只能在恢复后从 /api/state 或 state 主题里看到。串口日志 [NET] alert W-0x ... 只出现在 USB-CDC 应用日志口,COM4(UART0) 上只有 ESP-ROM/IDF 日志。

GET /api/settings

{
  "wifiEnabled": true, "mqttEnabled": false, "mqttBroker": "",
  "mqttPort": 1883, "mqttTopicPrefix": "chamber",
  "ntpEnabled": true, "otaEnabled": true,
  "timezone": "CST-8", "ntpServer1": "ntp.aliyun.com",
  "ntpServer2": "pool.ntp.org", "staticIpEnabled": false,
  "staticIp": "192.168.1.50", "staticGateway": "192.168.1.1",
  "staticSubnet": "255.255.255.0", "staticDns1": "223.5.5.5",
  "staticDns2": "1.1.1.1", "otaPassword": "CH-XXXXXXXXXXXX",
  "heaterMaxCurrentA": 6, "heaterFanPercent": 100, "heaterBoardLimitC": 150,
  "brightness": 80, "rgbMaxBrightness": 100, "rgbFollowScreenSleep": false,
  "language": "zh"
}

POST /api/settings

表单编码。只覆盖请求中出现的字段,未提交的保持原值。写入 NVS 后调用 onSettingsChanged() 立即重配。

字段 取值
mqttEnabled 1/0、true/false、on/off
mqttBroker 主机名或 IP,最长 63 字符
mqttPort 1–65535
mqttTopicPrefix 最长 23 字符
ntpEnabled / otaEnabled 同上布尔写法
language zh、cn 或 en
brightness / rgbMaxBrightness 1–100(RGB 最大亮度对 4 颗状态灯统一缩放)
rgbFollowScreenSleep 1/0 或 true/false(屏幕休眠时 RGB 同步熄灭)
heaterMaxCurrentA 1–12 A
heaterFanPercent 20–100 %
heaterBoardLimitC 40–180 ℃
timezone POSIX TZ,如中国 CST-8、UTC UTC0
ntpServer1 / ntpServer2 NTP 主机名
staticIpEnabled 是否使用静态 IPv4
staticIp / staticGateway / staticSubnet 静态地址、网关和掩码
staticDns1 / staticDns2 DNS 地址
# 打开 MQTT 并指向局域网 broker
curl -X POST http://192.168.1.50/api/settings -d "mqttEnabled=1&mqttBroker=192.168.1.10&mqttPort=1883&mqttTopicPrefix=chamber"

# 切换英文
curl -X POST http://192.168.1.50/api/settings -d "language=en"

wifiEnabled=0 会被拒绝并返回 400。该接口本身走网络,关掉 WiFi 等于自断 通道,因此只能在屏幕设置页或串口操作。

成功返回 {"ok":true},参数非法返回 400 带 err 说明。

触摸模式、触摸校准、注册码刻意不开放远程接口:这些都是本地交互配置,远程改错 一旦生效(例如把触摸关掉、写错注册码),远端就再也没法改回来了。

POST /api/action

curl -X POST http://192.168.1.50/api/action -d "name=toggleLight"

可用 name 与界面按钮一一对应:

name 作用
toggleSystem 系统启停
togglePreheat 提前预热
toggleLight 灯光
toggleManualExhaust 手动强排
prevMaterial / nextMaterial 切换耗材
toggleAutoExhaust 自动排气
toggleAutoTemp 自动恒温
togglePostExhaust 打印结束排气

POST /api/profile

修改当前耗材预设。index 为必填的耗材序号(0–11),其余字段可省略,省略时 沿用当前值。

curl -X POST http://192.168.1.50/api/profile -d "index=0&minC=0&maxC=40&fanMin=30&fanMax=100&postFan=100&postSeconds=180"

约束:minC 0–90、maxC ≥ minC+5 且 ≤ 100、风速 0–100、 postSeconds 0–1800。越界返回 400。校验通过后立即持久化到 NVS。

POST /api/wifi/reset

清空 WiFi 凭据并重启,见上文。

MQTT

默认关闭(mqttEnabled = false),需在设置页或 POST /api/settings 打开并 填写 broker 地址。

主题

前缀取自 mqttTopicPrefix,默认 chamber。

主题 方向 载荷 QoS / retain
<前缀>/state 发布 同 GET /api/state 的 JSON QoS 0 / retain
<前缀>/event 发布 {"event":"<名称>"} QoS 0 / 不 retain
<前缀>/online 发布 上线 "1";异常离线由 LWT 发布 "0" QoS 1 / retain
<前缀>/cmd 订阅 见下文 —

state 每 5 秒上报一次并 retain,新订阅者能立刻拿到最后状态。

event 在状态机跃迁时上报(载荷为 Idle/Preheat/Printing 等 state 名), 也在下发命令成功和 MQTT 上线时上报。进入故障时载荷改为 Fault F-0x <故障码名>(如 Fault F-03 BoardOverTemp),比只报一个 Fault 更能直接指导排查。

命令

{"action": "toggleLight"}
{"profile": 3}

action 的取值同 /api/action 的 name。profile 为耗材序号。执行成功后会 在该主题回发一条 event。

mosquitto_pub -h 192.168.1.10 -t chamber/cmd -m '{"action":"togglePreheat"}'
mosquitto_sub -h 192.168.1.10 -t 'chamber/#' -v

重连

broker 不可达时每 5 秒重试一次,同一节流器也用于 state 周期上报。 mqttBroker、mqttPort、mqttEnabled 任一变化都会断开重连。 为保护 50 ms 温控节拍,预热/打印或加热输出不为零时不会发起可能阻塞的 MQTT TCP 重连;温控停止后再恢复连接。单次 MQTT socket 等待上限为 1 秒。

NTP 校时

configTzTime(timezone, ntpServer1, ntpServer2);

默认使用 CST-8(UTC+8),时区和两个 NTP 服务器均可在 Web 管理页配置。采用 POSIX TZ 语法,例如 UTC 使用 UTC0。同步成功后主界面显示完整时间。

断网时的回退顺序:NTP → 上次手动校时(manualClockEpoch)→ 占位串 ----/--/-- --:--:--。手动校时在设置页的「日期」「时间」两项完成,写入 RTC 与 NVS,重启后仍生效。

关闭 NTP 会调用 esp_sntp_stop(),已同步的时钟在断电前继续保持。

OTA 升级

主机名 chamber。设备 ID / OTA 密码由 ESP32 芯片 eFuse 内 48 位 MAC 生成,格式为 CH-XXXXXXXXXXXX(12 位十六进制),可在 Web 管理页查看,也会在启动串口日志中打印。

MAC 由 IEEE 逐颗分配、天然唯一;固件对该 48 位做整宽异或(双射、不丢位),因此 任意两颗芯片得到的 ID 必然不同,逐机唯一、不会重复(早期的 8 位版本把 64 位 折叠成 32 位,理论上存在碰撞)。

  • Arduino IDE:工具 → 端口 → 选择 chamber
  • PlatformIO:需显式指定 espota 协议,因为 platformio.ini 未配置 upload_protocol,默认走串口 esptool
pio run -t upload --upload-port chamber.local --upload-protocol espota

若上面这条不便使用,也可在 platformio.ini 的 [env:esp32-s3-n16r8] 中加 upload_protocol = espota 与 upload_port = chamber.local 固化下来。

前提是 board_build.partitions 指定的分区表带 app0/app1 双槽,详见 编译烧录与预编译固件。

OTA 开始时会自动关闭加热(controller_->setSystemEnabled(false)),因为刷写 期间 PID 节拍会失步,必须切断加热保证安全。升级完成后需手动重新启动系统。

关闭 OTA 会调用 ArduinoOTA.end(),之后该设备不再出现在 OTA 端口列表中。已停 的 OTA 无法远程重新打开(通道已断),只能回设置页或重启。

mDNS

STA 连上后注册 chamber.local,因此可以用主机名代替 IP 访问:

http://chamber.local/api/state

Windows 需安装 Bonjour(装过 iTunes 即有)。解析失败时改用 IP。

状态与串口调试

NetState 五态:Off(WiFi 关闭)、Connecting、Connected、ConfigPortal、 MqttConnected。

串口按 W 打印当前联网配置(读 main 侧的 settings 拷贝)。关键日志前缀: [NET]、[MQTT]、[NTP]、[OTA]、[FAULT]。

串口日志分流(排障必读):platformio.ini 的 -DARDUINO_USB_CDC_ON_BOOT=1 让 Arduino Serial 走 S3 原生 USB-CDC(板载 USB 口);FTDI → COM4(UART0) 只剩 ESP-ROM 与 ESP-IDF 日志(entry 0x、[E][Preferences.cpp] 等)。 所以在 COM4 看不到 chamber= 周期上报、AHT20 打印属正常现象,不代表设备卡死。 判据:只看 COM4 时,出现 entry 0x 即为正常启动。

已知限制

  • 只支持 2.4 GHz WiFi。
  • 未做 HTTPS/TLS:REST 无鉴权,MQTT 无账号密码;OTA 已使用每台设备独立密码。 不要暴露到公网,仅限可信局域网使用。
  • GET /api/settings 会把 mqttBroker 明文返回,无脱敏。
  • 屏幕设置页只暴露联网开关;MQTT、NTP、时区和静态 IP 的文本参数在 Web 管理页配置。
⚠️ **GitHub.com Fallback** ⚠️