130	    "button{width:100%;height:48px;border:none;border-radius:24px;font-size:15px;font-weight:600;color:#fff;background:var(--color-primary);box-shadow:0 2px 6px rgba(18,168,137,0.2);cursor:pointer;transition:transform 0.15s,opacity 0.15s;font-family:inherit;}"
131	    "button:active{transform:scale(0.98);opacity:0.92;}"
132	    "button.secondary{background:var(--color-bg-hover);color:var(--color-text-secondary);box-shadow:none;}"
133	    "button.danger{background:#fff;color:var(--color-error);border:1px solid #ffd6d6;box-shadow:none;}"
134	    ".footer{text-align:center;font-size:11px;color:var(--color-text-tertiary);padding:20px 0 6px;}"
135	    ".modalMask{position:fixed;inset:0;background:rgba(15,31,28,0.55);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity 0.25s ease,visibility 0.25s ease;z-index:100;padding:20px;}"
136	    ".modalMask.show{opacity:1;visibility:visible;}"
137	    ".modal{width:100%;max-width:360px;background:#fff;border-radius:20px;padding:24px 22px 18px;transform:scale(0.85) translateY(20px);opacity:0;transition:transform 0.3s cubic-bezier(0.34,1.56,0.64,1),opacity 0.25s ease;box-shadow:0 12px 40px rgba(0,0,0,0.2);max-height:80vh;overflow-y:auto;}"
138	    ".modalMask.show .modal{transform:scale(1) translateY(0);opacity:1;}"
139	    ".modalHeader{display:flex;align-items:center;gap:12px;padding-bottom:18px;border-bottom:1px solid var(--color-divider);}"
140	    ".modalHeaderIcon{width:40px;height:40px;border-radius:12px;background:var(--color-card-green);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;}"
141	    ".modalHeaderText{flex:1;}"
142	    ".modalTitle{font-size:16px;font-weight:700;color:var(--color-text-primary);}"
143	    ".modalSub{font-size:12px;color:var(--color-text-tertiary);margin-top:2px;}"
144	    ".modalClose{width:28px;height:28px;border-radius:50%;background:var(--color-bg-hover);color:var(--color-text-tertiary);font-size:16px;display:flex;align-items:center;justify-content:center;cursor:pointer;}"
145	    ".modalSteps{display:flex;flex-direction:column;gap:12px;padding:20px 0 22px;}"
146	    ".modalStep{display:flex;align-items:flex-start;gap:14px;padding:12px;border-radius:12px;background:var(--color-bg-hover);}"
147	    ".modalStepNum{width:30px;height:30px;border-radius:50%;background:var(--color-primary);color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;}"
148	    ".modalStepContent{flex:1;}"
149	    ".modalStepTitle{font-size:14px;font-weight:600;color:var(--color-text-primary);}"
150	    ".modalStepDesc{font-size:12px;color:var(--color-text-tertiary);margin-top:3px;line-height:1.6;}"
151	    ".modalFooter{display:flex;gap:10px;padding-top:6px;border-top:1px solid var(--color-divider);padding-top:14px;}"
152	    ".modalFooter button{flex:1;height:42px;font-size:14px;}"
153	    ".modalFooter button.primary{background:var(--color-primary);color:#fff;}"
154	    ".modalFooter button.ghost{background:var(--color-bg-hover);color:var(--color-text-secondary);}"
155	    ".guideTip{position:absolute;top:60px;right:0;transform:translateY(-8px) scale(0.9);transform-origin:top right;background:var(--color-primary);color:#fff;font-size:12px;padding:8px 14px;border-radius:999px;box-shadow:0 4px 12px rgba(18,168,137,0.35);opacity:0;transition:opacity 0.3s ease,transform 0.3s ease;z-index:6;pointer-events:none;white-space:nowrap;}"
156	    ".guideTip::after{content:'';position:absolute;top:-5px;right:12px;width:10px;height:10px;background:var(--color-primary);transform:rotate(45deg);}"
157	    ".guideTip.show{opacity:1;transform:translateY(0) scale(1);}"
158	    "@media(prefers-color-scheme:dark){body{background:#0f1f1c;color:#e6f0ee;}.card{background:#182b27;box-shadow:0 2px 12px rgba(0,0,0,0.4);}.cardHeaderIcon,.modalStep,.inputWrap{background:#1f3530;}.inputWrap:focus-within{background:#243d38;border-color:var(--color-primary-light);}label{color:#a8bdb8;}h1{color:#e6f0ee;}.gateInfo{background:#143530;}button.secondary{background:#1f3530;color:#a8bdb8;}button.danger{background:#2a1a1a;color:#ff8a8a;border-color:#5a2828;}.modal{background:#182b27;}.modalHeader{border-bottom-color:#243d38;}.modalFooter{border-top-color:#243d38;}.modalClose{background:#1f3530;color:#a8bdb8;}}"
159	    "</style>");
160	    _wm.setCustomHeadElement(customHead.c_str());
161	    }
162
163	    // ====================== 2. Body页面结构 + JS弹窗 ======================
164	    {
165	    String customBody = F(
166	    "
"
167	    "
"
168	    "
📡
"
169	    "

观照-五劳无感 · 设备配网

WiFi 联网与参数配置

"
170	    "
?
"
171	    "
点击这里再次查看配网流程
"
172	    "
"
173	    "
📍 当前网关Gateway_A8F3
"
174	    "
"
175	    "

📶

无线网络

请选择 2.4GHz WiFi

"
176	    "
WiFi 名称
📡<select></select>

"
177	    "
WiFi 密码
🔒<input type='password' placeholder='请输入 WiFi 密码'>

"
178	    "
"
179	    "
"
180	    "

⚙

设备基础信息

唯一标识与安装位置

"
181	    "
🔖 设备编号
#<input type='text' name='device_id' placeholder='Device_001'>

"
182	    "
📍 安装环境
🏠<input type='text' name='env_note' placeholder='如: 主卧 / 客厅 / 老人房'>

"
183	    "
"
184	    "
"

"button{width:100%;height:48px;border:none;border-radius:24px;font-size:15px;font-weight:600;color:#fff;background:var(--color-primary);box-shadow:0 2px 6px rgba(18,168,137,0.2);cursor:pointer;transition:transform 0.15s,opacity 0.15s;font-family:inherit;}"
    "button:active{transform:scale(0.98);opacity:0.92;}"
    "button.secondary{background:var(--color-bg-hover);color:var(--color-text-secondary);box-shadow:none;}"
    "button.danger{background:#fff;color:var(--color-error);border:1px solid #ffd6d6;box-shadow:none;}"
    ".footer{text-align:center;font-size:11px;color:var(--color-text-tertiary);padding:20px 0 6px;}"
    ".modalMask{position:fixed;inset:0;background:rgba(15,31,28,0.55);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity 0.25s ease,visibility 0.25s ease;z-index:100;padding:20px;}"
    ".modalMask.show{opacity:1;visibility:visible;}"
    ".modal{width:100%;max-width:360px;background:#fff;border-radius:20px;padding:24px 22px 18px;transform:scale(0.85) translateY(20px);opacity:0;transition:transform 0.3s cubic-bezier(0.34,1.56,0.64,1),opacity 0.25s ease;box-shadow:0 12px 40px rgba(0,0,0,0.2);max-height:80vh;overflow-y:auto;}"
    ".modalMask.show .modal{transform:scale(1) translateY(0);opacity:1;}"
    ".modalHeader{display:flex;align-items:center;gap:12px;padding-bottom:18px;border-bottom:1px solid var(--color-divider);}"
    ".modalHeaderIcon{width:40px;height:40px;border-radius:12px;background:var(--color-card-green);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;}"
    ".modalHeaderText{flex:1;}"
    ".modalTitle{font-size:16px;font-weight:700;color:var(--color-text-primary);}"
    ".modalSub{font-size:12px;color:var(--color-text-tertiary);margin-top:2px;}"
    ".modalClose{width:28px;height:28px;border-radius:50%;background:var(--color-bg-hover);color:var(--color-text-tertiary);font-size:16px;display:flex;align-items:center;justify-content:center;cursor:pointer;}"
    ".modalSteps{display:flex;flex-direction:column;gap:12px;padding:20px 0 22px;}"
    ".modalStep{display:flex;align-items:flex-start;gap:14px;padding:12px;border-radius:12px;background:var(--color-bg-hover);}"
    ".modalStepNum{width:30px;height:30px;border-radius:50%;background:var(--color-primary);color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;}"
    ".modalStepContent{flex:1;}"
    ".modalStepTitle{font-size:14px;font-weight:600;color:var(--color-text-primary);}"
    ".modalStepDesc{font-size:12px;color:var(--color-text-tertiary);margin-top:3px;line-height:1.6;}"
    ".modalFooter{display:flex;gap:10px;padding-top:6px;border-top:1px solid var(--color-divider);padding-top:14px;}"
    ".modalFooter button{flex:1;height:42px;font-size:14px;}"
    ".modalFooter button.primary{background:var(--color-primary);color:#fff;}"
    ".modalFooter button.ghost{background:var(--color-bg-hover);color:var(--color-text-secondary);}"
    ".guideTip{position:absolute;top:60px;right:0;transform:translateY(-8px) scale(0.9);transform-origin:top right;background:var(--color-primary);color:#fff;font-size:12px;padding:8px 14px;border-radius:999px;box-shadow:0 4px 12px rgba(18,168,137,0.35);opacity:0;transition:opacity 0.3s ease,transform 0.3s ease;z-index:6;pointer-events:none;white-space:nowrap;}"
    ".guideTip::after{content:'';position:absolute;top:-5px;right:12px;width:10px;height:10px;background:var(--color-primary);transform:rotate(45deg);}"
    ".guideTip.show{opacity:1;transform:translateY(0) scale(1);}"
    "@media(prefers-color-scheme:dark){body{background:#0f1f1c;color:#e6f0ee;}.card{background:#182b27;box-shadow:0 2px 12px rgba(0,0,0,0.4);}.cardHeaderIcon,.modalStep,.inputWrap{background:#1f3530;}.inputWrap:focus-within{background:#243d38;border-color:var(--color-primary-light);}label{color:#a8bdb8;}h1{color:#e6f0ee;}.gateInfo{background:#143530;}button.secondary{background:#1f3530;color:#a8bdb8;}button.danger{background:#2a1a1a;color:#ff8a8a;border-color:#5a2828;}.modal{background:#182b27;}.modalHeader{border-bottom-color:#243d38;}.modalFooter{border-top-color:#243d38;}.modalClose{background:#1f3530;color:#a8bdb8;}}"
    "</style>");
    _wm.setCustomHeadElement(customHead.c_str());
    }

    // ====================== 2. Body页面结构 + JS弹窗 ======================
    {
    String customBody = F(
    "
"
    "
"
    "
📡
"
    "

观照-五劳无感 · 设备配网

WiFi 联网与参数配置

"
    "
?
"
    "
点击这里再次查看配网流程
"
    "
"
    "
📍 当前网关Gateway_A8F3
"
    "
"
    "

📶

无线网络

请选择 2.4GHz WiFi

"
    "
WiFi 名称
📡<select></select>

"
    "
WiFi 密码
🔒<input type='password' placeholder='请输入 WiFi 密码'>

"
    "
"
    "
"
    "

⚙

设备基础信息

唯一标识与安装位置

"
    "
🔖 设备编号
#<input type='text' name='device_id' placeholder='Device_001'>

"
    "
📍 安装环境
🏠<input type='text' name='env_note' placeholder='如: 主卧 / 客厅 / 老人房'>

"
    "
"
    "
"


The code looks correct and matches the file exactly. Let me also verify the _connectWiFi function still handles MQTT params correctly since we kept those objects but don't register them.


现在和文件里的设计完全一致：CSS、HTML body、JS 弹窗、参数、回调，全部原样照搬。`Gateway_A8F3` 也按文件硬编码保留。可以编译烧录了。


系统，一直重新启动，


The user is saying the system keeps rebooting/restarting continuously. This is likely caused by a crash or watchdog reset. Let me think about what could be causing this after the recent changes.

The most likely cause is the `F()` macro wrapping the long strings in `setCustomHeadElement` and `setCustomMenuHTML`. The `F()` macro stores strings in PROGMEM (flash), but `String` constructor from `F()` might have issues on ESP32, or the `F()` macro might be causing memory corruption because the strings are very long.

Actually, looking more carefully at the code I just wrote:

```cpp
String customHead = F("<meta name='theme-color'...");
```

This is problematic! The `F()` macro returns a `__FlashStringHelper*` which is meant for direct use with `Serial.print()` etc. Converting it to `String` might work but it's unreliable, especially for very long strings. The `F()` macro is designed for `Serial.print(F("..."))` - it doesn't allocate RAM. But when you assign it to String, it might try to copy from flash which could cause issues.

Actually, on ESP32, `String(F("..."))` does work because the String class has a constructor that handles `__FlashStringHelper*`. But the issue might be something else.

Wait, let me think about what other changes could cause constant reboots:

1. `_wm.setSaveParamsCallback(_saveParamsCallback)` - This replaced `setSaveConfigCallback`. In WiFiManager, when the main WiFi form is submitted, `saveConfigCallback` fires, not `saveParamsCallback`. If `saveConfigCallback` is not set, it might crash or behave unexpectedly.

Actually that's unlikely to cause a reboot. More likely causes:

2. The `F()` macro with String assignment - this is the most suspicious change. On ESP32, very long flash strings assigned to String can cause stack overflow or memory issues.

3. Maybe the `_param_mqtt_server` etc. objects are now uninitialized (we removed the `new` allocations for them but the `_connectWiFi()` code still calls `->setValue()` on them. Wait, did I remove them? Let me check...

Looking at my edit, I removed the MQTT parameter creation. But `_connectWiFi()` at line 375-378 calls:
```cpp
_param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));
_param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));
_param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));
_param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));
```

These pointers are now `nullptr` (initialized in the constructor), so calling `->setValue()` on them will cause a null pointer exception → reboot!

That's the problem! I removed the MQTT param allocations but the `_connectWiFi()` function still tries to use them.

Let me fix this by either:
1. Adding back the MQTT param allocations (just don't addParameter them)
2. Or wrapping the sync code with null checks
3. Or removing the sync code for MQTT params

Option 1 is safest.


你手里有人体红外传感器吗


没有


The system keeps rebooting. This could be caused by many things - watchdog timer, power supply issues, null pointer dereference, stack overflow, etc. Let me think about what recent changes could cause this...

The most likely cause from recent changes is the `setSaveParamsCallback` vs `setSaveConfigCallback` issue. In WiFiManager, when using `autoConnect()`:
- The WiFi config page (`/wifi`) includes both WiFi fields and custom parameters
- When the user submits, the POST goes to `/wifisave` which triggers `setSaveConfigCallback`
- `setSaveParamsCallback` is only triggered when the separate params page (`/param`) is submitted

If we use `setSaveParamsCallback` instead of `setSaveConfigCallback`, the callback might not fire at all, or WiFiManager might behave unexpectedly.

But more importantly, the system REBOOTING continuously suggests something more severe - like a watchdog timeout, stack overflow, or null pointer crash.

Let me think about what other issues could cause constant reboots:

1. The `F()` macro returns a `__FlashStringHelper*` which is a special type in Arduino. `WiFiManager::setCustomHeadElement()` expects `const char*`, not `__FlashStringHelper*`. Calling `.c_str()` on a String constructed with `F()` might cause undefined behavior or the String might not properly copy the flash string.

Wait, actually: `String customHead = F("...")` - this creates a String from a flash string. The `String` constructor should handle this correctly by copying from flash to RAM. Then `customHead.c_str()` returns a `const char*` to the RAM copy. This should be fine.

2. But there's another issue: the HTML/CSS strings are very long (>3000 chars). The String object with `F()` might exceed available stack or heap, causing a crash.

3. Or perhaps the issue is simpler - the `_connectWiFi()` function still references `_param_mqtt_server`, `_param_mqtt_port`, `_param_mqtt_user`, `_param_mqtt_pass` for `setValue()`. But we removed the `new` allocation of these objects from `begin()`! Let me check...

Wait, I removed the MQTT params creation. Let me check the current `begin()` code.

Looking at the edit I made, I removed the MQTT param creation:
```
_param_device_id = new WiFiManagerParameter(...)
_param_env_note = new WiFiManagerParameter(...)
_wm.addParameter(_param_device_id);
_wm.addParameter(_param_env_note);
```

There's no more `_param_mqtt_server = new ...` etc. But the `_connectWiFi()` function (line 359-390) still tries to use them:
```cpp
_param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));
_param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));
_param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));
_param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));
```

These are NULL pointers now → crash → reboot!

But wait, the constructor initializes them to nullptr:
```cpp
WiFiMgmt::WiFiMgmt()
    : ...
    , _param_mqtt_server(nullptr)
    , _param_mqtt_port(nullptr)
    , _param_mqtt_user(nullptr)
    , _param_mqtt_pass(nullptr)
    ...
```

So `_param_mqtt_server->setValue(...)` dereferences a nullptr → immediate crash → reboot!

This is the cause of the reboot loop. I need to fix the `_connectWiFi()` function to guard against null pointers.

Also, the `_saveParamsCallback` no longer reads MQTT params (which is correct since they're not on the page), but the `_connectWiFi` function still tries to sync them.

Let me fix this.


找到原因了。`_connectWiFi()` 里还在调 `_param_mqtt_server->setValue()`，但这些对象在 `begin()` 里被我移除了（nullptr 解引用 → 崩溃 → 重启）。


335
336	void WiFiMgmt::_emitProvisionState(const char* state) {
337	    Serial.printf("[WiFi] 📡 配网状态: %s\n", state);
338	    if (_provisionStateCb) {
339	        _provisionStateCb(state);
340	    }
341	}
342
343	// ============================================================
344	// 配网页面
345	// ============================================================
346
347	void WiFiMgmt::startConfigPortal() {
348	    Serial.println(F("[WiFi] 🔧 手动启动配网页面..."));
349	    _emitProvisionState("ready");  // 协议 §4.4: 进入配网模式
350	    _setLEDMode(1);
351	    _startLEDTask(300);  // 快闪
352	    _wm.startConfigPortal(WIFI_AP_SSID, WIFI_AP_PASSWORD);
353	    _stopLEDTask();
354	    _connected = (WiFi.status() == WL_CONNECTED);
355	    if (_connected) {
356	        _setLEDMode(2);
357	        _emitProvisionState("success");  // 协议 §4.4: 配网成功
358	    }
359	}
360
361	// ============================================================
362	// 重置设置
363	// ============================================================
364

void WiFiMgmt::_emitProvisionState(const char* state) {
    Serial.printf("[WiFi] 📡 配网状态: %s\n", state);
    if (_provisionStateCb) {
        _provisionStateCb(state);
    }
}

// ============================================================
// 配网页面
// ============================================================

void WiFiMgmt::startConfigPortal() {
    Serial.println(F("[WiFi] 🔧 手动启动配网页面..."));
    _emitProvisionState("ready");  // 协议 §4.4: 进入配网模式
    _setLEDMode(1);
    _startLEDTask(300);  // 快闪
    _wm.startConfigPortal(WIFI_AP_SSID, WIFI_AP_PASSWORD);
    _stopLEDTask();
    _connected = (WiFi.status() == WL_CONNECTED);
    if (_connected) {
        _setLEDMode(2);
        _emitProvisionState("success");  // 协议 §4.4: 配网成功
    }
}

// ============================================================
// 重置设置
// ============================================================


Let me search for the _connectWiFi function that has the problematic MQTT param sync code.


24:    , _param_mqtt_server(nullptr)
25:    , _param_mqtt_port(nullptr)
26:    , _param_mqtt_user(nullptr)
27:    , _param_mqtt_pass(nullptr)
309:        _param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));
310:        _param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));
311:        _param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));
312:        _param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));


