首页 / 资讯中心 / 文章详情

ESP32 NVS 浏览器编辑器:免重刷固件动态修改 WiFi 配置

ESP32 NVS 浏览器编辑器:免重刷固件动态修改 WiFi 配置 ★ FEATURED ARTICLE
1. 从一个真实痛点说起改个 WiFi 密码为什么要重刷固件搞 ESP32 的朋友大概率都遇到过这个场景设备已经装到现场了外壳封好、螺丝拧死甚至灌了胶结果甲方一个电话打过来——“WiFi 密码换了你过来改一下”。你心里清楚改密码这事在代码里就是改两行字符串但问题是这两行字符串被编译进了固件里要改就得重新编译、重新烧录人还得跑一趟现场。更难受的是有些设备装在吊顶里、配电箱里、户外立杆上拆一次的成本远超改密码本身。我见过最夸张的一个案例某环境监测项目二十多个节点分布在三栋楼里就为了改个 WiFi 密码两个工程师跑了两天。这个问题的根源在于很多人把 WiFi 配置硬编码在了源码里比如const char* ssid MyWiFi;这种写法。编译之后这些字符串就固化在 flash 的代码段里了运行时只读改不了。而 ESP32 其实自带了一套非易失性存储机制——NVSNon-Volatile Storage专门用来存这种需要掉电保存、又要能动态修改的键值对数据。WiFi 的 SSID 和密码完全可以存在 NVS 里程序启动时读出来用改密码的时候只改 NVS 就行根本不用碰固件。那怎么改 NVS传统做法是串口发命令、或者自己写个 Web 服务器、或者用蓝牙配网。这些方案各有各的麻烦串口要接线Web 服务器要占代码空间还得处理各种请求蓝牙配网对普通用户来说门槛太高。而今天要聊的这个思路是用浏览器直接读写 ESP32 的 NVS 键值——电脑或手机打开一个网页连上设备就能看到当前存了哪些键、值是什么直接改完保存重启生效。整个过程不需要重新编译不需要烧录工具甚至不需要装任何 App。这篇文章我会把这个方案的来龙去脉讲透NVS 到底是怎么工作的、为什么它能被浏览器访问、整个工具链怎么搭、代码怎么写、踩过哪些坑。不管你是刚接触 ESP32 的新手还是已经做过几个项目的老手应该都能从中拿到能直接用的东西。2. NVS 到底是个什么东西先搞懂原理再动手2.1 NVS 在 ESP32 里的定位和存储结构NVS 是 ESP-IDF 提供的一个键值存储库底层跑在 SPI Flash 上通过分区表划出一块独立区域通常叫nvs分区默认大小 0x6000 即 24KB。它跟文件系统SPIFFS、LittleFS、FATFS是并列关系但定位完全不同文件系统适合存大块数据、日志、网页资源NVS 适合存小块的、结构化的、频繁读写的配置项比如 WiFi 凭据、设备 ID、校准参数、用户偏好。它的存储结构可以类比成一个“带索引的抽屉柜”。每个键值对叫一个 entry键是字符串最长 15 字符值支持多种类型uint8_t、int8_t、uint16_t、int16_t、uint32_t、int32_t、uint64_t、int64_t、字符串、二进制 blob。命名空间namespace相当于抽屉的分层不同命名空间下的同名键互不干扰。比如 WiFi 配置放在wifi_config命名空间设备参数放在device_cfg命名空间各管各的。为什么 NVS 能掉电保存又支持频繁改写因为它用了日志式写入 页擦除的机制。Flash 的物理特性是只能把 1 写成 0要把 0 变回 1 必须整页擦除。NVS 的做法是写入新值时不覆盖旧值而是在后面追加一条新记录旧记录标记为失效。当一页写满了才触发一次垃圾回收把有效数据搬到新页擦除旧页。这样既延长了 flash 寿命又保证了掉电时数据不会丢——因为任何时刻至少有一份完整数据在。注意NVS 的键名长度上限是 15 个字符不含结尾的\0命名空间名上限也是 15 字符。超了会直接报错这个坑我在第一次用的时候踩过键名写了个wifi_configuration编译能过但运行时报ESP_ERR_NVS_KEY_TOO_LONG排查了半天。2.2 为什么把 WiFi 配置放 NVS 而不是硬编码硬编码的问题前面说了改一次要重刷。但还有几个隐性好处值得说清楚。第一是多环境适配。同一份固件出厂时 NVS 是空的设备第一次启动进入配网模式用户填好 WiFi 信息存进 NVS之后就一直用。这样一份固件可以发给所有客户不用为每个客户单独编译。第二是恢复出厂设置变得简单。只要擦除 NVS 分区或者只擦除某个命名空间设备就回到未配置状态重新配网即可。比在代码里写一堆#ifdef判断要干净得多。第三是参数可远程下发。除了 WiFi很多运行参数上报间隔、阈值、灵敏度也可以放 NVS配合 OTA 或者配置接口动态调整不用为了改个阈值就发新固件。第四是调试友好。设备出问题时直接读 NVS 看当前配置是什么比翻代码猜“到底编译进去的是哪个值”要靠谱得多。2.3 浏览器访问 NVS 的技术可行性分析浏览器要读写 ESP32 的 NVS中间必须有一条通信链路。ESP32 本身是个 MCU没有屏幕没有键盘浏览器跑在电脑或手机上两者怎么连常见方案有几种串口Web Serial API、蓝牙Web Bluetooth API、WiFiHTTP/WebSocket。串口和蓝牙都需要浏览器支持对应的 Web APIChrome 系支持得还行但 Safari 和 Firefox 就够呛而且用户要手动授权、选设备体验一般。WiFi 方案最通用——只要设备和浏览器在同一个局域网打开网页就能用手机电脑都行不挑浏览器。所以这个工具的核心思路是ESP32 上跑一个轻量 HTTP 服务器提供读写 NVS 的接口浏览器打开一个网页通过 HTTP 请求调用这些接口把 NVS 的键值渲染成表单用户改完提交服务器写回 NVS。整个链路就是标准的 Web 技术没有任何黑魔法。这里有个关键点HTTP 服务器本身要占资源。ESP32 的 RAM 有限通常几百 KB 可用跑一个完整的 Web 服务器 网页资源得精打细算。好在 ESP-IDF 自带的esp_http_server组件足够轻量网页资源可以放在 flash 里用EMBED_FILES或者 SPIFFS不占 RAM。实测下来一个功能完整的 NVS 编辑器固件增量大概 100~200KBRAM 占用 20~30KB对大多数项目来说可以接受。3. 方案选型为什么是 HTTP 浏览器而不是别的3.1 几种常见 NVS 修改方案的横向对比在动手之前我把能想到的方案都列出来对比了一遍这样你选型的时候心里有数。方案实现难度用户体验资源占用跨平台性适用场景串口命令行低差要接线装驱动极低差开发调试蓝牙配网中中要装 App中中消费级产品自建 Web 服务器中好浏览器直接开中好局域网设备物理按键 LED 指示低差操作繁琐极低好简单设备浏览器工具本方案中好功能完整中好需要频繁改配置串口方案最直接但现场设备往往没有串口引出而且普通用户不会用。蓝牙配网体验不错但需要开发 App 或者用现成的配网库而且蓝牙和 WiFi 共存时射频资源紧张容易出问题。物理按键方案适合只有一两个参数要改的场景参数一多就没法用了。浏览器方案的优势在于零安装、跨平台、界面可以做得很好看、能同时管理多个参数。缺点是设备必须和浏览器在同一局域网如果设备已经连不上 WiFi比如密码错了那就得先想办法让设备进入 AP 模式浏览器连上设备的热点再改。这个后面会讲怎么处理。3.2 HTTP 服务器的选型esp_http_server vs 其他ESP-IDF 里做 HTTP 服务器主流选择是官方的esp_http_server。也有用libesphttpd或者自己撸 socket 的但没必要。esp_http_server的优势是官方维护跟 IDF 版本同步更新支持 URI 注册、GET/POST、WebSocket、文件上传内存占用可控可以配置最大连接数、URI 数量跟 NVS、WiFi 组件集成度高配置上主要关注几个参数max_uri_handlers注册多少个接口、max_open_sockets同时几个连接、stack_size服务器任务栈大小。我一般设max_uri_handlers8、max_open_sockets4、stack_size8192够用且不浪费。实操心得esp_http_server默认的 URI 匹配是精确匹配如果你要处理/api/nvs/*这种通配得用httpd_uri_match_wildcard注册。我第一次写的时候没注意注册了/api/nvs结果/api/nvs/get一直 404查文档才发现要单独注册或者用通配匹配。3.3 前端页面的组织方式内嵌 vs SPIFFS网页资源HTML、CSS、JS放哪里有两个选择编译进固件内嵌或者放 SPIFFS 分区。内嵌的好处是简单用EMBED_FILES把文件转成 C 数组直接返回。缺点是改网页要重新编译固件而且大文件会撑大固件体积。SPIFFS 的好处是网页可以单独更新通过文件上传接口固件体积小。缺点是要多管理一个分区而且 SPIFFS 的读写速度比直接读 flash 慢一点。我的建议是如果网页不常改用内嵌如果网页要频繁迭代用 SPIFFS。这个 NVS 编辑器的网页其实不复杂一个 HTML 文件加一点 JS压缩后 10KB 左右内嵌完全没问题。而且内嵌的话整个工具就是一个固件烧进去就能用不用额外上传网页文件对用户更友好。4. 核心实现从 NVS 读写到 HTTP 接口的完整链路4.1 NVS 初始化与命名空间管理先看 NVS 的初始化。ESP-IDF 里用 NVS 之前必须先调用nvs_flash_init()而且要考虑 flash 版本升级、分区损坏等情况。esp_err_t ret nvs_flash_init(); if (ret ESP_ERR_NVS_NO_FREE_PAGES || ret ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret nvs_flash_init(); } ESP_ERROR_CHECK(ret);这段代码几乎是标配如果 NVS 分区满了或者版本不匹配先擦除再初始化。擦除会丢失所有已存数据所以只在初始化失败时做。命名空间的管理上我建议按功能划分。WiFi 配置用一个命名空间wifi_cfg里面存ssid、password、static_ip等键。设备参数用dev_cfg存device_id、report_interval等。这样读写的时候逻辑清晰也方便单独擦除某个命名空间。nvs_handle_t handle; esp_err_t err nvs_open(wifi_cfg, NVS_READWRITE, handle); if (err ! ESP_OK) { ESP_LOGE(TAG, 打开命名空间失败: %s, esp_err_to_name(err)); return; } // 读字符串 size_t len 0; nvs_get_str(handle, ssid, NULL, len); // 先获取长度 char* ssid malloc(len); nvs_get_str(handle, ssid, ssid, len); // 写字符串 nvs_set_str(handle, ssid, NewWiFi); nvs_commit(handle); // 必须 commit 才真正写入 nvs_close(handle);这里有个容易忽略的点nvs_set_*只是把数据写到缓存必须调用nvs_commit才真正落盘。我见过有人写完没 commit重启后数据没了还以为是 flash 坏了。4.2 枚举 NVS 中所有键值的实现细节浏览器工具要展示“当前存了哪些键”就得枚举 NVS。NVS 提供了迭代器接口nvs_iterator_t it NULL; esp_err_t res nvs_entry_find(nvs, wifi_cfg, NVS_TYPE_ANY, it); while (res ESP_OK) { nvs_entry_info_t info; nvs_entry_info(it, info); // info.key 是键名info.type 是类型 // 根据类型读取值 res nvs_entry_next(it); } nvs_release_iterator(it);注意nvs_entry_find的第一个参数是分区名通常是nvs第二个是命名空间传NULL表示所有命名空间。这个接口在不同 IDF 版本里签名有变化5.0 之后是nvs_entry_find(partition, namespace, type, it)老版本是nvs_entry_find(namespace, type, it)移植代码的时候要注意。枚举出来之后根据类型分别读取。字符串和 blob 要先查长度再分配内存整数直接读。这里要处理一个边界情况如果某个键的值特别大比如一个几 KB 的 blob返回给浏览器的时候要限制大小不然 HTTP 响应会爆掉。我一般限制单个值不超过 1KB超了就只返回“值过大请用其他方式查看”。4.3 HTTP 接口设计RESTful 风格的读写接口接口设计上我用了最朴素的 RESTful 风格方法路径功能请求体响应GET/api/nvs/list列出所有键值无JSON 数组GET/api/nvs/get?nsxxxkeyyyy读单个键无JSON 对象POST/api/nvs/set写单个键JSON状态码POST/api/nvs/erase擦除命名空间JSON状态码GET/返回网页无HTML为什么用 JSON 而不是表单因为 NVS 的值有类型JSON 能自然表达字符串、数字、布尔。而且前端用fetch发 JSON 很方便不用处理表单编码。写接口的实现要注意先解析 JSON再根据类型调用对应的nvs_set_*。ESP-IDF 自带cJSON库解析起来不费劲。cJSON* root cJSON_Parse(req_body); cJSON* ns cJSON_GetObjectItem(root, ns); cJSON* key cJSON_GetObjectItem(root, key); cJSON* value cJSON_GetObjectItem(root, value); cJSON* type cJSON_GetObjectItem(root, type); nvs_handle_t handle; nvs_open(ns-valuestring, NVS_READWRITE, handle); if (strcmp(type-valuestring, str) 0) { nvs_set_str(handle, key-valuestring, value-valuestring); } else if (strcmp(type-valuestring, i32) 0) { nvs_set_i32(handle, key-valuestring, value-valueint); } else if (strcmp(type-valuestring, u8) 0) { nvs_set_u8(handle, key-valuestring, (uint8_t)value-valueint); } nvs_commit(handle); nvs_close(handle);注意nvs_set_str的键名和值都不能包含\0以外的特殊字符而且值如果是空字符串某些 IDF 版本会报错。我一般在前端做校验空值直接拒绝提交。4.4 前端页面把 NVS 键值渲染成可编辑表单前端部分其实不复杂核心就三件事加载时拉取键值列表、渲染成表格、提交时发 POST 请求。async function loadNVS() { const resp await fetch(/api/nvs/list); const data await resp.json(); const tbody document.querySelector(#nvs-table tbody); tbody.innerHTML ; data.items.forEach(item { const tr document.createElement(tr); tr.innerHTML td${item.ns}/td td${item.key}/td td${item.type}/td tdinput value${item.value}>idf_component_register( SRCS main.c nvs_api.c INCLUDE_DIRS . EMBED_FILES www/index.html )这样编译后index.html的内容会变成_binary_index_html_start和_binary_index_html_end两个符号可以直接当字符串用。5.2 WiFi 连接与 HTTP 服务器启动设备启动后先连 WiFi。这里有个鸡生蛋蛋生鸡的问题如果 NVS 里没存 WiFi 信息或者存的信息连不上设备就上不了网浏览器也访问不了它。所以要有 fallback 机制——连不上就开 AP 模式自己当热点。void wifi_init(void) { // 先从 NVS 读 WiFi 配置 char ssid[32] {0}, password[64] {0}; nvs_handle_t handle; if (nvs_open(wifi_cfg, NVS_READONLY, handle) ESP_OK) { size_t len sizeof(ssid); nvs_get_str(handle, ssid, ssid, len); len sizeof(password); nvs_get_str(handle, password, password, len); nvs_close(handle); } if (strlen(ssid) 0) { // 没配置开 AP 模式 start_ap_mode(); } else { // 有配置尝试连接 if (connect_sta(ssid, password) ! ESP_OK) { // 连不上也开 AP 模式 start_ap_mode(); } } }AP 模式的 SSID 我一般设成ESP32_Config_XXXXXXXX 是 MAC 后四位密码留空或者设个简单的。用户连上这个热点浏览器打开192.168.4.1就能进 NVS 编辑器把正确的 WiFi 信息填进去保存后重启设备就能连上正常 WiFi 了。HTTP 服务器在 WiFi 连上之后启动httpd_config_t config HTTPD_DEFAULT_CONFIG(); config.max_uri_handlers 8; config.max_open_sockets 4; config.stack_size 8192; config.uri_match_fn httpd_uri_match_wildcard; httpd_handle_t server NULL; if (httpd_start(server, config) ESP_OK) { httpd_register_uri_handler(server, uri_list); httpd_register_uri_handler(server, uri_get); httpd_register_uri_handler(server, uri_set); httpd_register_uri_handler(server, uri_erase); httpd_register_uri_handler(server, uri_root); }5.3 关键接口的代码实现与参数说明/api/nvs/list的实现是核心因为它要枚举所有命名空间和键。这里有个细节nvs_entry_find传NULL作为命名空间时会遍历所有命名空间但返回的info.ns字段在有些 IDF 版本里是空的。稳妥的做法是先枚举所有命名空间再逐个枚举键。// 枚举所有命名空间通过遍历所有 entry 收集 static esp_err_t list_handler(httpd_req_t *req) { cJSON* root cJSON_CreateArray(); nvs_iterator_t it NULL; esp_err_t res nvs_entry_find(nvs, NULL, NVS_TYPE_ANY, it); while (res ESP_OK) { nvs_entry_info_t info; nvs_entry_info(it, info); cJSON* item cJSON_CreateObject(); cJSON_AddStringToObject(item, ns, info.namespace_name); cJSON_AddStringToObject(item, key, info.key); cJSON_AddStringToObject(item, type, type_to_str(info.type)); // 读取值 char value_str[256] {0}; read_value_as_string(info.namespace_name, info.key, info.type, value_str, sizeof(value_str)); cJSON_AddStringToObject(item, value, value_str); cJSON_AddItemToArray(root, item); res nvs_entry_next(it); } nvs_release_iterator(it); char* out cJSON_PrintUnformatted(root); httpd_resp_set_type(req, application/json); httpd_resp_send(req, out, strlen(out)); free(out); cJSON_Delete(root); return ESP_OK; }read_value_as_string是个辅助函数根据类型调用对应的nvs_get_*然后转成字符串。整数用snprintf字符串直接拷贝blob 转成 hex 字符串限制长度。/api/nvs/set的实现前面给过片段完整版要处理错误JSON 解析失败返回 400NVS 打开失败返回 500写入失败返回 500 并带上错误码。响应体统一用 JSON方便前端处理。5.4 网页端交互与实时反馈网页端除了基本的列表和编辑我还加了几个实用功能搜索过滤键多了之后找某个键很麻烦。加个搜索框输入关键字实时过滤表格行。类型提示鼠标悬停在类型列上显示这个类型的取值范围。比如u8显示 0~255i32显示 -2147483648~2147483647。批量保存改多个键的时候一个个点保存太累。加个“全部保存”按钮遍历所有修改过的输入框依次发请求。危险操作确认擦除命名空间是不可逆的点按钮后弹个确认框要求输入命名空间名才能执行。这个设计借鉴了 GitHub 删除仓库的交互能有效防止误操作。async function eraseNamespace(ns) { const input prompt(输入命名空间名 ${ns} 以确认擦除); if (input ! ns) { alert(命名空间名不匹配操作取消); return; } await fetch(/api/nvs/erase, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({ns: ns}) }); loadNVS(); }6. 踩坑实录那些文档里不会写的问题6.1 NVS 键名长度与字符限制的坑前面提过键名最长 15 字符但还有个更隐蔽的限制键名不能包含空格和特殊字符。我试过用wifi ssid带空格当键名nvs_set_str返回ESP_ERR_NVS_KEY_TOO_LONG但这个错误码其实有误导性实际原因是字符不合法。后来查源码才发现NVS 对键名的校验是strlen(key) 15 || strchr(key, ) ! NULL之类的逻辑错误码没细分。所以键名规范建议只用小写字母、数字、下划线长度控制在 15 以内。比如wifi_ssid、dev_id、report_int。这样既安全又易读。6.2 字符串值长度与内存分配的陷阱nvs_get_str的标准用法是调两次第一次传NULL获取长度第二次分配内存再读。但有个坑如果第一次调用时键不存在返回的是ESP_ERR_NVS_NOT_FOUND长度变量不会被设置。如果不检查返回值就直接malloc(len)len 可能是 0 或者随机值导致 malloc 失败或者分配过小。正确做法size_t len 0; esp_err_t err nvs_get_str(handle, key, NULL, len); if (err ! ESP_OK) { // 键不存在或其他错误直接返回 return err; } char* buf malloc(len); if (buf NULL) return ESP_ERR_NO_MEM; err nvs_get_str(handle, key, buf, len); // 用完 free(buf)6.3 HTTP 请求体过大导致的解析失败esp_http_server默认的请求体缓冲区大小有限HTTPD_DEFAULT_CONFIG里recv_wait_timeout和缓冲区相关。如果前端提交的 JSON 特别大比如批量保存几十个键可能一次收不完导致cJSON_Parse失败。解决办法有两个一是前端分批提交每批不超过 10 个键二是服务器端用httpd_req_recv循环接收拼完整再解析。我选了前者因为实现简单而且用户体验上分批提交还能显示进度。// 服务器端循环接收的写法 int total req-content_len; int received 0; char* buf malloc(total 1); while (received total) { int ret httpd_req_recv(req, buf received, total - received); if (ret 0) { free(buf); return ESP_FAIL; } received ret; } buf[total] \0;6.4 并发访问与 NVS 句柄冲突esp_http_server是多任务的每个请求跑在独立的任务里。如果两个请求同时打开同一个 NVS 命名空间可能会冲突。NVS 本身对同一命名空间的并发写不是线程安全的需要加锁。我的做法是用一个全局互斥锁所有 NVS 操作前先xSemaphoreTake操作完xSemaphoreGive。锁的粒度不用太细因为 NVS 操作本身很快锁竞争不激烈。static SemaphoreHandle_t nvs_mutex NULL; // 初始化时创建 nvs_mutex xSemaphoreCreateMutex(); // 操作前 xSemaphoreTake(nvs_mutex, portMAX_DELAY); // ... NVS 操作 ... xSemaphoreGive(nvs_mutex);实操心得这个锁一定要在 NVS 初始化之后、HTTP 服务器启动之前创建。我有一次把创建锁的代码放在 HTTP 服务器启动之后结果第一个请求进来时锁还是 NULL直接崩了。这种初始化顺序问题在嵌入式里很常见建议把初始化流程写成一个明确的序列每步检查返回值。6.5 常见问题速查表现象可能原因排查方法解决方案网页打不开设备没连上 WiFi串口看日志确认 IP检查 NVS 里 WiFi 配置或进 AP 模式接口返回 404URI 没注册或路径不对看服务器日志的 URI 匹配检查httpd_register_uri_handler保存后重启丢失没调nvs_commit代码审查每次nvs_set_*后必须 commit键名报错键名超长或含非法字符打印键名长度限制 15 字符只用字母数字下划线值读出来是乱码类型不匹配对比写入和读取的类型确保nvs_set_*和nvs_get_*类型一致并发写崩溃没加锁看是否多请求同时写加互斥锁保护 NVS 操作固件太大网页资源没压缩看 map 文件压缩 HTML或用 SPIFFS 外置7. 进阶玩法让这个工具更好用7.1 加个 OTA 升级入口既然已经有了 HTTP 服务器和网页加个 OTA 升级功能是顺手的事。ESP-IDF 的esp_https_ota或者简单的esp_ota_ops都能用。网页上加个文件选择框上传固件 bin服务器收到后写入 OTA 分区重启切换。这样整个设备维护就闭环了改配置用 NVS 编辑器升级固件用 OTA都不用跑现场。不过 OTA 要注意分区表要留两个 app 分区ota_0和ota_1而且固件要签名校验防止刷入错误固件变砖。7.2 配置导入导出与批量部署NVS 里的配置可以导出成 JSON 文件下载到本地。批量部署的时候先在一台设备上配好导出 JSON然后其他设备导入省得一个个填。导出接口就是/api/nvs/list的完整版把所有命名空间和键值打包成 JSON 返回。导入接口接收 JSON遍历写入 NVS。注意导入前要先擦除现有配置或者做合并策略覆盖同名的保留不同的。这个功能在多设备项目里特别实用。我之前做的一个项目有 50 台设备就是靠导出导入半天配完了所有设备。7.3 安全加固加个简单的认证默认情况下局域网内任何人都能访问这个编辑器改你的 NVS。如果设备部署在不可信的局域网建议加个简单的认证。最简单的做法是 HTTP Basic Auth服务器检查Authorization头用户名密码存在 NVS 里初始默认admin/admin用户可改。前端在fetch请求里带上Authorization头。// 服务器端校验 char auth[128]; if (httpd_req_get_hdr_value_str(req, Authorization, auth, sizeof(auth)) ! ESP_OK) { httpd_resp_set_status(req, 401 Unauthorized); httpd_resp_set_hdr(req, WWW-Authenticate, Basic realm\NVS Editor\); httpd_resp_send(req, NULL, 0); return ESP_OK; } // 解析 base64对比用户名密码Basic Auth 的安全性一般base64 明文传输但在局域网内够用。如果要更安全可以上 HTTPS但 ESP32 跑 TLS 会占不少资源而且证书管理麻烦看项目需求权衡。7.4 与配网流程的整合这个 NVS 编辑器其实可以跟配网流程整合。设备第一次启动NVS 为空自动开 AP 模式用户连上热点浏览器打开编辑器填入 WiFi 信息保存后设备自动重启连 WiFi。之后如果 WiFi 密码变了设备连不上又自动回到 AP 模式用户再改。整个流程对用户来说就是连热点、开网页、填密码、保存。不需要任何专业知识也不需要装 App。这个体验比很多商业 IoT 设备的配网流程都顺畅。8. 一些个人体会和后续扩展方向这个 NVS 编辑器我从去年开始在自己的项目里用前后迭代了七八个版本现在算是比较稳定了。最大的感受是嵌入式开发里很多看似麻烦的问题其实用 Web 技术能优雅地解决。ESP32 有 WiFi、有 HTTP 服务器、有足够的 flash 和 RAM完全可以把配置管理做成一个 Web 应用用户体验直接上一个台阶。踩过的坑里最值得记住的是 NVS 的键名限制和 commit 机制。这两个问题在文档里都有写但很容易忽略而且出错时的错误码不够直观排查起来费时间。建议第一次用 NVS 的时候先写个最简单的读写测试把键名长度、类型匹配、commit 这些点都验证一遍再往项目里集成。后续我打算加的功能一是配置版本管理每次修改记录时间和修改人方便追溯二是配置模板常用配置存成模板一键应用三是跟 MQTT 结合配置变更时发消息通知方便远程监控。如果你也在做 ESP32 项目被配置管理困扰过不妨试试这个方案。代码量不大核心逻辑几百行但带来的便利是实实在在的。尤其是设备已经部署到现场之后能远程改配置和升级固件省下的跑腿时间够你多做好几个项目了。
阅读完成 · 觉得有帮助?
咨询建站