零知派——ESP32-S3 AI 小智 使用 Preferences NVS 实现Web配网持久化

news2026/5/8 8:06:59
✔零知派零知开源是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录让开发重心从 “配置环境” 转移到 “创意实现”极大降低了技术门槛。零知开源编程软件内置上千个覆盖多场景的示例代码支持项目源码一键下载项目文章在线浏览。零知派(零知开源)平台通过软硬件协同创新让你的创意快速转化为实物来动手试试吧目录一、为什么需要网页配网二、整体架构从 AP 启动到配置保存三、AP 热点与 DNS Captive Portal3.1 启动 AP 热点3.2 DNS Captive Portal 实现四、Web 服务器与 API 设计4.1 建立 Web 服务器4.2 配网页面 HTML4.3 WiFi 扫描接口4.4 接收凭据并异步连接4.5 状态查询接口五、配置持久化Preferences 库的使用六、主循环中的配网处理七、按键触发重新配网八、完整流程图项目概述本方案利用零知派ESP32-S3内置的NVS非易失性存储与Preferences库实现WiFi配置的持久化保存。首次通过网页配网成功后SSID和密码被自动写入Flash分区断电不丢失。设备每次重启时优先从Flash读取已保存的凭证调用WiFi.begin()自动重连。若网络环境变化导致连接失败系统自动回退到网页配网模式。项目难点及解决方案问题描述AP/STA模式的无缝切换 与 非阻塞事件处理解决方案关闭AP前确保STA已成功连接采用轮询 WiFi 状态取代while() 等待 WiFi 连接的阻塞式等待。一、为什么需要网页配网常见方案对比方案优点缺点硬编码 SSID/密码简单直接无法适应不同网络毫无通用性SmartConfig微信配网无需连接 AP兼容性差部分路由器不支持成功率低依赖微信生态蓝牙配网稳定需要蓝牙硬件App 开发成本高网页配网跨平台任何手机/电脑浏览器无需安装 App实现简单用户需手动切换 WiFi 连接设备 AP网页配网的核心流程设备上电后如果没有有效 WiFi 配置自动进入 AP 模式并启动一个 Web 服务器。用户用手机连接设备的热点在浏览器中打开配置页面通常会自动弹出选择 WiFi 并输入密码设备收到后尝试连接成功后保存配置并重启。二、整体架构从 AP 启动到配置保存配网模块涉及以下几个关键组件AP 热点设备作为接入点供用户连接。DNS Captive Portal自动劫持 DNS将任意域名解析到设备 IP实现配网页面自动弹出。Web Server提供 HTML 页面和 REST API。异步连接 状态轮询WiFi 连接不阻塞 Web 服务前端实时获取状态。PreferencesNVS持久化存储 WiFi 凭据。按键重置长按按键清除配置重新进入配网模式。三、AP 热点与 DNS Captive Portal3.1 启动 AP 热点ESP32 可以同时工作在 STA连接路由器和 AP自身作为热点模式。配网阶段我们使用APSTA模式但 AP 是核心WiFi.mode(WIFI_AP_STA); WiFi.softAP(kApSsid, kApPassword); // SSID: XiaoZhi-AI, 密码: 12345678 Serial.printf(AP IP address: %s\n, WiFi.softAPIP().toString().c_str()); // 通常是 192.168.4.1密码不能为空至少 8 位否则部分手机无法连接。设置简单易记的密码即可。3.2 DNS Captive Portal 实现Captive Portal强制门户技术能让用户连接热点后自动弹出认证/配置页面而不需要手动输入 IP。原理是启动一个 DNS 服务器将所有域名解析到设备的 AP IP。g_dnsServer new DNSServer(); g_dnsServer-start(53, *, WiFi.softAPIP()); // 监听 53 端口所有域名都解析到 AP IP然后在主循环中不断处理 DNS 请求g_dnsServer-processNextRequest();配合 Web 服务器的根路径/返回配网 HTML用户打开任意浏览器或点击弹窗就会显示配置界面。四、Web 服务器与 API 设计4.1 建立 Web 服务器使用WebServer库监听 80 端口g_webServer new WebServer(80); g_webServer-on(/, HandleRoot); // 配网主页 g_webServer-on(/connect, HTTP_POST, HandleConnect); // 提交 WiFi 凭据 g_webServer-on(/status, HandleStatus); // 查询连接状态 g_webServer-on(/scan, HandleScan); // 扫描周围 WiFi 列表 g_webServer-on(/clear, HandleClear); // 清除已保存配置 g_webServer-onNotFound(HandleRoot); // 其他路径重定向到根 g_webServer-begin();4.2 配网页面 HTML页面内容被转换为 C 字符串数组存储在webconfig_html.h中编译时烧录到 Flash。页面包含WiFi 列表下拉框通过 Ajax 调用/scan填充密码输入框连接按钮状态提示区这样无需外置文件系统所有资源内嵌。4.3 WiFi 扫描接口为了提高用户体验让用户无需手动输入 SSID实现了 WiFi 扫描功能。注意WiFi.scanNetworks()是同步阻塞的可能耗时 1~3 秒。为了避免影响 Web 响应我们做了以下设计使用g_scanning标志防止并发扫描虽然 WebServer 单线程但防止定时器或多次点击。扫描前确保 WiFi 模式为WIFI_AP_STAAP 不能关闭。返回 JSON 数组包含ssid、rssi、encrypted、encryptionType字段。关键代码片段int n WiFi.scanNetworks(); String json [; for (int i 0; i n i 20; i) { json {\ssid\:\ EscapeJsonString(WiFi.SSID(i)) \,; json \rssi\: String(WiFi.RSSI(i)) ,; json \encrypted\: String(WiFi.encryptionType(i) ! WIFI_AUTH_OPEN) }; if (i n-1) json ,; } json ]; g_webServer-send(200, application/json, json); WiFi.scanDelete(); // 释放内存其中EscapeJsonString()处理 SSID 中的双引号、反斜杠等特殊字符防止 JSON 格式错误。4.4 接收凭据并异步连接connect接口收到ssid和password后不能阻塞等待连接成功否则浏览器会超时。因此采用立即返回 后台连接 前端轮询的策略。void HandleConnect() { g_pendingSsid ssid; g_pendingPassword password; WiFi.begin(ssid.c_str(), password.c_str()); g_connecting true; g_connectSuccess false; g_connectStartTime millis(); g_webServer-send(200, application/json, {\success\: true}); }4.5 状态查询接口前端每隔 1 秒请求status根据返回值更新界面if (!g_connecting !g_connectSuccess) status idle; else if (g_connectSuccess) status connected; else if (g_connecting) { if (millis() - g_connectStartTime 20000) { // 超时 20 秒 status failed; g_connecting false; WiFi.disconnect(); } else { wl_status_t wifiStatus WiFi.status(); if (wifiStatus WL_CONNECTED) { status connected; g_connectSuccess true; g_connecting false; SaveWifiConfig(g_pendingSsid, g_pendingPassword); } else if (wifiStatus WL_CONNECT_FAILED || wifiStatus WL_NO_SSID_AVAIL) { status failed; g_connecting false; } else { status connecting; } } }当状态变为 connected 时前端可以跳转到成功页面设备稍后自动重启。五、配置持久化Preferences 库的使用ESP32 提供Preferences库用于在 NVSNon-Volatile Storage中存储键值对非常适合保存 WiFi 凭据#include Preferences.h Preferences g_preferences; const char* kNamespace wifi_config; bool SaveWifiConfig(const String ssid, const String password) { g_preferences.begin(kNamespace, false); g_preferences.putString(ssid, ssid); g_preferences.putString(password, password); g_preferences.end(); return true; } bool LoadWifiConfig(String ssid, String password) { g_preferences.begin(kNamespace, true); ssid g_preferences.getString(ssid, ); password g_preferences.getString(password, ); g_preferences.end(); return ssid.length() 0; }注意begin()的第二个参数为false表示可写为true表示只读。保存配置后即使断电也不会丢失六、主循环中的配网处理在setup()中调用ConfigureWifi()函数其逻辑尝试加载并连接保存的 WiFiConnectToSavedWifi()。如果成功直接返回进入正常应用流程。如果失败或没有保存配置调用StartWebConfig()进入配网模式。在配网模式中主循环不断调用HandleWebConfig()处理 DNS 和 Web 请求同时检查异步连接状态。一旦连接成功延迟重启下次启动就会加载新配置HandleWebConfig()的非阻塞实现void HandleWebConfig() { if (g_isWebConfigMode g_dnsServer g_webServer) { g_dnsServer-processNextRequest(); g_webServer-handleClient(); if (g_connectSuccess) { static unsigned long lastRestartTime 0; if (lastRestartTime 0) { lastRestartTime millis(); } else if (millis() - lastRestartTime 5000) { ESP.restart(); } } } }七、按键触发重新配网ESP_ERROR_CHECK(iot_button_register_cb( g_button_boot_handle, // Boot 按键句柄 BUTTON_PRESS_DOWN, // 按键事件按下 nullptr, [](void*, void* data) { // 回调函数 printf(boot button pressed\n); ClearWifiConfig(); //清除配置后重启 delay(100); ESP.restart(); }, nullptr)); iot_button_unregister_cb(g_button_boot_handle, BUTTON_PRESS_DOWN, nullptr); //连接成功后注销重新配网功能在连接WiFi成功前按下Boot按键可以强制重新配网且在连接成功后注销该功能不会跟后续的语音打断功能冲突八、完整流程图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2548737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…