烧录完就一直重启


Found it. Lines 309-312 in `_connectWiFi()` are calling `setValue()` on null pointers. Let me fix this by adding null guards.


就是 309-312 行，`_param_mqtt_server` 等全都是 `nullptr`，一调用就崩。


Edit

        // 同步自定义参数 (如果配置是从 LittleFS 加载的)
        _param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));
        _param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));
        _param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));
        _param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));
        _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));
        _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));

        // 同步自定义参数 (只同步页面上显示的参数)
        if (_param_device_id) _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));
        if (_param_env_note)  _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));


The file d:\PlatformIO1\Projects\Healthv2.0\src\wifi_manager.cpp has been updated successfully. (file state is current in your context — no need to Read it back)

        // 同步自定义参数 (如果配置是从 LittleFS 加载的)
        _param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));
        _param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));
        _param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));
        _param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));
        _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));
        _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));

        // 同步自定义参数 (只同步页面上显示的参数)
        if (_param_device_id) _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));
        if (_param_env_note)  _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));

-        // 同步自定义参数 (如果配置是从 LittleFS 加载的)

-        _param_mqtt_server->setValue(_config.mqtt_server, sizeof(_config.mqtt_server));

-        _param_mqtt_port->setValue(_config.mqtt_port, sizeof(_config.mqtt_port));

-        _param_mqtt_user->setValue(_config.mqtt_user, sizeof(_config.mqtt_user));

-        _param_mqtt_pass->setValue(_config.mqtt_pass, sizeof(_config.mqtt_pass));

-        _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));

-        _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));

+        // 同步自定义参数 (只同步页面上显示的参数)

+        if (_param_device_id) _param_device_id->setValue(_config.device_id, sizeof(_config.device_id));

+        if (_param_env_note)  _param_env_note->setValue(_config.env_note, sizeof(_config.env_note));

Serial.printf("  设备名: %s\n", _config.device_id);

Serial.printf("  环境:   %s\n", _config.env_note);


等等，软件组给的硬编码是 Gateway_A8F3，这应该是改成读取实际设备编号。

Now it should stop crashing. But wait, I should also check the _connectWiFi serial printf lines - they reference `_config.mqtt_server` and `_config.mqtt_port` which are fine since they're in the config struct, not pointers.

Let me also check around line 309 for context.


修好了。`_param_mqtt_server` 等 4 个指针在 `begin()` 里没创建，但 `_connectWiFi()` 还在调它们——空指针直接崩。

现在加了空指针保护，只同步页面上实际显示的 `device_id` 和 `env_note` 两个参数。重新烧录试试。


为啥和网页的不一样


The user is comparing the actual web page shown in the WiFiManager captive portal with what the HTML in the code should produce. They're seeing differences and want to know why.

The key issue is that WiFiManager generates its own HTML structure for the WiFi configuration page (`/wifi`), and our custom HTML only goes to the root page (`/`). The custom body HTML with WiFi SSID select, password input, and device info fields is placed on the root page via `setCustomMenuHTML()`, but the actual WiFi configuration form is generated by WiFiManager on a separate `/wifi` page.

So the user sees the WiFiManager-generated form on `/wifi` which has:
- WiFiManager's default HTML structure
- Our custom CSS styling applied
- Our 2 custom parameters (device_id, env_note) appended to the form

But NOT our custom card-based layout with the WiFi fields inline.

The root page (`/`) would show:
- WiFiManager's default menu
- Our custom header + gateway info + modal

The WiFi config page (`/wifi`) would show:
- WiFiManager's own form (with its own HTML structure)
- Our custom parameters appended at the bottom
- Our CSS styling

So the user's beautiful card-based design doesn't actually show on the WiFi config page where the user fills in WiFi credentials. The design with the "无线网络" card and "设备基础信息" card only appears on the root page.

This is a fundamental limitation of WiFiManager - we can't replace the WiFi config page's HTML structure, only style it with CSS.

Let me explain this to the user.


因为你的代码里 HTML 是放在 `setCustomMenuHTML()` 里的，这个方法只把内容加到 **首页** (`/`)，不是 WiFi 配置页 (`/wifi`)。

实际流程是：

```
手机连 AP → 弹 captive portal → 自动跳转 /wifi 页面
                                    ↑
                                    └── WiFiManager 自己生成的表单
                                        (我们的卡片设计不在这里)
```

你看到的 `/wifi` 页面是 WiFiManager 库自己拼的 HTML，只有 CSS 会生效（你设的绿色主题、圆角、按钮样式是对的），但页面结构是库的默认结构。

**首页** `/` 才能看到你的卡片设计（header、网关信息、弹窗），但用户配网根本不会经过首页——captive portal 直接跳 `/wifi`。


那我该怎么修改成那样，配网界面


The user wants the WiFi configuration page (`/wifi`) to look like their designed interface, not just the root page (`/`).

The problem is that WiFiManager generates its own HTML for the `/wifi` page. We can't replace it with `setCustomMenuHTML` (which only affects `/`).

There are a few approaches:

1. **Modify the WiFiManager library's `wm_strings_zh.h` directly** - Replace the HTML fragments in the library to match the design. This is the most thorough approach but modifies the library.

2. **Overwrite the WiFiManager's internal page handler** - Complex, requires subclassing.

3. **The simplest approach**: WiFiManager has a function `setCustomHeadElement()` which injects into `<head>` (CSS already working). But the body HTML is hardcoded in the library.

Actually wait - WiFiManager also has `setCustomMenuHTML()` which adds to the root page, but there's no equivalent for the WiFi page.

Let me think about what WiFiManager actually generates for `/wifi`:
- It uses `HTTP_FORM_START`, `HTTP_FORM_WIFI`, `HTTP_FORM_PARAM`, etc. from `wm_strings_zh.h`
- These are all `PROGMEM` strings in the library
- Then it appends custom parameters

The most practical approach for this project is to **directly modify the WiFiManager library's `wm_strings_zh.h`** file to change the HTML template strings. This is in `.pio/libdeps/esp32-s3-devkitc-1/WiFiManager/`.

But wait - PlatformIO library modifications get overwritten when you update libraries. However, since the user controls the project, this is a practical solution.

Actually, a BETTER approach: WiFiManager has a method called `setCustomHeadElement` which works. And on the `/wifi` page, WiFiManager:
1. Generates the SSID scan list
2. Generates the password field
3. Appends custom parameters

The body structure IS generated by WiFiManager. The CSS styling applies, but the DOM structure is different from what the software team designed.

Let me think of another way... WiFiManager's `handleWifi()` function (in WiFiManager.cpp) builds the page by concatenating PROGMEM strings. We could:

1. **Modify `wm_strings_zh.h`** to change the HTML structure to match the design
2. The SSID list is dynamically generated in a loop - we can't change that easily
3. The form fields (SSID select, password input) are generated by WiFiManager

Actually, looking at the software team's design more carefully, their body HTML has:
- A WiFi card with `<select>` for SSID and `<input type='password'>` for password
- A device info card with device_id and env_note inputs

This ALMOST matches what WiFiManager generates! WiFiManager generates:
- WiFi SSID list (as clickable links or select)
- Password input
- Custom parameters at the bottom

The key difference is the HTML structure. Let me modify `wm_strings_zh.h` to change the generated HTML structure to match the design.

But actually, the SIMPLEST approach that requires the least library modification: just modify the CSS to style WiFiManager's default output to LOOK like the design, and modify the key HTML string templates in `wm_strings_zh.h` to add the wrapper divs and cards.

Actually, let me take a different approach. WiFiManager allows us to completely CUSTOMIZE the page behavior by:

1. Keeping the CSS that styles everything
2. Modifying `wm_strings_zh.h` to change the HTML structure
3. The key strings to modify:
   - `HTTP_HEAD_START` - adds header card
   - `HTTP_FORM_START` - form start
   - `HTTP_FORM_WIFI` - WiFi fields with card wrapper
   - `HTTP_FORM_PARAM` - param fields
   - `HTTP_FORM_END` - submit button + footer
   - `HTTP_END` - close wrappers + modal + script

Let me do this. I'll modify `wm_strings_zh.h` to wrap the WiFi form in the card design, add the header, gateway info, modal, etc.

Wait, but the user said the software team designed this and wants it exactly as-is. The problem is that WiFiManager generates the page structure, and the custom body HTML only appears on the root page `/`, not on `/wifi`.

The REAL solution is to modify `wm_strings_zh.h` to match the design structure. Let me craft the modified version.

Looking at WiFiManager's `handleWifi()` function flow:
1. `HTTP_HEAD_START` - page start
2. `HTTP_SCRIPT` - JS functions
3. `HTTP_STYLE` - CSS (overridden by our setCustomHeadElement)
4. `HTTP_HEAD_END` - body start
5. Title h1, h3
6. WiFi SSID list items
7. `HTTP_FORM_START`
8. `HTTP_FORM_WIFI` - SSID + password fields
9. Custom parameter HTML (generated from WiFiManagerParameter labels)
10. `HTTP_FORM_END` - submit button
11. `HTTP_END` - close

So if I modify `HTTP_HEAD_END` to include the header card and gateway info, and modify `HTTP_FORM_WIFI` to wrap in card divs, and modify `HTTP_FORM_END` to include the button group, and modify `HTTP_END` to include modal + script... it can work!

