在生产环境 ,没法为基于 ESP32 的物联网项目更改代码中的 Wi-Fi 凭据,有一种称为 ESP-Touch 的方法,它适用于 TI 开发的 SmartConfig 技术,使用 ESP-Touch,您将不再需要对 Wi-Fi 凭据进行硬编码,因为您可以随时轻松更改它。
本文将介绍如何将 ESP-Touch 协议用于基于 ESP32 的物联网项目/设备。
我们将使用 Espressif 应用程序名称作为 EspTouch: SmartConfig for ESP8266, ESP32,通过使用这个应用程序,我们可以轻松地使用新的 Wi-Fi 凭据配置我们的 ESP32 设备。
我们将构建一个 ESP32 项目,以在成功配置后将 Wi-Fi 凭据存储在 EEPROM 内存中。
此外,我们将使用 ESP32 上的一个 按钮作为重置按钮,用于擦除存储的 Wi-Fi 凭据并配置新凭据。
ESP-Touch 协议使用 SmartConfig 技术。
SmartConfigTM 是 TI 开发的一项技术,用于将基于 Wi-Fi 的新型物联网设备连接到 Wi-Fi 网络。
它使用移动应用程序将网络凭据从智能手机或平板电脑广播到未配置的 Wi-Fi 设备。
使用 ESP-Touch 的主要优点是无需在 ESP32 中创建具有已知 SSID 或密码的接入点 (AP)。
因此,ESP-Touch 协议提供了一种无缝方式来配置连接到路由器的 Wi-Fi 设备。对于无头系统,它非常用户友好。只需在您的智能手机上点击几下。
IoT 设备最初没有连接到网络,ESPTOUCH 应用程序无法直接向设备发送任何信息。借助 ESP-TOUCH 通信协议,智能手机等具备 Wi-Fi 接入能力的设备可以向 Wi-Fi 接入点 (AP) 发送一系列 UDP 数据包,将 SSID 和密码编码到每个 UDP 数据包。然后,物联网设备可以访问 UDP 数据包,获取并解析出所需的信息。根据 ESP-Touch 用户指南,数据包结构如下所示。
我们将使用 Arduino IDE 对我们的 ESP32 板进行编程。
如果您之前已经完成,请跳过上述步骤。
此外,我们需要下载一个名为 EspTouch 的 Espressif 应用程序:ESP8266 的 SmartConfig、Android 的 ESP32 或 Apple 的Espressif Esptouch 。
如果您计划开发您的移动应用程序,请不要担心,因为 Espressif 提供了所有支持。看看以下 -
ESP32 包为我们提供了一个基本的 WiFiSmartConfig 示例。
让我们先了解一下这个例子。
您可以在以下位置导航到此示例
文件 > 示例 > WiFi > WiFiSmartConfig。
注意:- 示例路径仅在 Arduino IDE 中选择正确的 ESP32 板时可见。
这是示例代码-
void setup() {
Serial.println("SmartConfig received.");
//Wait for WiFi to connect to AP
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
}
将此示例代码上传到您的 ESP32 板上,我们可以看到示例中没有硬编码的网络凭据。
上传后,打开串口监视器并设置合适的波特率。
您会看到它正在等待 SmartConfig 配置,一旦进入配置模式,它将显示连续的点。
现在在您的移动设备中打开 ESP-Touch 应用程序并将您的移动设备连接到您的 Wi-Fi 路由器网络。在android中,它还会要求您打开位置服务以检测连接的Wi-Fi SSID。
它将获取并显示连接的 Wi-Fi 网络 SSID 和 BSSID。
现在您需要输入连接的 Wi-Fi 网络的密码。
选择多播单选按钮。
然后按确认按钮,你会看到这样的弹出窗口。
稍等片刻,您将在应用程序中看到一条成功消息以及连接的 ESP32 BSSID 和 Inet 地址信息。
而且,在串行监视器上,您将看到 SmartConfig 收到的消息, 现在它将连接到给定的 Wi-Fi 网络。
就这么简单,我们不需要为 ESP 接入点存储任何 SSID 或密码。
该示例现在并不完美,因为我们需要在重新启动 ESP 时对其进行配置,因为我们没有存储 Wi-Fi 凭据。此外,ESP 将始终进入 SmartConfig 模式。
我们将修改现有代码以克服这些问题。
第一步是包含示例所需的库。
在 setup 函数中,我们将首先初始化串行通信以观察串行监视器中的数据。
我们使用默认波特率 115200。但您可以根据需要更改它。
Serial.begin(115200);
启动 SmartConfig
在启动 SmartConfig 之前,必须将 ESP 置于站模式。
因此将 Wi-Fi 模式设置为 WIFI_AP_STA
WiFi.mode(WIFI_AP_STA);
现在,使用此命令打开 SmartConfig。
WiFi.beginSmartConfig();
现在我们将在循环中等待,直到收到 SmartConfig 数据。这意味着它将保持无限循环,直到有人使用移动应用程序再次对其进行配置。因此,使它成为这个特定示例的一个缺点。
当 ESP 进入此 while 循环时,您将在串行监视器中看到一个连续的点。
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("SmartConfig received.");
成功配置 Wi-Fi 凭据后,它将自动尝试连接到给定的 Wi-Fi 凭据。它将进入另一个 while 循环,直到连接到 Wi-Fi。
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
连接后,我们将串行打印 Wi-Fi 连接消息以及 IP 地址。
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
哇!现在就是这么简单;我可以在 5 秒内配置我的 ESP。
现在,让我们为这个示例添加更多功能,使其变得更加可靠。
在这个项目中,我们会将接收到的 Wi-Fi 凭据存储在 EEPROM/闪存中。因此,我们不需要每次都配置 ESP。
接下来,我们将添加一个小检查,例如 ESP 打开时;它将检索存储的 Wi-Fi 凭据并连接到 Wi-Fi 网络。
如果连接成功,则跳过进入 SmartConfig 模式。
此外,我们将使用启动按钮作为重置按钮。它将清除存储的 Wi-Fi 凭据并重新启动 ESP 以进行新配置。
需要长按开机键3秒以上再松开,重置配置成功。
这是完整的项目代码。
/*
Configure ESP32 Wi-Fi parameters using SmartConfig
*/
#include "WiFi.h"
#include "EEPROM.h"
#define LENGTH(x) (strlen(x) + 1) // length of char string
#define EEPROM_SIZE 200 // EEPROM size
#define WiFi_rst 0 //WiFi credential reset pin (Boot button on ESP32)
String ssid; //string variable to store ssid
String pss; //string variable to store password
unsigned long rst_millis;
void setup() {
Serial.begin(115200); //Init serial
pinMode(WiFi_rst, INPUT);
if (!EEPROM.begin(EEPROM_SIZE)) { //Init EEPROM
Serial.println("failed to init EEPROM");
delay(1000);
}
else
{
ssid = readStringFromFlash(0); // Read SSID stored at address 0
Serial.print("SSID = ");
Serial.println(ssid);
pss = readStringFromFlash(40); // Read Password stored at address 40
Serial.print("psss = ");
Serial.println(pss);
}
WiFi.begin(ssid.c_str(), pss.c_str());
delay(3500); // Wait for a while till ESP connects to WiFi
if (WiFi.status() != WL_CONNECTED) // if WiFi is not connected
{
//Init WiFi as Station, start SmartConfig
WiFi.mode(WIFI_AP_STA);
WiFi.beginSmartConfig();
//Wait for SmartConfig packet from mobile
Serial.println("Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("SmartConfig received.");
//Wait for WiFi to connect to AP
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// read the connected WiFi SSID and password
ssid = WiFi.SSID();
pss = WiFi.psk();
Serial.print("SSID:");
Serial.println(ssid);
Serial.print("PSS:");
Serial.println(pss);
Serial.println("Store SSID & PSS in Flash");
writeStringToFlash(ssid.c_str(), 0); // storing ssid at address 0
writeStringToFlash(pss.c_str(), 40); // storing pss at address 40
}
else
{
Serial.println("WiFi Connected");
}
}
void loop() {
// put your main code here, to run repeatedly:
rst_millis = millis();
while (digitalRead(WiFi_rst) == LOW)
{
// Wait till boot button is pressed
}
// check the button press time if it is greater than 3sec clear wifi cred and restart ESP
if (millis() - rst_millis >= 3000)
{
Serial.println("Reseting the WiFi credentials");
writeStringToFlash("", 0); // Reset the SSID
writeStringToFlash("", 40); // Reset the Password
Serial.println("Wifi credentials erased");
Serial.println("Restarting the ESP");
delay(500);
ESP.restart(); // Restart ESP
}
}
void writeStringToFlash(const char* toStore, int startAddr) {
int i = 0;
for (; i < LENGTH(toStore); i++) {
EEPROM.write(startAddr + i, toStore[i]);
}
EEPROM.write(startAddr + i, '\0');
EEPROM.commit();
}
String readStringFromFlash(int startAddr) {
char in[128]; // char array of size 128 for reading the stored data
int i = 0;
for (; i < 128; i++) {
in[i] = EEPROM.read(startAddr + i);
}
return String(in);
}
首先,我们将包含该项目所需的所有库。
#include "WiFi.h"
#include "EEPROM.h"
定义自定义函数 LENGTH(x) 将为我们提供一个增量为 char 字符串的长度。稍后我们将使用此功能。
并将所需的 EEPROM 大小定义为 EEPROM_SIZE。
#define LENGTH(x) (strlen(x) + 1) // length of char string
#define EEPROM_SIZE 200 // EEPROM size
我们正在使用 ESP32 板的启动按钮来重置 Wi-Fi 凭据设置。ESP32 板上的开机按钮与 GPIO0 引脚相连,并带有上拉电阻。
因此,我们将 WiFi_rst 定义为 0。如果您使用任何其他引脚作为重置按钮,则需要将该 GPIO 编号添加到 WiFi_rst 变量中。
#define WiFi_rst 0 //WiFi credential reset pin (Boot button on ESP32)
我们正在定义用于检索 SSID 和密码的字符串变量。
此外,我们将使用 rst_millis 变量来计算按下重置按钮的时间。
String ssid; //string variable to store ssid
String pss; //string variable to store password
unsigned long rst_millis;
我们将使用所需的波特率初始化串行通信。
Serial.begin(115200); //Init serial
将 WiFi_rst 引脚设置为输入引脚。
pinMode(WiFi_rst, INPUT);
现在,使用预定义的 EEPROM_SIZE 初始化 EEPROM。
初始化后,我们将分别在地址 0 和 40 处将存储的 SSID 和密码读取为字符串。
我们使用名为 readStringFromFlash() 的用户定义函数从 EEPROM/闪存中读取字符串。
if (!EEPROM.begin(EEPROM_SIZE)) { //Init EEPROM
Serial.println("failed to init EEPROM");
delay(1000);
}
else
{
ssid = readStringFromFlash(0); // Read SSID stored at address 0
Serial.print("SSID = ");
Serial.println(ssid);
pss = readStringFromFlash(40); // Read Password stored at address 40
Serial.print("psss = ");
Serial.println(pss);
}
使用 Wi-Fi.begin 功能连接到 Wi-Fi 网络。我们将 Wi-Fi 凭据作为字符串变量传递;因此,我们将需要使用 c_str(),它将返回一个指向以空字符结尾的字符串的 const char*。
我们将添加一点延迟,以便 ESP 可以连接到 Wi-Fi 网络。
WiFi.begin(ssid.c_str(), pss.c_str());
delay(3500); // Wait for a while till ESP connects to WiFi
延迟之后,我们将检查 ESP32 是否连接到 Wi-Fi。
如果 ESP 连接到 Wi-Fi,那么我们将跳过 if 条件中的 SmartConfig 代码。
如果它与 Wi-Fi 连接失败,我们将启动 Wi-Fi Station 模式和 SmartConfig,与前面的示例类似。
if (WiFi.status() != WL_CONNECTED) // if WiFi is not connected
{
//Init WiFi as Station, start SmartConfig
WiFi.mode(WIFI_AP_STA);
WiFi.beginSmartConfig();
使用while 循环等待 SmartConfig 数据到达 。网络凭据到达后,它将尝试连接到该 Wi-Fi 网络。
//Wait for SmartConfig packet from mobile
Serial.println("Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("SmartConfig received.");
//Wait for WiFi to connect to AP
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
连接 Wi-Fi 后,我们将通过以下函数读取连接的 Wi-Fi SSID 和密码。
ssid = WiFi.SSID();
pss = WiFi.psk();
Serial.print("SSID:");
Serial.println(ssid);
Serial.print("PSS:");
Serial.println(pss);
我们将使用另一个用户定义的函数 writeStringToFlash() 来存储新凭据。 我们只需要传递字符串数据和地址。
Serial.println("Store SSID & PSS in Flash");
writeStringToFlash(ssid.c_str(), 0); // storing ssid at address 0
writeStringToFlash(pss.c_str(), 40); // storing pss at address 40
在循环函数内部,我们将当前的millis()值存储在 rst_millis 变量中,因为当有人按下 Wi-Fi 重置按钮时,我们将使用该值作为开始时间。
rst_millis = millis();
当我们按下 Boot 按钮时, while 循环 条件就满足了。因此,代码被困在循环中,直到按钮被释放。
while (digitalRead(WiFi_rst) == LOW)
{
// Wait till boot button is pressed
}
当按钮立即松开时,我们将检查我们按下按钮的时间,如果时间大于 3000mS, 则满足if 条件 。
if (millis() - rst_millis >= 3000)
现在我们将通过将空白值传递给 writeStringToFlash() 函数来擦除地址 0 和 40 处存储的 Wi-Fi 凭据。
Serial.println("Reseting the WiFi credentials");
writeStringToFlash("", 0); // Reset the SSID
writeStringToFlash("", 40); // Reset the Password
Serial.println("Wifi credentials erased");
最后,我们将使用以下命令触发对 ESP32 的软件复位。
Serial.println("Restarting the ESP");
delay(500);
ESP.restart(); // Restart ESP
void writeStringToFlash(const char* toStore, int startAddr)
该用户自定义函数将字符串或字符数组指针存储在 ESP32 的 EEPROM/Flash 存储器中。
我们需要将其存储在非易失性存储器中;因此即使电源关闭,存储的数据也不会被删除。
如果我们仔细看这个函数的代码,它只是一个 for 循环。 它根据 LENGTH() 函数输入执行,如前所述,它将提供字符串的长度。
我们将使用 EEPROM.write() 函数将字符串的每个字节存储到传递的特定地址,并且地址保持递增。
一旦 执行了 for 循环 ,我们将保存一个 '\0' 作为字符串终止符。并将提交更改,以便将它们全部存储在内存中。
void writeStringToFlash(const char* toStore, int startAddr) {
int i = 0;
for (; i < LENGTH(toStore); i++) {
EEPROM.write(startAddr + i, toStore[i]);
}
EEPROM.write(startAddr + i, '\0');
EEPROM.commit();
}
String readStringFromFlash(int startAddr)
此用户定义函数从 EEPROM/闪存中的所需地址读取存储的字符串。
这里我们将char数组名初始化为 in[128] ,它的大小为128,这意味着它只能处理小于128的字符串长度。如果需要处理更大的字符串,可以增加大小。
与存储函数类似,它也适用于 for 循环。它将从startAddr (起始地址)开始 一个接一个地读取所有字符 。
最后,我们将以字符串的形式返回它。
String readStringFromFlash(int startAddr) {
char in[128]; // char array of size 128 for reading the stored data
int i = 0;
for (; i < 128; i++) {
in[i] = EEPROM.read(startAddr + i);
}
return String(in);
}
来源:https://zhuanlan.zhihu.com/p/502767902
电子设计自动化(英语:Electronic design automation,缩写:EDA)是指利用计算机辅助设计(CAD)软件,来完成超大规模集成电路(VLSI)芯片的功能设计、综合、验证、物理设计(包括布局、布线、版图、设计规则检查等)等流程的设计方式。
乐动掌控采用掌控板作为主控,塑胶一体式外壳,侧面和底面开具多个乐高扩展孔位,兼容乐高积木,可完成多种创意应用。
在MicroPython的ESP32库中,NVS类用于管理非易失性存储,支持 32 位有符号整数和 二进制blob。
umqtt 是 MicroPython 的一个轻量级 MQTT 客户端库,使得在微控制器上使用 MQTT 协议变得简单易行。本文将介绍 umqtt 的实用方法,帮助您更好地在项目中应用这一技术。
Arduino-ESP32项目提供的Preferences库是一个专为ESP32设计的非易失性存储解决方案,它替代了传统的Arduino EEPROM库,提供了更强大、更可靠的数据存储功能。
本方案是一个基于ESP32-CAM + 物联网的图像采集方案。
ESP32-CAM与MicroPython结合可实现摄像头图像采集、视频流传输等功能,不过Micropython官方没有支持ESP32-CAM的固件,需要烧录第三方的专有固件。
相信很多人都有把绿植给养死的经历,可能是浇水过多、忘记浇水、较长时间不在家不能浇水等,本文介绍一种可以灵活定制的智能浇花方案。
MicroPython 在 ESP32 上支持线程(Thread)功能,通过_thread模块实现。线程允许程序并发执行多个任务,适合处理需要同时运行的场景,例如传感器数据采集和网络通信。
掌控板3.0升级了主控,还主打AI。带有双麦克风阵列,增加了音频解码芯片,板载了一个1W喇叭,还把之前的单色屏幕换成了1.47寸的彩色屏幕,有更多的可玩性。
乐鑫自主研发的 ESP-TOUCH 协议采⽤的是 Smart Config(智能配置)技术,帮助用户将采用 ESP8266 和 ESP32 的设备(以下简称“设备”)连接至 Wi-Fi 网络。