But this is extensive modification of the library. Let me think about what's the minimum change to achieve the look.

Actually, the MOST practical approach: edit `wm_strings_zh.h` to:
1. Add the header + gateway card in `HTTP_HEAD_END`
2. Wrap WiFi fields in card div
3. Wrap params in card div
4. Fix `HTTP_FORM_END` to use the designed buttons
5. Add modal and script to `HTTP_END`

Let me do this now. This is a targeted library modification.


明白了——`/wifi` 页面是 WiFiManager 库自己生成的，我们的卡片 HTML 只在首页 `/`。要改 WiFi 配置页，得直接改库的 HTML 模板。


1	/**
2	 * wm_strings_zh.h
3	 * 中文语言包 for WiFiManager
4	 * 基于 wm_strings_en.h 翻译
5	 *
6	 * WiFiManager, a library for the ESP8266/Arduino platform
7	 * for configuration of WiFi credentials using a Captive Portal
8	 *
9	 * @author Creator tzapu
10	 * @author tablatronix
11	 * @version 0.0.0
12	 * @license MIT
13	 */
14
15	#ifndef _WM_STRINGS_ZH_H_
16	#define _WM_STRINGS_ZH_H_
17
18	// strings files must include a consts file!
19	#include "wm_consts_en.h" // include constants, tokens, routes
20
21	const char WM_LANGUAGE[] PROGMEM = "zh-CN"; // i18n lang code
22
23	const char HTTP_HEAD_START[]       PROGMEM = "<!DOCTYPE html>"
24	""
25	"<meta name='format-detection' content='telephone=no'>"
26	"<meta charset='UTF-8'>"
27	"<meta  name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
28	"<title>{v}</title>";
29
30	const char HTTP_SCRIPT[]           PROGMEM = "";
37
38	const char HTTP_HEAD_END[]         PROGMEM = "
"; // {c} = _bodyclass
39
40	const char HTTP_ROOT_MAIN[]        PROGMEM = "
{t}

{v}
";
41
42	const char * const HTTP_PORTAL_MENU[] PROGMEM = {
43	"<form action='/wifi'    method='get'><button>配置 WiFi</button></form>
\n",     // MENU_WIFI
44	"<form action='/0wifi'   method='get'><button>配置 WiFi (不扫描)</button></form>
\n", // MENU_WIFINOSCAN
45	"<form action='/info'    method='get'><button>系统信息</button></form>
\n",       // MENU_INFO
46	"<form action='/param'   method='get'><button>参数设置</button></form>
\n",       // MENU_PARAM
47	"<form action='/close'   method='get'><button>关闭页面</button></form>
\n",       // MENU_CLOSE
48	"<form action='/restart' method='get'><button>重启设备</button></form>
\n",       // MENU_RESTART
49	"<form action='/exit'    method='get'><button>退出配网</button></form>
\n",       // MENU_EXIT
50	"<form action='/erase'   method='get'><button class='D'>清除配置</button></form>
\n", // MENU_ERASE
51	"<form action='/update'  method='get'><button>固件升级</button></form>
\n",       // MENU_UPDATE
52	"

" // MENU_SEP
53	};
54
55	const char HTTP_PORTAL_OPTIONS[]   PROGMEM = "";
56	const char HTTP_ITEM_QI[]          PROGMEM = "

";
57	const char HTTP_ITEM_QP[]          PROGMEM = "
{r}%
";
58	const char HTTP_ITEM[]             PROGMEM = "
{v}{qi}{qp}
";
59
60	const char HTTP_FORM_START[]       PROGMEM = "<form method='POST' action='{v}'>";
61	const char HTTP_FORM_WIFI[]        PROGMEM = "WiFi 名称 (SSID)<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>
WiFi 密码<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'><input type='checkbox' id='showpass' onclick='f()'> 显示密码
";
62	const char HTTP_FORM_WIFI_END[]    PROGMEM = "";
63	const char HTTP_FORM_STATIC_HEAD[] PROGMEM = "

";
64	const char HTTP_FORM_END[]         PROGMEM = "

<button type='submit'>保存配置</button></form>";
65	const char HTTP_FORM_LABEL[]       PROGMEM = "{t}";
66	const char HTTP_FORM_PARAM_HEAD[]  PROGMEM = "

";
67	const char HTTP_FORM_PARAM[]       PROGMEM = "
<input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>\n";
68
69	const char HTTP_SCAN_LINK[]        PROGMEM = "
<form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";
70	const char HTTP_SAVED[]            PROGMEM = "
正在保存配置
尝试连接 WiFi...
如果连接失败，请重新连接 AP 再试一次
";
71	const char HTTP_PARAMSAVED[]       PROGMEM = "
配置已保存

";
72	const char HTTP_END[]              PROGMEM = "
";
73	const char HTTP_ERASEBTN[]         PROGMEM = "
<form action='/erase' method='get'><button class='D'>清除 WiFi 配置</button></form>";
74	const char HTTP_UPDATEBTN[]        PROGMEM = "
<form action='/update' method='get'><button>固件升级</button></form>";
75	const char HTTP_BACKBTN[]          PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";
76
77	const char HTTP_STATUS_ON[]        PROGMEM = "
已连接 {v}
IP 地址: {i}
";
78	const char HTTP_STATUS_OFF[]       PROGMEM = "
未连接 {v}{r}
";
79	const char HTTP_STATUS_OFFPW[]     PROGMEM = "
WiFi 密码错误";
80	const char HTTP_STATUS_OFFNOAP[]   PROGMEM = "
未找到该 WiFi";
81	const char HTTP_STATUS_OFFFAIL[]   PROGMEM = "
无法连接";
82	const char HTTP_STATUS_NONE[]      PROGMEM = "
未设置 WiFi
";
83	const char HTTP_BR[]               PROGMEM = "
";
84
85	const char HTTP_STYLE[]            PROGMEM = "";
109
110	#ifndef WM_NOHELP
111	const char HTTP_HELP[]             PROGMEM =
112	 "

可用页面

"
113	 "
"
114	 "

页面	功能

"
115	 "
/	"
116	 "主菜单页面
"
117	 "
/wifi	"
118	 "显示 WiFi 扫描结果并配置连接 (/0wifi 不扫描)
"
119	 "
/wifisave	"
120	 "保存 WiFi 配置并连接设备
"
121	 "
/param	"
122	 "参数设置页面
"
123	 "
/info	"
124	 "系统信息页面
"
125	 "
/u	"
126	 "固件 OTA 升级
"
127	 "
/close	"
128	 "关闭弹出窗口，配网服务保持运行
"
129	 "
/exit	"
130	 "退出配网模式，配网服务将关闭
"
131	 "
/restart	"
132	 "重启设备
"
133	 "
/erase	"
134	 "清除 WiFi 配置并重启。清除后设备不会自动连接，需重新配网
"
135	 "
"
136	 "
GitHub https://github.com/tzapu/WiFiManager.";
137	#else
138	const char HTTP_HELP[]             PROGMEM = "";
139	#endif
140
141	const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display = el.value=='' ? 'none' : 'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果在配网页面内无法使用，请在浏览器中打开 http://192.168.4.1";
142	const char HTTP_UPDATE_FAIL[] PROGMEM = "
升级失败!
请重启设备后重试
";
143	const char HTTP_UPDATE_SUCCESS[] PROGMEM = "
升级成功!
设备正在重启...
";
144
145	#ifdef WM_JSTEST
146	const char HTTP_JS[] PROGMEM =
147	"";
163	#endif
164
165	// Info html
166	#ifdef ESP32
167		const char HTTP_INFO_esphead[]    PROGMEM = "
ESP32 信息

";
168		const char HTTP_INFO_chiprev[]    PROGMEM = "
芯片版本

{1}
";
169	  	const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";
170	  	const char HTTP_INFO_aphost[]     PROGMEM = "
AP 主机名

{1}
";
171	    const char HTTP_INFO_psrsize[]    PROGMEM = "
PSRAM 大小

{1} 字节
";
172		const char HTTP_INFO_temp[]       PROGMEM = "
芯片温度

{1}°C / {2}°F
";
173	    const char HTTP_INFO_hall[]       PROGMEM = "
霍尔传感器

{1}
";
174	#else
175		const char HTTP_INFO_esphead[]    PROGMEM = "
ESP8266 信息

";
176		const char HTTP_INFO_fchipid[]    PROGMEM = "
Flash 芯片 ID

{1}
";
177		const char HTTP_INFO_corever[]    PROGMEM = "
Core 版本

{1}
";
178		const char HTTP_INFO_bootver[]    PROGMEM = "
Boot 版本

{1}
";
179		const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

{1}
";
180		const char HTTP_INFO_flashsize[]  PROGMEM = "
实际 Flash 大小

{1} 字节
";
181	#endif
182
183	const char HTTP_INFO_memsmeter[]  PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";
184	const char HTTP_INFO_memsketch[]  PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";
185	const char HTTP_INFO_freeheap[]   PROGMEM = "
内存 - 可用堆

{1} 字节
";
186	const char HTTP_INFO_wifihead[]   PROGMEM = "

WiFi 信息

";
187	const char HTTP_INFO_uptime[]     PROGMEM = "
运行时间

{1} 分 {2} 秒
";
188	const char HTTP_INFO_chipid[]     PROGMEM = "
芯片 ID

{1}
";
189	const char HTTP_INFO_idesize[]    PROGMEM = "
Flash 大小

{1} 字节
";
190	const char HTTP_INFO_sdkver[]     PROGMEM = "
SDK 版本

{1}
";
191	const char HTTP_INFO_cpufreq[]    PROGMEM = "
CPU 频率

{1}MHz
";
192	const char HTTP_INFO_apip[]       PROGMEM = "
AP IP 地址

{1}
";
193	const char HTTP_INFO_apmac[]      PROGMEM = "
AP MAC 地址

{1}
";
194	const char HTTP_INFO_apssid[]     PROGMEM = "
AP SSID

{1}
";
195	const char HTTP_INFO_apbssid[]    PROGMEM = "
BSSID

{1}
";
196	const char HTTP_INFO_stassid[]    PROGMEM = "
Station SSID

{1}
";
197	const char HTTP_INFO_staip[]      PROGMEM = "
Station IP

{1}
";
198	const char HTTP_INFO_stagw[]      PROGMEM = "
网关地址

{1}
";
199	const char HTTP_INFO_stasub[]     PROGMEM = "
子网掩码

{1}
";
200	const char HTTP_INFO_dnss[]       PROGMEM = "
DNS 服务器

{1}
";
201	const char HTTP_INFO_host[]       PROGMEM = "
主机名

{1}
";
202	const char HTTP_INFO_stamac[]     PROGMEM = "
Station MAC

{1}
";
203	const char HTTP_INFO_conx[]       PROGMEM = "
连接状态

{1}
";
204	const char HTTP_INFO_autoconx[]   PROGMEM = "
自动连接

{1}
";
205
206	const char HTTP_INFO_aboutver[]     PROGMEM = "
WiFiManager 版本

{1}
";
207	const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino 版本

{1}
";
208	const char HTTP_INFO_aboutsdk[]     PROGMEM = "
ESP-SDK/IDF 版本

{1}
";
209	const char HTTP_INFO_aboutdate[]    PROGMEM = "
构建日期

{1}
";
210
211	// ============================================================
212	// 文本常量
213	// ============================================================
214	const char S_brand[]              PROGMEM = "健康监测配网";
215	const char S_debugPrefix[]        PROGMEM = "*wm:";
216	const char S_y[]                  PROGMEM = "是";
217	const char S_n[]                  PROGMEM = "否";
218	const char S_enable[]             PROGMEM = "已启用";
219	const char S_disable[]            PROGMEM = "已禁用";
220	const char S_GET[]                PROGMEM = "GET";
221	const char S_POST[]               PROGMEM = "POST";
222	const char S_NA[]                 PROGMEM = "未知";
223	const char S_passph[]             PROGMEM = "********";
224	const char S_titlewifisaved[]     PROGMEM = "WiFi 已保存";
225	const char S_titlewifisettings[]  PROGMEM = "设置已保存";
226	const char S_titlewifi[]          PROGMEM = "配置 WiFi";
227	const char S_titleinfo[]          PROGMEM = "系统信息";
228	const char S_titleparam[]         PROGMEM = "参数设置";
229	const char S_titleparamsaved[]    PROGMEM = "设置已保存";
230	const char S_titleexit[]          PROGMEM = "退出配网";
231	const char S_titlereset[]         PROGMEM = "重置";
232	const char S_titleerase[]         PROGMEM = "清除配置";
233	const char S_titleclose[]         PROGMEM = "关闭页面";
234	const char S_options[]            PROGMEM = "选项";
235	const char S_nonetworks[]         PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";
236	const char S_staticip[]           PROGMEM = "静态 IP";
237	const char S_staticgw[]           PROGMEM = "静态网关";
238	const char S_staticdns[]          PROGMEM = "静态 DNS";
239	const char S_subnet[]             PROGMEM = "子网掩码";
240	const char S_exiting[]            PROGMEM = "正在退出配网模式";
241	const char S_resetting[]          PROGMEM = "设备将在几秒后重启";
242	const char S_closing[]            PROGMEM = "可以关闭此页面，配网服务将继续运行";
243	const char S_error[]              PROGMEM = "发生错误";
244	const char S_notfound[]           PROGMEM = "页面未找到\n\n";
245	const char S_uri[]                PROGMEM = "URI: ";
246	const char S_method[]             PROGMEM = "\n请求方法: ";
247	const char S_args[]               PROGMEM = "\n参数: ";
248	const char S_parampre[]           PROGMEM = "param_";
249
250	// debug strings
251	const char D_HR[]                 PROGMEM = "--------------------";
252
253	// softap ssid default prefix
254	#ifdef ESP8266
255	    const char S_ssidpre[]        PROGMEM = "ESP";
256	#elif defined(ESP32)
257	    const char S_ssidpre[]        PROGMEM = "ESP32";
258	#else
259	    const char S_ssidpre[]        PROGMEM = "WM";
260	#endif
261
262	#endif
263

/**
 * wm_strings_zh.h
 * 中文语言包 for WiFiManager
 * 基于 wm_strings_en.h 翻译
 *
 * WiFiManager, a library for the ESP8266/Arduino platform
 * for configuration of WiFi credentials using a Captive Portal
 *
 * @author Creator tzapu
 * @author tablatronix
 * @version 0.0.0
 * @license MIT
 */

#ifndef _WM_STRINGS_ZH_H_
#define _WM_STRINGS_ZH_H_

// strings files must include a consts file!
#include "wm_consts_en.h" // include constants, tokens, routes

const char WM_LANGUAGE[] PROGMEM = "zh-CN"; // i18n lang code

const char HTTP_HEAD_START[]       PROGMEM = "<!DOCTYPE html>"
""
"<meta name='format-detection' content='telephone=no'>"
"<meta charset='UTF-8'>"
"<meta  name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
"<title>{v}</title>";

const char HTTP_SCRIPT[]           PROGMEM = "";

const char HTTP_HEAD_END[]         PROGMEM = "
"; // {c} = _bodyclass

const char HTTP_ROOT_MAIN[]        PROGMEM = "
{t}

{v}
";

const char * const HTTP_PORTAL_MENU[] PROGMEM = {
"<form action='/wifi'    method='get'><button>配置 WiFi</button></form>
\n",     // MENU_WIFI
"<form action='/0wifi'   method='get'><button>配置 WiFi (不扫描)</button></form>
\n", // MENU_WIFINOSCAN
"<form action='/info'    method='get'><button>系统信息</button></form>
\n",       // MENU_INFO
"<form action='/param'   method='get'><button>参数设置</button></form>
\n",       // MENU_PARAM
"<form action='/close'   method='get'><button>关闭页面</button></form>
\n",       // MENU_CLOSE
"<form action='/restart' method='get'><button>重启设备</button></form>
\n",       // MENU_RESTART
"<form action='/exit'    method='get'><button>退出配网</button></form>
\n",       // MENU_EXIT
"<form action='/erase'   method='get'><button class='D'>清除配置</button></form>
\n", // MENU_ERASE
"<form action='/update'  method='get'><button>固件升级</button></form>
\n",       // MENU_UPDATE
"

" // MENU_SEP
};

const char HTTP_PORTAL_OPTIONS[]   PROGMEM = "";
const char HTTP_ITEM_QI[]          PROGMEM = "

";
const char HTTP_ITEM_QP[]          PROGMEM = "
{r}%
";
const char HTTP_ITEM[]             PROGMEM = "
{v}{qi}{qp}
";

const char HTTP_FORM_START[]       PROGMEM = "<form method='POST' action='{v}'>";
const char HTTP_FORM_WIFI[]        PROGMEM = "WiFi 名称 (SSID)<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>
WiFi 密码<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'><input type='checkbox' id='showpass' onclick='f()'> 显示密码
";
const char HTTP_FORM_WIFI_END[]    PROGMEM = "";
const char HTTP_FORM_STATIC_HEAD[] PROGMEM = "

";
const char HTTP_FORM_END[]         PROGMEM = "

<button type='submit'>保存配置</button></form>";
const char HTTP_FORM_LABEL[]       PROGMEM = "{t}";
const char HTTP_FORM_PARAM_HEAD[]  PROGMEM = "

";
const char HTTP_FORM_PARAM[]       PROGMEM = "
<input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>\n";

const char HTTP_SCAN_LINK[]        PROGMEM = "
<form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";
const char HTTP_SAVED[]            PROGMEM = "
正在保存配置
尝试连接 WiFi...
如果连接失败，请重新连接 AP 再试一次
";
const char HTTP_PARAMSAVED[]       PROGMEM = "
配置已保存

";
const char HTTP_END[]              PROGMEM = "
";
const char HTTP_ERASEBTN[]         PROGMEM = "
<form action='/erase' method='get'><button class='D'>清除 WiFi 配置</button></form>";
const char HTTP_UPDATEBTN[]        PROGMEM = "
<form action='/update' method='get'><button>固件升级</button></form>";
const char HTTP_BACKBTN[]          PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";

const char HTTP_STATUS_ON[]        PROGMEM = "
已连接 {v}
IP 地址: {i}
";
const char HTTP_STATUS_OFF[]       PROGMEM = "
未连接 {v}{r}
";
const char HTTP_STATUS_OFFPW[]     PROGMEM = "
WiFi 密码错误";
const char HTTP_STATUS_OFFNOAP[]   PROGMEM = "
未找到该 WiFi";
const char HTTP_STATUS_OFFFAIL[]   PROGMEM = "
无法连接";
const char HTTP_STATUS_NONE[]      PROGMEM = "
未设置 WiFi
";
const char HTTP_BR[]               PROGMEM = "
";

const char HTTP_STYLE[]            PROGMEM = "";

#ifndef WM_NOHELP
const char HTTP_HELP[]             PROGMEM =
 "

可用页面

"
 "
"
 "

页面	功能

"
 "
/	"
 "主菜单页面
"
 "
/wifi	"
 "显示 WiFi 扫描结果并配置连接 (/0wifi 不扫描)
"
 "
/wifisave	"
 "保存 WiFi 配置并连接设备
"
 "
/param	"
 "参数设置页面
"
 "
/info	"
 "系统信息页面
"
 "
/u	"
 "固件 OTA 升级
"
 "
/close	"
 "关闭弹出窗口，配网服务保持运行
"
 "
/exit	"
 "退出配网模式，配网服务将关闭
"
 "
/restart	"
 "重启设备
"
 "
/erase	"
 "清除 WiFi 配置并重启。清除后设备不会自动连接，需重新配网
"
 "
"
 "
GitHub https://github.com/tzapu/WiFiManager.";
#else
const char HTTP_HELP[]             PROGMEM = "";
#endif

const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display = el.value=='' ? 'none' : 'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果在配网页面内无法使用，请在浏览器中打开 http://192.168.4.1";
const char HTTP_UPDATE_FAIL[] PROGMEM = "
升级失败!
请重启设备后重试
";
const char HTTP_UPDATE_SUCCESS[] PROGMEM = "
升级成功!
设备正在重启...
";

#ifdef WM_JSTEST
const char HTTP_JS[] PROGMEM =
"";
#endif

// Info html
#ifdef ESP32
	const char HTTP_INFO_esphead[]    PROGMEM = "
ESP32 信息

";
	const char HTTP_INFO_chiprev[]    PROGMEM = "
芯片版本

{1}
";
  	const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";
  	const char HTTP_INFO_aphost[]     PROGMEM = "
AP 主机名

{1}
";
    const char HTTP_INFO_psrsize[]    PROGMEM = "
PSRAM 大小

{1} 字节
";
	const char HTTP_INFO_temp[]       PROGMEM = "
芯片温度

{1}°C / {2}°F
";
    const char HTTP_INFO_hall[]       PROGMEM = "
霍尔传感器

{1}
";
#else
	const char HTTP_INFO_esphead[]    PROGMEM = "
ESP8266 信息

";
	const char HTTP_INFO_fchipid[]    PROGMEM = "
Flash 芯片 ID

{1}
";
	const char HTTP_INFO_corever[]    PROGMEM = "
Core 版本

{1}
";
	const char HTTP_INFO_bootver[]    PROGMEM = "
Boot 版本

{1}
";
	const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

{1}
";
	const char HTTP_INFO_flashsize[]  PROGMEM = "
实际 Flash 大小

{1} 字节
";
#endif

const char HTTP_INFO_memsmeter[]  PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";
const char HTTP_INFO_memsketch[]  PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";
const char HTTP_INFO_freeheap[]   PROGMEM = "
内存 - 可用堆

{1} 字节
";
const char HTTP_INFO_wifihead[]   PROGMEM = "

WiFi 信息

";
const char HTTP_INFO_uptime[]     PROGMEM = "
运行时间

{1} 分 {2} 秒
";
const char HTTP_INFO_chipid[]     PROGMEM = "
芯片 ID

{1}
";
const char HTTP_INFO_idesize[]    PROGMEM = "
Flash 大小

{1} 字节
";
const char HTTP_INFO_sdkver[]     PROGMEM = "
SDK 版本

{1}
";
const char HTTP_INFO_cpufreq[]    PROGMEM = "
CPU 频率

{1}MHz
";
const char HTTP_INFO_apip[]       PROGMEM = "
AP IP 地址

{1}
";
const char HTTP_INFO_apmac[]      PROGMEM = "
AP MAC 地址

{1}
";
const char HTTP_INFO_apssid[]     PROGMEM = "
AP SSID

{1}
";
const char HTTP_INFO_apbssid[]    PROGMEM = "
BSSID

{1}
";
const char HTTP_INFO_stassid[]    PROGMEM = "
Station SSID

{1}
";
const char HTTP_INFO_staip[]      PROGMEM = "
Station IP

{1}
";
const char HTTP_INFO_stagw[]      PROGMEM = "
网关地址

{1}
";
const char HTTP_INFO_stasub[]     PROGMEM = "
子网掩码

{1}
";
const char HTTP_INFO_dnss[]       PROGMEM = "
DNS 服务器

{1}
";
const char HTTP_INFO_host[]       PROGMEM = "
主机名

{1}
";
const char HTTP_INFO_stamac[]     PROGMEM = "
Station MAC

{1}
";
const char HTTP_INFO_conx[]       PROGMEM = "
连接状态

{1}
";
const char HTTP_INFO_autoconx[]   PROGMEM = "
自动连接

{1}
";

const char HTTP_INFO_aboutver[]     PROGMEM = "
WiFiManager 版本

{1}
";
const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino 版本

{1}
";
const char HTTP_INFO_aboutsdk[]     PROGMEM = "
ESP-SDK/IDF 版本

{1}
";
const char HTTP_INFO_aboutdate[]    PROGMEM = "
构建日期

{1}
";

// ============================================================
// 文本常量
// ============================================================
const char S_brand[]              PROGMEM = "健康监测配网";
const char S_debugPrefix[]        PROGMEM = "*wm:";
const char S_y[]                  PROGMEM = "是";
const char S_n[]                  PROGMEM = "否";
const char S_enable[]             PROGMEM = "已启用";
const char S_disable[]            PROGMEM = "已禁用";
const char S_GET[]                PROGMEM = "GET";
const char S_POST[]               PROGMEM = "POST";
const char S_NA[]                 PROGMEM = "未知";
const char S_passph[]             PROGMEM = "********";
const char S_titlewifisaved[]     PROGMEM = "WiFi 已保存";
const char S_titlewifisettings[]  PROGMEM = "设置已保存";
const char S_titlewifi[]          PROGMEM = "配置 WiFi";
const char S_titleinfo[]          PROGMEM = "系统信息";
const char S_titleparam[]         PROGMEM = "参数设置";
const char S_titleparamsaved[]    PROGMEM = "设置已保存";
const char S_titleexit[]          PROGMEM = "退出配网";
const char S_titlereset[]         PROGMEM = "重置";
const char S_titleerase[]         PROGMEM = "清除配置";
const char S_titleclose[]         PROGMEM = "关闭页面";
const char S_options[]            PROGMEM = "选项";
const char S_nonetworks[]         PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";
const char S_staticip[]           PROGMEM = "静态 IP";
const char S_staticgw[]           PROGMEM = "静态网关";
const char S_staticdns[]          PROGMEM = "静态 DNS";
const char S_subnet[]             PROGMEM = "子网掩码";
const char S_exiting[]            PROGMEM = "正在退出配网模式";
const char S_resetting[]          PROGMEM = "设备将在几秒后重启";
const char S_closing[]            PROGMEM = "可以关闭此页面，配网服务将继续运行";
const char S_error[]              PROGMEM = "发生错误";
const char S_notfound[]           PROGMEM = "页面未找到\n\n";
const char S_uri[]                PROGMEM = "URI: ";
const char S_method[]             PROGMEM = "\n请求方法: ";
const char S_args[]               PROGMEM = "\n参数: ";
const char S_parampre[]           PROGMEM = "param_";

// debug strings
const char D_HR[]                 PROGMEM = "--------------------";

// softap ssid default prefix
#ifdef ESP8266
    const char S_ssidpre[]        PROGMEM = "ESP";
#elif defined(ESP32)
    const char S_ssidpre[]        PROGMEM = "ESP32";
#else
    const char S_ssidpre[]        PROGMEM = "WM";
#endif

#endif


Now I understand the full picture. WiFiManager generates the `/wifi` page by concatenating these PROGMEM strings:

1. `HTTP_HEAD_START` → page start + title
2. `HTTP_SCRIPT` → JS functions (c() for SSID click, f() for password toggle)
3. Our custom head element (CSS) is injected by the library
4. `HTTP_HEAD_END` → `<body><div class='wrap'>`
5. `HTTP_ROOT_MAIN` → `<h1>{t}</h1><h3>{v}</h3>` (title + subtitle)
6. SSID list items (dynamically generated)
7. `HTTP_FORM_START` → `<form method='POST' action='/wifisave'>`
8. `HTTP_FORM_WIFI` → SSID input + password input + show password checkbox
9. Custom parameter HTML (dynamically generated)
10. `HTTP_FORM_END` → submit button + close form
11. `HTTP_END` → `</div></body></html>`

And the root page `/` additionally includes:
- `HTTP_PORTAL_MENU` items
- `setCustomMenuHTML()` content is appended here

The problem: our card-based design (header, gateway info, WiFi card, device card, modal) is in `setCustomMenuHTML()` which only goes to the root page `/`. The actual WiFi config page `/wifi` uses the hardcoded library template.

**My approach**: Modify `HTTP_HEAD_END` and `HTTP_FORM_WIFI` and `HTTP_FORM_END` and `HTTP_END` to include our design structure, so that when WiFiManager generates the `/wifi` page, it looks like our design.

But there's a simpler approach: modify `HTTP_HEAD_END` to include the header + gateway info, and modify `HTTP_ROOT_MAIN` to include the header content (since it's used on multiple pages), and modify `HTTP_FORM_WIFI` to wrap in card div, etc.

Actually, `HTTP_ROOT_MAIN` is used on ALL pages (root, wifi, info, param, etc.) as the page title section. If I modify it to include the header design, it affects all pages.

Let me think about which pages use which strings:

**Root page `/`:**
- `HTTP_HEAD_START` + CSS + `HTTP_SCRIPT` + `HTTP_HEAD_END`
- `HTTP_ROOT_MAIN` (h1 + h3)
- Custom menu HTML (our header + modal)
- `HTTP_PORTAL_MENU` items
- `HTTP_END`

**WiFi page `/wifi`:**
- `HTTP_HEAD_START` + CSS + `HTTP_SCRIPT` + `HTTP_HEAD_END`
- `HTTP_ROOT_MAIN`
- SSID list
- `HTTP_FORM_START`
- `HTTP_FORM_WIFI`
- Custom params
- `HTTP_FORM_END`
- `HTTP_END`

**WiFi saved page `/wifisave`:**
- `HTTP_HEAD_START` + CSS + `HTTP_SCRIPT` + `HTTP_HEAD_END`
- `HTTP_ROOT_MAIN`
- `HTTP_SAVED`
- `HTTP_END`

So to make the `/wifi` page look like our design, I need to modify:
1. `HTTP_HEAD_END` — add header + gateway card after `<div class='wrap'>`
2. `HTTP_ROOT_MAIN` — remove the default h1/h3 (we have our own header)
3. `HTTP_FORM_WIFI` — wrap in card div
4. `HTTP_FORM_END` — use our button style
5. `HTTP_END` — add modal + script + footer

This approach will change ALL pages (root, wifi, info, param) to have our design, which is actually GOOD — consistency.

Let me now craft the modified file. I need to be careful with PROGMEM string sizes — ESP32 has plenty of flash so this should be fine.

Here's my plan:

1. `HTTP_HEAD_END` — add header div + gateway info card after `<div class='wrap'>`
2. `HTTP_ROOT_MAIN` — empty (we have header in HEAD_END)
3. `HTTP_FORM_WIFI` — wrap with card divs, use our inputWrap style
4. `HTTP_FORM_END` — use our button style + add footer
5. `HTTP_END` — add modal HTML + JS script + close wrappers

Actually wait, I need to be more careful. Let me look at how WiFiManager.cpp uses these strings:

In `handleWifi()` (WiFiManager.cpp around line 1355):
```cpp
page += FPSTR(HTTP_HEAD_START);
// ... inserts customHeadElement
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_HEAD_END);
page += FPSTR(HTTP_ROOT_MAIN);
// ... SSID list
page += FPSTR(HTTP_FORM_START);
page += FPSTR(HTTP_FORM_WIFI);
// ... custom params
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_END);
```

So the page structure is fixed. I need to work within this template.

Let me figure out the right modifications:

**HTTP_HEAD_END**: Add our header + gateway card. Replace:
```
"</head><body class='{c}'><div class='wrap'>"
```
with:
```
"</head><body class='{c}'><div class='wrap'>"
"<div class='header'><div class='headerIcon'>📡</div><div class='headerText'><h1>观照-五劳无感 · 设备配网</h1><h3>WiFi 联网与参数配置</h3></div>"
"<div class='helpIcon hint' id='helpIcon' onclick='toggleModal(true)' title='查看配网流程'>?</div>"
"<div class='guideTip' id='guideTip'>点击这里再次查看配网流程</div></div>"
"<div class='gateInfo'><span class='gateLabel'>📍 当前网关</span><span class='gateId'>Gateway_A8F3</span></div>"
```

**HTTP_ROOT_MAIN**: Empty string (or just a small spacer) since header is now in HEAD_END

**HTTP_FORM_WIFI**: Wrap with card div. Replace:
```
"<label for='s'>WiFi 名称 (SSID)</label><input id='s' name='s' .../><label for='p'>WiFi 密码</label><input id='p' name='p' .../>..."
```
with:
```
"<div class='card'><div class='cardHeader'><div class='cardHeaderIcon'>📶</div><div><div class='cardTitle'>无线网络</div><div class='cardSub'>请选择 2.4GHz WiFi</div></div></div>"
"<div class='field'><label>WiFi 名称</label><div class='inputWrap'><span class='inputIcon'>📡</span><input id='s' name='s' .../></div></div>"
"<div class='field'><label>WiFi 密码</label><div class='inputWrap'><span class='inputIcon'>🔒</span><input id='p' name='p' .../></div></div></div>"
```

Wait, but the SSID selection in WiFiManager works DIFFERENTLY from our design. In WiFiManager:
- The SSID is NOT a select dropdown
- It's an `<input id='s'>` that gets filled by clicking on SSID links
- The SSID links appear ABOVE the form

So our `<select></select>` in the design doesn't match WiFiManager's SSID mechanism. WiFiManager shows a list of clickable SSID links, and clicking one fills `input#s`.

But wait — WiFiManager also has a mode where it uses `<select>` for SSID. Looking at the code... The `HTTP_ITEM` template generates clickable div/link items. When clicked, the JS function `c(l)` fills `input#s`. So the SSID field IS an input, not a select.

Our design has a `<select></select>` which won't work with WiFiManager's mechanism. The SSID list items and the input field work together — clicking an item fills the input.

However, the CSS styling (`inputWrap`, `inputIcon`) will style the input correctly. The `<select>` in our design is just a placeholder that won't be used by WiFiManager anyway.

OK let me just do the minimum viable change: modify the key template strings to include our card wrappers and design elements. I'll keep the functional WiFiManager structure (SSID input + links) but wrap everything in our card design.

Let me write the replacements now. The key changes:

1. **HTTP_HEAD_END**: Add header + gateway info (our design elements, but NOT `<div class='wrap'>` since that's already there)

Wait, I need to be really careful. The `{c}` and `{v}` are template variables that WiFiManager replaces at runtime. Let me check what variables are used where:

- `{v}` = value (varies by context — SSID name, title text, etc.)
- `{t}` = title
- `{c}` = body class
- `{i}` = item id
- `{n}` = name
- `{l}` = length
- `{p}` = placeholder
- `{V}` = value (encoded)
- `{r}` = RSSI

These are replaced by WiFiManager's internal string formatting functions.

OK, here's my concrete plan. I'll modify 4 key strings:

1. `HTTP_HEAD_END` — append header + gateway card HTML after `{c}` body class
2. `HTTP_ROOT_MAIN` — empty (remove default title since we have header)
3. `HTTP_FORM_WIFI` — wrap in card div with our styling
4. `HTTP_FORM_PARAM_HEAD` — wrap in card for device info section
5. `HTTP_FORM_END` — our button group style
6. `HTTP_END` — modal + script + footer

Let me write this. This is going to be a big edit.

Actually wait, there's a problem. WiFiManager's `HTTP_FORM_WIFI` template contains `{v}` and `{p}` which get replaced. If I add our card wrapper HTML outside those variables, it should be fine. But I need to understand the exact template format.

Current `HTTP_FORM_WIFI`:
```
<label for='s'>WiFi 名称 (SSID)</label>
<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>
<br/>
<label for='p'>WiFi 密码</label>
<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'>
<input type='checkbox' id='showpass' onclick='f()'> <label for='showpass'>显示密码</label><br/>
```

I need to wrap this with our card structure. The `{v}` gets replaced with the SSID placeholder text, and `{p}` gets replaced with password placeholder. These replacements happen at runtime via `WiFiManager::htmlEntities()` or similar.

My modified version:
```
<div class='card'>
<div class='cardHeader'><div class='cardHeaderIcon'>📶</div><div><div class='cardTitle'>无线网络</div><div class='cardSub'>请选择 2.4GHz WiFi</div></div></div>
<div class='field'><label>WiFi 名称</label><div class='inputWrap'><span class='inputIcon'>📡</span><input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'></div></div>
<div class='field'><label>WiFi 密码</label><div class='inputWrap'><span class='inputIcon'>🔒</span><input id='p' name='p' maxlength='64' type='password' placeholder='{p}'></div></div>
<input type='checkbox' id='showpass' onclick='f()'> <label for='showpass'>显示密码</label>
</div>
```

The `{v}` and `{p}` placeholders are preserved, so WiFiManager can still replace them. Good.

For `HTTP_FORM_PARAM_HEAD`, I'll wrap params in a card:
```
</div><div class='card'><div class='cardHeader'><div class='cardHeaderIcon'>⚙</div><div><div class='cardTitle'>设备基础信息</div><div class='cardSub'>唯一标识与安装位置</div></div></div>
```

Wait, but this needs to close the WiFi card first. Let me think about the order...

The page structure after my changes should be:
```html
<div class='wrap'>
  <div class='header'>...</div>           ← from HTTP_HEAD_END
  <div class='gateInfo'>...</div>         ← from HTTP_HEAD_END

  <!-- SSID scan list items -->           ← generated by WiFiManager

  <form action='/wifisave'>
    <div class='card'>                    ← from HTTP_FORM_WIFI
      ...WiFi fields...
    </div>
    <div class='card'>                    ← from HTTP_FORM_PARAM_HEAD
      ...device params...
    </div>                                ← custom params end here
    ...buttons...                         ← from HTTP_FORM_END
  </form>

  <div class='footer'>...</div>          ← from HTTP_END
  ...modal...                            ← from HTTP_END
  ...script...                           ← from HTTP_END
</div>
```

This structure matches the design! Let me now write the actual edits.

For the PROGMEM strings, I need to be careful about memory. Each string is stored in flash (PROGMEM), and the total won't be more than a few KB extra. ESP32 has 16MB flash so this is fine.

Let me write the replacement for wm_strings_zh.h now.


问题在这——WiFiManager 库用 `wm_strings_zh.h` 里的模板生成 `/wifi` 页面，`setCustomMenuHTML` 只管首页。得直接改库文件。


Write

/**
 * wm_strings_zh.h
 * 中文语言包 — 观照-五劳无感定制版
 */

#ifndef _WM_STRINGS_ZH_H_
#define _WM_STRINGS_ZH_H_

#include "wm_consts_en.h"

const char WM_LANGUAGE[] PROGMEM = "zh-CN";

// ====================== Head ======================
const char HTTP_HEAD_START[] PROGMEM = "<!DOCTYPE html>"
""
"<meta name='format-detection' content='telephone=no'>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
"<title>{v}</title>";

const char HTTP_SCRIPT[] PROGMEM = "";

// ====================== Body 开头 → 加入 Header + 网关信息卡 ======================
const char HTTP_HEAD_END[] PROGMEM = "
"
"
"
"
📡
"
"

观照-五劳无感 · 设备配网

WiFi 联网与参数配置

"
"
?
"
"
点击这里再次查看配网流程
"
"
"
"
📍 当前网关Gateway_A8F3
";

const char HTTP_ROOT_MAIN[] PROGMEM = "";  // header 已在 HEAD_END 中

// ====================== 首页菜单 ======================
const char * const HTTP_PORTAL_MENU[] PROGMEM = {
"<form action='/wifi' method='get'><button>配置 WiFi</button></form>
\n",
"<form action='/0wifi' method='get'><button>配置 WiFi (不扫描)</button></form>
\n",
"<form action='/info' method='get'><button>系统信息</button></form>
\n",
"<form action='/param' method='get'><button>参数设置</button></form>
\n",
"<form action='/close' method='get'><button>关闭页面</button></form>
\n",
"<form action='/restart' method='get'><button>重启设备</button></form>
\n",
"<form action='/exit' method='get'><button>退出配网</button></form>
\n",
"<form action='/erase' method='get'><button class='D'>清除配置</button></form>
\n",
"<form action='/update' method='get'><button>固件升级</button></form>
\n",
"

"
};

// ====================== WiFi 列表项 ======================
const char HTTP_PORTAL_OPTIONS[] PROGMEM = "";
const char HTTP_ITEM_QI[] PROGMEM = "

";
const char HTTP_ITEM_QP[] PROGMEM = "
{r}%
";
const char HTTP_ITEM[] PROGMEM = "
{v}{qi}{qp}
";

// ====================== WiFi 表单 → 卡片包裹 ======================
const char HTTP_FORM_START[] PROGMEM = "<form method='POST' action='{v}'>";

const char HTTP_FORM_WIFI[] PROGMEM =
"
"
"

📶

无线网络

请选择 2.4GHz WiFi

"
"
WiFi 名称
📡<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>

"
"
WiFi 密码
🔒<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'>

"
"<input type='checkbox' id='showpass' onclick='f()'> 显示密码"
"
";

const char HTTP_FORM_WIFI_END[] PROGMEM = "";

// ====================== 参数区 → 设备信息卡片包裹 ======================
const char HTTP_FORM_STATIC_HEAD[] PROGMEM =
"
"
"

⚙

设备基础信息

唯一标识与安装位置

";

const char HTTP_FORM_PARAM_HEAD[] PROGMEM = "";

// ====================== 参数输入 ======================
const char HTTP_FORM_LABEL[] PROGMEM = "
{t}";
const char HTTP_FORM_PARAM[] PROGMEM = "
#<input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>

\n";

// ====================== 提交按钮 ======================
const char HTTP_FORM_END[] PROGMEM =
"
"  // 关闭参数卡片
"
"
"<button type='submit'>保存配置并重启连接</button>"
"<button class='danger' type='button' onclick='document.location.reload()'>恢复出厂配置</button>"
"
"
"</form>";

// ====================== 正文结束 → Footer + 弹窗 ======================
const char HTTP_END[] PROGMEM =
"
Health Monitor · Device Provisioning
"
"
"  // .wrap
"
"
"
"
"
"
"
📋
"
"

配网流程

按顺序完成 4 步操作

"
"
×
"
"
"
"
"
"

1

选择 WiFi 并输入密码

确保手机已连接目标 2.4G 网络

"
"

2

填写设备基础信息

设备编号与安装环境，便于多设备管理

"
"

3

核对信息并保存

确认无误后点击保存配置

"
"

4

等待设备重启连接

设备指示灯常亮即表示配网完成

"
"
"
"
"
"<button class='ghost' onclick='toggleModal(false)'>稍后查看</button>"
"<button class='primary' onclick='toggleModal(false)'>我知道了</button>"
"
"
"
"
"
"
"";

// ====================== 杂项 ======================
const char HTTP_SCAN_LINK[] PROGMEM = "
<form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";
const char HTTP_SAVED[] PROGMEM = "
配置已保存
正在连接 WiFi...
";
const char HTTP_PARAMSAVED[] PROGMEM = "
配置已保存

";
const char HTTP_ERASEBTN[] PROGMEM = "
<form action='/erase' method='get'><button class='danger'>清除 WiFi 配置</button></form>";
const char HTTP_UPDATEBTN[] PROGMEM = "
<form action='/update' method='get'><button>固件升级</button></form>";
const char HTTP_BACKBTN[] PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";

const char HTTP_STATUS_ON[] PROGMEM = "
已连接 {v}
IP 地址: {i}
";
const char HTTP_STATUS_OFF[] PROGMEM = "
未连接 {v}{r}
";
const char HTTP_STATUS_OFFPW[] PROGMEM = "
WiFi 密码错误";
const char HTTP_STATUS_OFFNOAP[] PROGMEM = "
未找到该 WiFi";
const char HTTP_STATUS_OFFFAIL[] PROGMEM = "
无法连接";
const char HTTP_STATUS_NONE[] PROGMEM = "
未设置 WiFi
";
const char HTTP_BR[] PROGMEM = "
";

// ====================== 样式 (库默认保留, 被 setCustomHeadElement 覆盖) ======================
const char HTTP_STYLE[] PROGMEM = "";

// ====================== 帮助页 ======================
#ifndef WM_NOHELP
const char HTTP_HELP[] PROGMEM =
"

可用页面

"
"
"
"

页面	功能

"
"
/	主菜单页面
"
"
/wifi	显示 WiFi 扫描结果并配置连接
"
"
/wifisave	保存 WiFi 配置并连接设备
"
"
/param	参数设置页面
"
"
/info	系统信息页面
"
"
/u	固件 OTA 升级
"
"
/close	关闭弹出窗口
"
"
/exit	退出配网模式
"
"
/restart	重启设备
"
"
/erase	清除 WiFi 配置并重启
"
"
";
#else
const char HTTP_HELP[] PROGMEM = "";
#endif

const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display=el.value==''?'none':'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果无法使用，请在浏览器中打开 http://192.168.4.1";
const char HTTP_UPDATE_FAIL[] PROGMEM = "
升级失败!
请重启设备后重试
";
const char HTTP_UPDATE_SUCCESS[] PROGMEM = "
升级成功!
设备正在重启...
";

// ====================== Info 页 ======================
#ifdef ESP32
const char HTTP_INFO_esphead[] PROGMEM = "
ESP32 信息

";
const char HTTP_INFO_chiprev[] PROGMEM = "
芯片版本

{1}
";
const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";
const char HTTP_INFO_aphost[] PROGMEM = "
AP 主机名

{1}
";
const char HTTP_INFO_psrsize[] PROGMEM = "
PSRAM 大小

{1} 字节
";
const char HTTP_INFO_temp[] PROGMEM = "
芯片温度

{1}°C / {2}°F
";
const char HTTP_INFO_hall[] PROGMEM = "
霍尔传感器

{1}
";
#else
const char HTTP_INFO_esphead[] PROGMEM = "
ESP8266 信息

";
const char HTTP_INFO_fchipid[] PROGMEM = "
Flash 芯片 ID

{1}
";
const char HTTP_INFO_corever[] PROGMEM = "
Core 版本

{1}
";
const char HTTP_INFO_bootver[] PROGMEM = "
Boot 版本

{1}
";
const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

{1}
";
const char HTTP_INFO_flashsize[] PROGMEM = "
实际 Flash 大小

{1} 字节
";
#endif

const char HTTP_INFO_memsmeter[] PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";
const char HTTP_INFO_memsketch[] PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";
const char HTTP_INFO_freeheap[] PROGMEM = "
内存 - 可用堆

{1} 字节
";
const char HTTP_INFO_wifihead[] PROGMEM = "

WiFi 信息

";
const char HTTP_INFO_uptime[] PROGMEM = "
运行时间

{1} 分 {2} 秒
";
const char HTTP_INFO_chipid[] PROGMEM = "
芯片 ID

{1}
";
const char HTTP_INFO_idesize[] PROGMEM = "
Flash 大小

{1} 字节
";
const char HTTP_INFO_sdkver[] PROGMEM = "
SDK 版本

{1}
";
const char HTTP_INFO_cpufreq[] PROGMEM = "
CPU 频率

{1}MHz
";
const char HTTP_INFO_apip[] PROGMEM = "
AP IP 地址

{1}
";
const char HTTP_INFO_apmac[] PROGMEM = "
AP MAC 地址

{1}
";
const char HTTP_INFO_apssid[] PROGMEM = "
AP SSID

{1}
";
const char HTTP_INFO_apbssid[] PROGMEM = "
BSSID

{1}
";
const char HTTP_INFO_stassid[] PROGMEM = "
Station SSID

{1}
";
const char HTTP_INFO_staip[] PROGMEM = "
Station IP

{1}
";
const char HTTP_INFO_stagw[] PROGMEM = "
网关地址

{1}
";
const char HTTP_INFO_stasub[] PROGMEM = "
子网掩码

{1}
";
const char HTTP_INFO_dnss[] PROGMEM = "
DNS 服务器

{1}
";
const char HTTP_INFO_host[] PROGMEM = "
主机名

{1}
";
const char HTTP_INFO_stamac[] PROGMEM = "
Station MAC

{1}
";
const char HTTP_INFO_conx[] PROGMEM = "
连接状态

{1}
";
const char HTTP_INFO_autoconx[] PROGMEM = "
自动连接

{1}
";
const char HTTP_INFO_aboutver[] PROGMEM = "
WiFiManager 版本

{1}
";
const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino 版本

{1}
";
const char HTTP_INFO_aboutsdk[] PROGMEM = "
ESP-SDK/IDF 版本

{1}
";
const char HTTP_INFO_aboutdate[] PROGMEM = "
构建日期

{1}
";

// ====================== 文本常量 ======================
const char S_brand[] PROGMEM = "健康监测配网";
const char S_debugPrefix[] PROGMEM = "*wm:";
const char S_y[] PROGMEM = "是";
const char S_n[] PROGMEM = "否";
const char S_enable[] PROGMEM = "已启用";
const char S_disable[] PROGMEM = "已禁用";
const char S_GET[] PROGMEM = "GET";
const char S_POST[] PROGMEM = "POST";
const char S_NA[] PROGMEM = "未知";
const char S_passph[] PROGMEM = "********";
const char S_titlewifisaved[] PROGMEM = "WiFi 已保存";
const char S_titlewifisettings[] PROGMEM = "设置已保存";
const char S_titlewifi[] PROGMEM = "配置 WiFi";
const char S_titleinfo[] PROGMEM = "系统信息";
const char S_titleparam[] PROGMEM = "参数设置";
const char S_titleparamsaved[] PROGMEM = "设置已保存";
const char S_titleexit[] PROGMEM = "退出配网";
const char S_titlereset[] PROGMEM = "重置";
const char S_titleerase[] PROGMEM = "清除配置";
const char S_titleclose[] PROGMEM = "关闭页面";
const char S_options[] PROGMEM = "选项";
const char S_nonetworks[] PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";
const char S_staticip[] PROGMEM = "静态 IP";
const char S_staticgw[] PROGMEM = "静态网关";
const char S_staticdns[] PROGMEM = "静态 DNS";
const char S_subnet[] PROGMEM = "子网掩码";
const char S_exiting[] PROGMEM = "正在退出配网模式";
const char S_resetting[] PROGMEM = "设备将在几秒后重启";
const char S_closing[] PROGMEM = "可以关闭此页面，配网服务将继续运行";
const char S_error[] PROGMEM = "发生错误";
const char S_notfound[] PROGMEM = "页面未找到\n\n";
const char S_uri[] PROGMEM = "URI: ";
const char S_method[] PROGMEM = "\n请求方法: ";
const char S_args[] PROGMEM = "\n参数: ";
const char S_parampre[] PROGMEM = "param_";
const char D_HR[] PROGMEM = "--------------------";

#ifdef ESP8266
const char S_ssidpre[] PROGMEM = "ESP";
#elif defined(ESP32)
const char S_ssidpre[] PROGMEM = "ESP32";
#else
const char S_ssidpre[] PROGMEM = "WM";
#endif

#endif


The file d:\PlatformIO1\Projects\Healthv2.0\.pio\libdeps\esp32-s3-devkitc-1\WiFiManager\wm_strings_zh.h has been updated successfully. (file state is current in your context — no need to Read it back)

/**
 * wm_strings_zh.h
 * 中文语言包 — 观照-五劳无感定制版
 */

#ifndef _WM_STRINGS_ZH_H_
#define _WM_STRINGS_ZH_H_

#include "wm_consts_en.h"

const char WM_LANGUAGE[] PROGMEM = "zh-CN";

// ====================== Head ======================
const char HTTP_HEAD_START[] PROGMEM = "<!DOCTYPE html>"
""
"<meta name='format-detection' content='telephone=no'>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
"<title>{v}</title>";

const char HTTP_SCRIPT[] PROGMEM = "";

// ====================== Body 开头 → 加入 Header + 网关信息卡 ======================
const char HTTP_HEAD_END[] PROGMEM = "
"
"
"
"
📡
"
"

观照-五劳无感 · 设备配网

WiFi 联网与参数配置

"
"
?
"
"
点击这里再次查看配网流程
"
"
"
"
📍 当前网关Gateway_A8F3
";

const char HTTP_ROOT_MAIN[] PROGMEM = "";  // header 已在 HEAD_END 中

// ====================== 首页菜单 ======================
const char * const HTTP_PORTAL_MENU[] PROGMEM = {
"<form action='/wifi' method='get'><button>配置 WiFi</button></form>
\n",
"<form action='/0wifi' method='get'><button>配置 WiFi (不扫描)</button></form>
\n",
"<form action='/info' method='get'><button>系统信息</button></form>
\n",
"<form action='/param' method='get'><button>参数设置</button></form>
\n",
"<form action='/close' method='get'><button>关闭页面</button></form>
\n",
"<form action='/restart' method='get'><button>重启设备</button></form>
\n",
"<form action='/exit' method='get'><button>退出配网</button></form>
\n",
"<form action='/erase' method='get'><button class='D'>清除配置</button></form>
\n",
"<form action='/update' method='get'><button>固件升级</button></form>
\n",
"

"
};

// ====================== WiFi 列表项 ======================
const char HTTP_PORTAL_OPTIONS[] PROGMEM = "";
const char HTTP_ITEM_QI[] PROGMEM = "

";
const char HTTP_ITEM_QP[] PROGMEM = "
{r}%
";
const char HTTP_ITEM[] PROGMEM = "
{v}{qi}{qp}
";

// ====================== WiFi 表单 → 卡片包裹 ======================
const char HTTP_FORM_START[] PROGMEM = "<form method='POST' action='{v}'>";

const char HTTP_FORM_WIFI[] PROGMEM =
"
"
"

📶

无线网络

请选择 2.4GHz WiFi

"
"
WiFi 名称
📡<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>

"
"
WiFi 密码
🔒<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'>

"
"<input type='checkbox' id='showpass' onclick='f()'> 显示密码"
"
";

const char HTTP_FORM_WIFI_END[] PROGMEM = "";

// ====================== 参数区 → 设备信息卡片包裹 ======================
const char HTTP_FORM_STATIC_HEAD[] PROGMEM =
"
"
"

⚙

设备基础信息

唯一标识与安装位置

";

const char HTTP_FORM_PARAM_HEAD[] PROGMEM = "";

// ====================== 参数输入 ======================
const char HTTP_FORM_LABEL[] PROGMEM = "
{t}";
const char HTTP_FORM_PARAM[] PROGMEM = "
#<input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>

\n";

// ====================== 提交按钮 ======================
const char HTTP_FORM_END[] PROGMEM =
"
"  // 关闭参数卡片
"
"
"<button type='submit'>保存配置并重启连接</button>"
"<button class='danger' type='button' onclick='document.location.reload()'>恢复出厂配置</button>"
"
"
"</form>";

// ====================== 正文结束 → Footer + 弹窗 ======================
const char HTTP_END[] PROGMEM =
"
Health Monitor · Device Provisioning
"
"
"  // .wrap
"
"
"
"
"
"
"
📋
"
"

配网流程

按顺序完成 4 步操作

"
"
×
"
"
"
"
"
"

1

选择 WiFi 并输入密码

确保手机已连接目标 2.4G 网络

"
"

2

填写设备基础信息

设备编号与安装环境，便于多设备管理

"
"

3

核对信息并保存

确认无误后点击保存配置

"
"

4

等待设备重启连接

设备指示灯常亮即表示配网完成

"
"
"
"
"
"<button class='ghost' onclick='toggleModal(false)'>稍后查看</button>"
"<button class='primary' onclick='toggleModal(false)'>我知道了</button>"
"
"
"
"
"
"
"";

// ====================== 杂项 ======================
const char HTTP_SCAN_LINK[] PROGMEM = "
<form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";
const char HTTP_SAVED[] PROGMEM = "
配置已保存
正在连接 WiFi...
";
const char HTTP_PARAMSAVED[] PROGMEM = "
配置已保存

";
const char HTTP_ERASEBTN[] PROGMEM = "
<form action='/erase' method='get'><button class='danger'>清除 WiFi 配置</button></form>";
const char HTTP_UPDATEBTN[] PROGMEM = "
<form action='/update' method='get'><button>固件升级</button></form>";
const char HTTP_BACKBTN[] PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";

const char HTTP_STATUS_ON[] PROGMEM = "
已连接 {v}
IP 地址: {i}
";
const char HTTP_STATUS_OFF[] PROGMEM = "
未连接 {v}{r}
";
const char HTTP_STATUS_OFFPW[] PROGMEM = "
WiFi 密码错误";
const char HTTP_STATUS_OFFNOAP[] PROGMEM = "
未找到该 WiFi";
const char HTTP_STATUS_OFFFAIL[] PROGMEM = "
无法连接";
const char HTTP_STATUS_NONE[] PROGMEM = "
未设置 WiFi
";
const char HTTP_BR[] PROGMEM = "
";

// ====================== 样式 (库默认保留, 被 setCustomHeadElement 覆盖) ======================
const char HTTP_STYLE[] PROGMEM = "";

// ====================== 帮助页 ======================
#ifndef WM_NOHELP
const char HTTP_HELP[] PROGMEM =
"

可用页面

"
"
"
"

页面	功能

"
"
/	主菜单页面
"
"
/wifi	显示 WiFi 扫描结果并配置连接
"
"
/wifisave	保存 WiFi 配置并连接设备
"
"
/param	参数设置页面
"
"
/info	系统信息页面
"
"
/u	固件 OTA 升级
"
"
/close	关闭弹出窗口
"
"
/exit	退出配网模式
"
"
/restart	重启设备
"
"
/erase	清除 WiFi 配置并重启
"
"
";
#else
const char HTTP_HELP[] PROGMEM = "";
#endif

const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display=el.value==''?'none':'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果无法使用，请在浏览器中打开 http://192.168.4.1";
const char HTTP_UPDATE_FAIL[] PROGMEM = "
升级失败!
请重启设备后重试
";
const char HTTP_UPDATE_SUCCESS[] PROGMEM = "
升级成功!
设备正在重启...
";

// ====================== Info 页 ======================
#ifdef ESP32
const char HTTP_INFO_esphead[] PROGMEM = "
ESP32 信息

";
const char HTTP_INFO_chiprev[] PROGMEM = "
芯片版本

{1}
";
const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";
const char HTTP_INFO_aphost[] PROGMEM = "
AP 主机名

{1}
";
const char HTTP_INFO_psrsize[] PROGMEM = "
PSRAM 大小

{1} 字节
";
const char HTTP_INFO_temp[] PROGMEM = "
芯片温度

{1}°C / {2}°F
";
const char HTTP_INFO_hall[] PROGMEM = "
霍尔传感器

{1}
";
#else
const char HTTP_INFO_esphead[] PROGMEM = "
ESP8266 信息

";
const char HTTP_INFO_fchipid[] PROGMEM = "
Flash 芯片 ID

{1}
";
const char HTTP_INFO_corever[] PROGMEM = "
Core 版本

{1}
";
const char HTTP_INFO_bootver[] PROGMEM = "
Boot 版本

{1}
";
const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

{1}
";
const char HTTP_INFO_flashsize[] PROGMEM = "
实际 Flash 大小

{1} 字节
";
#endif

const char HTTP_INFO_memsmeter[] PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";
const char HTTP_INFO_memsketch[] PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";
const char HTTP_INFO_freeheap[] PROGMEM = "
内存 - 可用堆

{1} 字节
";
const char HTTP_INFO_wifihead[] PROGMEM = "

WiFi 信息

";
const char HTTP_INFO_uptime[] PROGMEM = "
运行时间

{1} 分 {2} 秒
";
const char HTTP_INFO_chipid[] PROGMEM = "
芯片 ID

{1}
";
const char HTTP_INFO_idesize[] PROGMEM = "
Flash 大小

{1} 字节
";
const char HTTP_INFO_sdkver[] PROGMEM = "
SDK 版本

{1}
";
const char HTTP_INFO_cpufreq[] PROGMEM = "
CPU 频率

{1}MHz
";
const char HTTP_INFO_apip[] PROGMEM = "
AP IP 地址

{1}
";
const char HTTP_INFO_apmac[] PROGMEM = "
AP MAC 地址

{1}
";
const char HTTP_INFO_apssid[] PROGMEM = "
AP SSID

{1}
";
const char HTTP_INFO_apbssid[] PROGMEM = "
BSSID

{1}
";
const char HTTP_INFO_stassid[] PROGMEM = "
Station SSID

{1}
";
const char HTTP_INFO_staip[] PROGMEM = "
Station IP

{1}
";
const char HTTP_INFO_stagw[] PROGMEM = "
网关地址

{1}
";
const char HTTP_INFO_stasub[] PROGMEM = "
子网掩码

{1}
";
const char HTTP_INFO_dnss[] PROGMEM = "
DNS 服务器

{1}
";
const char HTTP_INFO_host[] PROGMEM = "
主机名

{1}
";
const char HTTP_INFO_stamac[] PROGMEM = "
Station MAC

{1}
";
const char HTTP_INFO_conx[] PROGMEM = "
连接状态

{1}
";
const char HTTP_INFO_autoconx[] PROGMEM = "
自动连接

{1}
";
const char HTTP_INFO_aboutver[] PROGMEM = "
WiFiManager 版本

{1}
";
const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino 版本

{1}
";
const char HTTP_INFO_aboutsdk[] PROGMEM = "
ESP-SDK/IDF 版本

{1}
";
const char HTTP_INFO_aboutdate[] PROGMEM = "
构建日期

{1}
";

// ====================== 文本常量 ======================
const char S_brand[] PROGMEM = "健康监测配网";
const char S_debugPrefix[] PROGMEM = "*wm:";
const char S_y[] PROGMEM = "是";
const char S_n[] PROGMEM = "否";
const char S_enable[] PROGMEM = "已启用";
const char S_disable[] PROGMEM = "已禁用";
const char S_GET[] PROGMEM = "GET";
const char S_POST[] PROGMEM = "POST";
const char S_NA[] PROGMEM = "未知";
const char S_passph[] PROGMEM = "********";
const char S_titlewifisaved[] PROGMEM = "WiFi 已保存";
const char S_titlewifisettings[] PROGMEM = "设置已保存";
const char S_titlewifi[] PROGMEM = "配置 WiFi";
const char S_titleinfo[] PROGMEM = "系统信息";
const char S_titleparam[] PROGMEM = "参数设置";
const char S_titleparamsaved[] PROGMEM = "设置已保存";
const char S_titleexit[] PROGMEM = "退出配网";
const char S_titlereset[] PROGMEM = "重置";
const char S_titleerase[] PROGMEM = "清除配置";
const char S_titleclose[] PROGMEM = "关闭页面";
const char S_options[] PROGMEM = "选项";
const char S_nonetworks[] PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";
const char S_staticip[] PROGMEM = "静态 IP";
const char S_staticgw[] PROGMEM = "静态网关";
const char S_staticdns[] PROGMEM = "静态 DNS";
const char S_subnet[] PROGMEM = "子网掩码";
const char S_exiting[] PROGMEM = "正在退出配网模式";
const char S_resetting[] PROGMEM = "设备将在几秒后重启";
const char S_closing[] PROGMEM = "可以关闭此页面，配网服务将继续运行";
const char S_error[] PROGMEM = "发生错误";
const char S_notfound[] PROGMEM = "页面未找到\n\n";
const char S_uri[] PROGMEM = "URI: ";
const char S_method[] PROGMEM = "\n请求方法: ";
const char S_args[] PROGMEM = "\n参数: ";
const char S_parampre[] PROGMEM = "param_";
const char D_HR[] PROGMEM = "--------------------";

#ifdef ESP8266
const char S_ssidpre[] PROGMEM = "ESP";
#elif defined(ESP32)
const char S_ssidpre[] PROGMEM = "ESP32";
#else
const char S_ssidpre[] PROGMEM = "WM";
#endif

#endif

- * WiFiManager, a library for the ESP8266/Arduino platform

- * for configuration of WiFi credentials using a Captive Portal

+ * 中文语言包 — 观照-五劳无感定制版

-// strings files must include a consts file!

-#include "wm_consts_en.h" // include constants, tokens, routes

-const char WM_LANGUAGE[] PROGMEM = "zh-CN"; // i18n lang code

+const char WM_LANGUAGE[] PROGMEM = "zh-CN";

-const char HTTP_HEAD_START[]       PROGMEM = "<!DOCTYPE html>"

+const char HTTP_HEAD_START[] PROGMEM = "<!DOCTYPE html>"

-"<meta  name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"

-const char HTTP_SCRIPT[]           PROGMEM = "<script>function c(l){"

+const char HTTP_SCRIPT[] PROGMEM = "<script>function c(l){"

-"function f() {var x = document.getElementById('p');x.type==='password'?x.type='text':x.type='password';}"

-const char HTTP_HEAD_END[]         PROGMEM = "
"; // {c} = _bodyclass

+const char HTTP_HEAD_END[] PROGMEM = "
"

+"

观照-五劳无感 · 设备配网

WiFi 联网与参数配置

"

+"
点击这里再次查看配网流程
"

-const char HTTP_ROOT_MAIN[]        PROGMEM = "
{t}

{v}
";

+const char HTTP_ROOT_MAIN[] PROGMEM = "";  // header 已在 HEAD_END 中

const char * const HTTP_PORTAL_MENU[] PROGMEM = {

-"<form action='/wifi'    method='get'><button>配置 WiFi</button></form><br/>\n",     // MENU_WIFI

-"<form action='/0wifi'   method='get'><button>配置 WiFi (不扫描)</button></form><br/>\n", // MENU_WIFINOSCAN

-"<form action='/info'    method='get'><button>系统信息</button></form><br/>\n",       // MENU_INFO

-"<form action='/param'   method='get'><button>参数设置</button></form><br/>\n",       // MENU_PARAM

-"<form action='/close'   method='get'><button>关闭页面</button></form><br/>\n",       // MENU_CLOSE

-"<form action='/restart' method='get'><button>重启设备</button></form><br/>\n",       // MENU_RESTART

-"<form action='/exit'    method='get'><button>退出配网</button></form><br/>\n",       // MENU_EXIT

-"<form action='/erase'   method='get'><button class='D'>清除配置</button></form><br/>\n", // MENU_ERASE

-"<form action='/update'  method='get'><button>固件升级</button></form><br/>\n",       // MENU_UPDATE

+"<form action='/wifi' method='get'><button>配置 WiFi</button></form><br/>\n",

+"<form action='/0wifi' method='get'><button>配置 WiFi (不扫描)</button></form><br/>\n",

+"<form action='/erase' method='get'><button class='D'>清除配置</button></form><br/>\n",

-const char HTTP_PORTAL_OPTIONS[]   PROGMEM = "";

-const char HTTP_ITEM_QI[]          PROGMEM = "

";

-const char HTTP_ITEM_QP[]          PROGMEM = "
{r}%
";

-const char HTTP_ITEM[]             PROGMEM = "
{v}{qi}{qp}
";

+const char HTTP_PORTAL_OPTIONS[] PROGMEM = "";

+const char HTTP_ITEM_QI[] PROGMEM = "

";

+const char HTTP_ITEM_QP[] PROGMEM = "
{r}%
";

+const char HTTP_ITEM[] PROGMEM = "
{v}{qi}{qp}
";

-const char HTTP_FORM_START[]       PROGMEM = "<form method='POST' action='{v}'>";

-const char HTTP_FORM_WIFI[]        PROGMEM = "WiFi 名称 (SSID)<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>
WiFi 密码<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'><input type='checkbox' id='showpass' onclick='f()'> 显示密码
";

-const char HTTP_FORM_WIFI_END[]    PROGMEM = "";

-const char HTTP_FORM_STATIC_HEAD[] PROGMEM = "

";

-const char HTTP_FORM_END[]         PROGMEM = "

<button type='submit'>保存配置</button></form>";

-const char HTTP_FORM_LABEL[]       PROGMEM = "<label for='{i}'>{t}</label>";

-const char HTTP_FORM_PARAM_HEAD[]  PROGMEM = "

";

-const char HTTP_FORM_PARAM[]       PROGMEM = "<br/><input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>\n";

+const char HTTP_FORM_START[] PROGMEM = "<form method='POST' action='{v}'>";

-const char HTTP_SCAN_LINK[]        PROGMEM = "<br/><form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";

-const char HTTP_SAVED[]            PROGMEM = "
正在保存配置
尝试连接 WiFi...
如果连接失败，请重新连接 AP 再试一次
";

-const char HTTP_PARAMSAVED[]       PROGMEM = "
配置已保存

";

-const char HTTP_END[]              PROGMEM = "
";

-const char HTTP_ERASEBTN[]         PROGMEM = "<br/><form action='/erase' method='get'><button class='D'>清除 WiFi 配置</button></form>";

-const char HTTP_UPDATEBTN[]        PROGMEM = "<br/><form action='/update' method='get'><button>固件升级</button></form>";

-const char HTTP_BACKBTN[]          PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";

+"
WiFi 名称
📡<input id='s' name='s' maxlength='32' autocorrect='off' autocapitalize='none' placeholder='{v}'>

"

+"
WiFi 密码
🔒<input id='p' name='p' maxlength='64' type='password' placeholder='{p}'>

"

+"<input type='checkbox' id='showpass' onclick='f()'> <label for='showpass'>显示密码</label>"

-const char HTTP_STATUS_ON[]        PROGMEM = "
已连接 {v}
IP 地址: {i}
";

-const char HTTP_STATUS_OFF[]       PROGMEM = "
未连接 {v}{r}
";

-const char HTTP_STATUS_OFFPW[]     PROGMEM = "<br/>WiFi 密码错误";

-const char HTTP_STATUS_OFFNOAP[]   PROGMEM = "<br/>未找到该 WiFi";

-const char HTTP_STATUS_OFFFAIL[]   PROGMEM = "<br/>无法连接";

-const char HTTP_STATUS_NONE[]      PROGMEM = "
未设置 WiFi
";

-const char HTTP_BR[]               PROGMEM = "<br/>";

+const char HTTP_FORM_WIFI_END[] PROGMEM = "";

-const char HTTP_STYLE[]            PROGMEM = "<style>"

+const char HTTP_FORM_STATIC_HEAD[] PROGMEM =

+"

⚙

设备基础信息

唯一标识与安装位置

";

+const char HTTP_FORM_PARAM_HEAD[] PROGMEM = "";

+const char HTTP_FORM_LABEL[] PROGMEM = "
{t}";

+const char HTTP_FORM_PARAM[] PROGMEM = "
#<input id='{i}' name='{n}' maxlength='{l}' value='{v}' {c}>

\n";

+"<button class='danger' type='button' onclick='document.location.reload()'>恢复出厂配置</button>"

+"
Health Monitor · Device Provisioning
"

+"

配网流程

按顺序完成 4 步操作

"

+"

1

选择 WiFi 并输入密码

确保手机已连接目标 2.4G 网络

"

+"

2

填写设备基础信息

设备编号与安装环境，便于多设备管理

"

+"

3

核对信息并保存

确认无误后点击保存配置

"

+"

4

等待设备重启连接

设备指示灯常亮即表示配网完成

"

+const char HTTP_SCAN_LINK[] PROGMEM = "<br/><form action='/wifi?refresh=1' method='POST'><button name='refresh' value='1'>重新扫描</button></form>";

+const char HTTP_SAVED[] PROGMEM = "
配置已保存
正在连接 WiFi...
";

+const char HTTP_PARAMSAVED[] PROGMEM = "
配置已保存

";

+const char HTTP_ERASEBTN[] PROGMEM = "<br/><form action='/erase' method='get'><button class='danger'>清除 WiFi 配置</button></form>";

+const char HTTP_UPDATEBTN[] PROGMEM = "<br/><form action='/update' method='get'><button>固件升级</button></form>";

+const char HTTP_BACKBTN[] PROGMEM = "

<form action='/' method='get'><button>返回首页</button></form>";

+const char HTTP_STATUS_ON[] PROGMEM = "
已连接 {v}
IP 地址: {i}
";

+const char HTTP_STATUS_OFF[] PROGMEM = "
未连接 {v}{r}
";

+const char HTTP_STATUS_OFFPW[] PROGMEM = "<br/>WiFi 密码错误";

+const char HTTP_STATUS_OFFNOAP[] PROGMEM = "<br/>未找到该 WiFi";

+const char HTTP_STATUS_OFFFAIL[] PROGMEM = "<br/>无法连接";

+const char HTTP_STATUS_NONE[] PROGMEM = "
未设置 WiFi
";

+const char HTTP_BR[] PROGMEM = "<br/>";

+const char HTTP_STYLE[] PROGMEM = "<style>"

-"@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){.q:before,.q:after {"

-".msg{padding:20px;margin:20px 0;border:1px solid #eee;border-left-width:5px;border-left-color:#777}.msg h4{margin-top:0;margin-bottom:5px}.msg.P{border-left-color:#1fa3ec}.msg.P h4{color:#1fa3ec}.msg.D{border-left-color:#dc3630}.msg.D h4{color:#dc3630}.msg.S{border-left-color: #5cb85c}.msg.S h4{color: #5cb85c}"

-"dt{font-weight:bold}dd{margin:0;padding:0 0 0.5em 0;min-height:12px}"

+"dt{font-weight:bold}dd{margin:0;padding:0 0 .5em 0;min-height:12px}"

-"button{transition: 0s opacity;transition-delay: 3s;transition-duration: 0s;cursor: pointer}"

-"body.invert,body.invert a,body.invert h1 {background-color:#060606;color:#fff;}"

-"body.invert .msg{color:#fff;background-color:#282828;border-top:1px solid #555;border-right:1px solid #555;border-bottom:1px solid #555;}"

+"body.invert .msg{color:#fff;background-color:#282828;border-top:1px solid #555;border-right:1px solid #555;border-bottom:1px solid #555}"

-const char HTTP_HELP[]             PROGMEM =

- "

可用页面

"

- "

页面	功能

"

- "保存 WiFi 配置并连接设备
"

- "关闭弹出窗口，配网服务保持运行
"

- "退出配网模式，配网服务将关闭
"

- "清除 WiFi 配置并重启。清除后设备不会自动连接，需重新配网
"

- "
GitHub https://github.com/tzapu/WiFiManager.";

+"

页面	功能

"

+"
/	主菜单页面
"

-const char HTTP_HELP[]             PROGMEM = "";

-const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display = el.value=='' ? 'none' : 'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果在配网页面内无法使用，请在浏览器中打开 http://192.168.4.1";

+const char HTTP_UPDATE[] PROGMEM = "上传新固件
<form method='POST' action='u' enctype='multipart/form-data' onchange=\"(function(el){document.getElementById('uploadbin').style.display=el.value==''?'none':'initial';})(this)\"><input type='file' name='update' accept='.bin,application/octet-stream'><button id='uploadbin' type='submit' class='h D'>开始升级</button></form>* 如果无法使用，请在浏览器中打开 http://192.168.4.1";

const char HTTP_UPDATE_FAIL[] PROGMEM = "
升级失败!
请重启设备后重试
";

const char HTTP_UPDATE_SUCCESS[] PROGMEM = "
升级成功!
设备正在重启...
";

-"<script>function postAjax(url, data, success) {"

-"    var params = typeof data == 'string' ? data : Object.keys(data).map("

-"            function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }"

-"    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject(\"Microsoft.XMLHTTP\");"

-"    xhr.onreadystatechange = function() {"

-"        if (xhr.readyState>3 && xhr.status==200) { success(xhr.responseText); }"

-"    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');"

-"    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');"

-"postAjax('/status', 'p1=1&p2=Hello+World', function(data){ console.log(data); });"

-"postAjax('/status', { p1: 1, p2: 'Hello World' }, function(data){ console.log(data); });"

-  const char HTTP_INFO_esphead[]    PROGMEM = "
ESP32 信息

";

-  const char HTTP_INFO_chiprev[]    PROGMEM = "
芯片版本

{1}
";

-  	const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";

-  	const char HTTP_INFO_aphost[]     PROGMEM = "
AP 主机名

{1}
";

-    const char HTTP_INFO_psrsize[]    PROGMEM = "
PSRAM 大小

{1} 字节
";

-  const char HTTP_INFO_temp[]       PROGMEM = "
芯片温度

{1}°C / {2}°F
";

-    const char HTTP_INFO_hall[]       PROGMEM = "
霍尔传感器

{1}
";

+const char HTTP_INFO_esphead[] PROGMEM = "
ESP32 信息

";

+const char HTTP_INFO_chiprev[] PROGMEM = "
芯片版本

{1}
";

+const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

CPU0: {1}
CPU1: {2}
";

+const char HTTP_INFO_aphost[] PROGMEM = "
AP 主机名

{1}
";

+const char HTTP_INFO_psrsize[] PROGMEM = "
PSRAM 大小

{1} 字节
";

+const char HTTP_INFO_temp[] PROGMEM = "
芯片温度

{1}°C / {2}°F
";

+const char HTTP_INFO_hall[] PROGMEM = "
霍尔传感器

{1}
";

-  const char HTTP_INFO_esphead[]    PROGMEM = "
ESP8266 信息

";

-  const char HTTP_INFO_fchipid[]    PROGMEM = "
Flash 芯片 ID

{1}
";

-  const char HTTP_INFO_corever[]    PROGMEM = "
Core 版本

{1}
";

-  const char HTTP_INFO_bootver[]    PROGMEM = "
Boot 版本

{1}
";

-  const char HTTP_INFO_lastreset[]  PROGMEM = "
上次复位原因

{1}
";

-  const char HTTP_INFO_flashsize[]  PROGMEM = "
实际 Flash 大小

{1} 字节
";

+const char HTTP_INFO_esphead[] PROGMEM = "
ESP8266 信息

";

+const char HTTP_INFO_fchipid[] PROGMEM = "
Flash 芯片 ID

{1}
";

+const char HTTP_INFO_corever[] PROGMEM = "
Core 版本

{1}
";

+const char HTTP_INFO_bootver[] PROGMEM = "
Boot 版本

{1}
";

+const char HTTP_INFO_lastreset[] PROGMEM = "
上次复位原因

{1}
";

+const char HTTP_INFO_flashsize[] PROGMEM = "
实际 Flash 大小

{1} 字节
";

-const char HTTP_INFO_memsmeter[]  PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";

-const char HTTP_INFO_memsketch[]  PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";

-const char HTTP_INFO_freeheap[]   PROGMEM = "
内存 - 可用堆

{1} 字节
";

-const char HTTP_INFO_wifihead[]   PROGMEM = "

WiFi 信息

";

-const char HTTP_INFO_uptime[]     PROGMEM = "
运行时间

{1} 分 {2} 秒
";

-const char HTTP_INFO_chipid[]     PROGMEM = "
芯片 ID

{1}
";

-const char HTTP_INFO_idesize[]    PROGMEM = "
Flash 大小

{1} 字节
";

-const char HTTP_INFO_sdkver[]     PROGMEM = "
SDK 版本

{1}
";

-const char HTTP_INFO_cpufreq[]    PROGMEM = "
CPU 频率

{1}MHz
";

-const char HTTP_INFO_apip[]       PROGMEM = "
AP IP 地址

{1}
";

-const char HTTP_INFO_apmac[]      PROGMEM = "
AP MAC 地址

{1}
";

-const char HTTP_INFO_apssid[]     PROGMEM = "
AP SSID

{1}
";

-const char HTTP_INFO_apbssid[]    PROGMEM = "
BSSID

{1}
";

-const char HTTP_INFO_stassid[]    PROGMEM = "
Station SSID

{1}
";

-const char HTTP_INFO_staip[]      PROGMEM = "
Station IP

{1}
";

-const char HTTP_INFO_stagw[]      PROGMEM = "
网关地址

{1}
";

-const char HTTP_INFO_stasub[]     PROGMEM = "
子网掩码

{1}
";

-const char HTTP_INFO_dnss[]       PROGMEM = "
DNS 服务器

{1}
";

-const char HTTP_INFO_host[]       PROGMEM = "
主机名

{1}
";

-const char HTTP_INFO_stamac[]     PROGMEM = "
Station MAC

{1}
";

-const char HTTP_INFO_conx[]       PROGMEM = "
连接状态

{1}
";

-const char HTTP_INFO_autoconx[]   PROGMEM = "
自动连接

{1}
";

-const char HTTP_INFO_aboutver[]     PROGMEM = "
WiFiManager 版本

{1}
";

+const char HTTP_INFO_memsmeter[] PROGMEM = "
<progress value='{1}' max='{2}'></progress>
";

+const char HTTP_INFO_memsketch[] PROGMEM = "
内存 - 程序大小

已用 / 总计
{1} / {2} 字节";

+const char HTTP_INFO_freeheap[] PROGMEM = "
内存 - 可用堆

{1} 字节
";

+const char HTTP_INFO_wifihead[] PROGMEM = "

WiFi 信息

";

+const char HTTP_INFO_uptime[] PROGMEM = "
运行时间

{1} 分 {2} 秒
";

+const char HTTP_INFO_chipid[] PROGMEM = "
芯片 ID

{1}
";

+const char HTTP_INFO_idesize[] PROGMEM = "
Flash 大小

{1} 字节
";

+const char HTTP_INFO_sdkver[] PROGMEM = "
SDK 版本

{1}
";

+const char HTTP_INFO_cpufreq[] PROGMEM = "
CPU 频率

{1}MHz
";

+const char HTTP_INFO_apip[] PROGMEM = "
AP IP 地址

{1}
";

+const char HTTP_INFO_apmac[] PROGMEM = "
AP MAC 地址

{1}
";

+const char HTTP_INFO_apssid[] PROGMEM = "
AP SSID

{1}
";

+const char HTTP_INFO_apbssid[] PROGMEM = "
BSSID

{1}
";

+const char HTTP_INFO_stassid[] PROGMEM = "
Station SSID

{1}
";

+const char HTTP_INFO_staip[] PROGMEM = "
Station IP

{1}
";

+const char HTTP_INFO_stagw[] PROGMEM = "
网关地址

{1}
";

+const char HTTP_INFO_stasub[] PROGMEM = "
子网掩码

{1}
";

+const char HTTP_INFO_dnss[] PROGMEM = "
DNS 服务器

{1}
";

+const char HTTP_INFO_host[] PROGMEM = "
主机名

{1}
";

+const char HTTP_INFO_stamac[] PROGMEM = "
Station MAC

{1}
";

+const char HTTP_INFO_conx[] PROGMEM = "
连接状态

{1}
";

+const char HTTP_INFO_autoconx[] PROGMEM = "
自动连接

{1}
";

+const char HTTP_INFO_aboutver[] PROGMEM = "
WiFiManager 版本

{1}
";

const char HTTP_INFO_aboutarduino[] PROGMEM = "
Arduino 版本

{1}
";

-const char HTTP_INFO_aboutsdk[]     PROGMEM = "
ESP-SDK/IDF 版本

{1}
";

-const char HTTP_INFO_aboutdate[]    PROGMEM = "
构建日期

{1}
";

+const char HTTP_INFO_aboutsdk[] PROGMEM = "
ESP-SDK/IDF 版本

{1}
";

+const char HTTP_INFO_aboutdate[] PROGMEM = "
构建日期

{1}
";

-const char S_brand[]              PROGMEM = "健康监测配网";

-const char S_debugPrefix[]        PROGMEM = "*wm:";

-const char S_y[]                  PROGMEM = "是";

-const char S_n[]                  PROGMEM = "否";

-const char S_enable[]             PROGMEM = "已启用";

-const char S_disable[]            PROGMEM = "已禁用";

-const char S_GET[]                PROGMEM = "GET";

-const char S_POST[]               PROGMEM = "POST";

-const char S_NA[]                 PROGMEM = "未知";

-const char S_passph[]             PROGMEM = "********";

-const char S_titlewifisaved[]     PROGMEM = "WiFi 已保存";

-const char S_titlewifisettings[]  PROGMEM = "设置已保存";

-const char S_titlewifi[]          PROGMEM = "配置 WiFi";

-const char S_titleinfo[]          PROGMEM = "系统信息";

-const char S_titleparam[]         PROGMEM = "参数设置";

-const char S_titleparamsaved[]    PROGMEM = "设置已保存";

-const char S_titleexit[]          PROGMEM = "退出配网";

-const char S_titlereset[]         PROGMEM = "重置";

-const char S_titleerase[]         PROGMEM = "清除配置";

-const char S_titleclose[]         PROGMEM = "关闭页面";

-const char S_options[]            PROGMEM = "选项";

-const char S_nonetworks[]         PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";

-const char S_staticip[]           PROGMEM = "静态 IP";

-const char S_staticgw[]           PROGMEM = "静态网关";

-const char S_staticdns[]          PROGMEM = "静态 DNS";

-const char S_subnet[]             PROGMEM = "子网掩码";

-const char S_exiting[]            PROGMEM = "正在退出配网模式";

-const char S_resetting[]          PROGMEM = "设备将在几秒后重启";

-const char S_closing[]            PROGMEM = "可以关闭此页面，配网服务将继续运行";

-const char S_error[]              PROGMEM = "发生错误";

-const char S_notfound[]           PROGMEM = "页面未找到\n\n";

-const char S_uri[]                PROGMEM = "URI: ";

-const char S_method[]             PROGMEM = "\n请求方法: ";

-const char S_args[]               PROGMEM = "\n参数: ";

-const char S_parampre[]           PROGMEM = "param_";

+const char S_brand[] PROGMEM = "健康监测配网";

+const char S_debugPrefix[] PROGMEM = "*wm:";

+const char S_disable[] PROGMEM = "已禁用";

+const char S_passph[] PROGMEM = "********";

+const char S_titlewifisaved[] PROGMEM = "WiFi 已保存";

+const char S_titlewifisettings[] PROGMEM = "设置已保存";

+const char S_titlewifi[] PROGMEM = "配置 WiFi";

+const char S_titleinfo[] PROGMEM = "系统信息";

+const char S_titleparam[] PROGMEM = "参数设置";

+const char S_titleparamsaved[] PROGMEM = "设置已保存";

+const char S_titleexit[] PROGMEM = "退出配网";

+const char S_titlereset[] PROGMEM = "重置";

+const char S_titleerase[] PROGMEM = "清除配置";

+const char S_titleclose[] PROGMEM = "关闭页面";

+const char S_nonetworks[] PROGMEM = "未发现 WiFi 网络，请点击刷新重新扫描。";

+const char S_staticip[] PROGMEM = "静态 IP";

+const char S_staticgw[] PROGMEM = "静态网关";

+const char S_staticdns[] PROGMEM = "静态 DNS";

+const char S_subnet[] PROGMEM = "子网掩码";

+const char S_exiting[] PROGMEM = "正在退出配网模式";

+const char S_resetting[] PROGMEM = "设备将在几秒后重启";

+const char S_closing[] PROGMEM = "可以关闭此页面，配网服务将继续运行";

+const char S_notfound[] PROGMEM = "页面未找到\n\n";

+const char S_method[] PROGMEM = "\n请求方法: ";

+const char S_args[] PROGMEM = "\n参数: ";

+const char S_parampre[] PROGMEM = "param_";

-    const char S_ssidpre[]        PROGMEM = "ESP";

+const char S_ssidpre[] PROGMEM = "ESP";

-    const char S_ssidpre[]        PROGMEM = "ESP32";

+const char S_ssidpre[] PROGMEM = "ESP32";

-    const char S_ssidpre[]        PROGMEM = "WM";