技术标签: 学习 ESP32-Arduino学习记录 物联网 单片机
不想了解代码实现,可直接到代码部分copy!ESP32亲测可用。
使用设备ESP32开发板(ESP32-WROOM-32)
搜了好多别人写的资料,很多都是copy+copy,也没有什么解释。啪,代码放在那里,自己看吧。
我不是说他们写的都是垃圾哈 ~ 那我承认,我就是这么想的,有的说是教程也啥都没写
不能怪人家不能怪人家,咱还是自己学!!!
咱的代码也是copy了再改的,没脸说人家。
让我自己写的话,那不叫写代码,那叫写bug。
在学习中进步!!
正题开始了
设备热点配网(Soft AP)
很抱歉C++的基础不好,没封装成库的形式,创建类后有一部分函数总是报错,没有解决。
但是也分成了文件的形式,要是拷贝使用也非常方便。
说明:LED显示配网状态
LED闪烁:表示正在尝试连接网络。
LED常亮:表示网络连接成功
LED常灭:表示等待配网
LED闪烁5次:表示已清除wifi信息
配网状态下ESP32开发板还挺温乎的!
实话实说,这是我抄的!!
但是我忘记在哪里抄的了。
(我的手机截图)
我是在这个网站看嫖来的配网界面好不好看的。
在线的,目前免费,试了一试还挺好用的
在这个软件中,新建工程复制进去这个代码就能看网页效果了。
因为我也不懂哈 ~ 有什么错误我可能不知道。但是显示的网页是正常的。
<!DOCTYPE html>
<html>
<head>
<title>WIFI
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<style type="text/css">
.input{display: block; margin-top: 10px;}
.input span{width: 100px; float: left; float: left; height: 36px; line-height: 36px;}
.input input{height: 30px;width: 200px;}
.btn{width: 120px; height: 35px; background-color: #000000; border:0px; color:#ffffff; margin-top:15px; margin-left:100px;}
</style>
<body>
<form method="POST" action="configwifi">
<label class="input">
<span>
WiFi SSID
</span>
<input type="text" name="ssid">
</label>
<label class="input">
<span>
WiFi PASS
</span>
<input type="text" name="pass">
</label>
<input class="btn" type="submit" name="submit" value="Submie">
<p>
<span> Nearby wifi:
</P>
</form>
</body>
</html>
红线上为配网前打印
红线后为配网后打印
以上就是代码之外的资料了 ~
本次工程包含三个文件main.ino、WiFiUser.cpp、WiFiUser.h
有关配网的函数都在WiFiUser.cpp、WiFiUser.h文件中,可直接添加这两个文件到工程目录下进行调用。
如果不想学习怎么实现,可直接复制这两个文件,两分钟内实现配网操作!
由于官方命名原因,ESP8266的库文件需要更改为ESP8266+库文件的形式,但函数可通用。(此条说明未验证)
如果想了解实现原理,需配合串口打印信息来分析。
很遗憾没有设置成类的形式,以后要改!!
在此文件夹下,声明了函数。可以见得,include此文件,只需要在自己写的函数中调用3个函数即可实现配网全操作。5个文件中一个是LED、一个是清除wifi保存在flash的信息、只有三个才是配网所需函数!
#ifndef __WIFIUSER_H__
#define __WIFIUSER_H__
#include <WiFi.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <ESPmDNS.h> //用于设备域名 MDNS.begin("esp32")
#include <esp_wifi.h> //用于esp_wifi_restore() 删除保存的wifi信息
extern const int LED; //设置LED引脚
extern const char* HOST_NAME; //设置设备名
extern int connectTimeOut_s; //WiFi连接超时时间,单位秒
//===========需要调用的函数===========
void checkConnect(bool reConnect); //检测wifi是否已经连接
void restoreWiFi(); //删除保存的wifi信息
void LEDinit(); //LED初始化
void checkDNS_HTTP(); //检测客户端DNS&HTTP请求
void connectToWiFi(int timeOut_s); //连接WiFi
//===========内部函数===========
void handleRoot(); //处理网站根目录的访问请求
void handleConfigWifi() ; //提交数据后的提示页面
void handleNotFound(); //处理404情况的函数'handleNotFound'
void initSoftAP(); //进入AP模式
void initDNS(); //开启DNS服务器
void initWebServer(); //初始化WebServer
bool scanWiFi(); //扫描附近的WiFi,为了显示在配网界面
void wifiConfig(); //配置配网功能
void blinkLED(int led, int n, int t); //LED闪烁函数 //用不上LED可删除
#endif
这就是所有有关配网的函数的定义了 ~
这里有一点应该注意的是:HTML放在代码中时在 " 前应该加 \ (转义符)
#include "WiFiUser.h"
const byte DNS_PORT = 53; //设置DNS端口号
const int webPort = 80; //设置Web端口号
const char* AP_SSID = "ESP32-4_1"; //设置AP热点名称
//const char* AP_PASS = ""; //这里不设置设置AP热点密码
const char* HOST_NAME = "MY_ESP32"; //设置设备名
String scanNetworksID = ""; //用于储存扫描到的WiFi ID
IPAddress apIP(192, 168, 4, 1); //设置AP的IP地址
String wifi_ssid = ""; //暂时存储wifi账号密码
String wifi_pass = ""; //暂时存储wifi账号密码
const int LED = 2; //设置LED引脚
DNSServer dnsServer; //创建dnsServer实例
WebServer server(webPort); //开启web服务, 创建TCP SERVER,参数: 端口号,最大连接数
#define ROOT_HTML "<!DOCTYPE html><html><head><title>WIFI</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><style type=\"text/css\">.input{display: block; margin-top: 10px;}.input span{width: 100px; float: left; float: left; height: 36px; line-height: 36px;}.input input{height: 30px;width: 200px;}.btn{width: 120px; height: 35px; background-color: #000000; border:0px; color:#ffffff; margin-top:15px; margin-left:100px;}</style><body><form method=\"POST\" action=\"configwifi\"><label class=\"input\"><span>WiFi SSID</span><input type=\"text\" name=\"ssid\" value=\"\"></label><label class=\"input\"><span>WiFi PASS</span> <input type=\"text\" name=\"pass\"></label><input class=\"btn\" type=\"submit\" name=\"submit\" value=\"Submie\"> <p><span> Nearby wifi:</P></form>"
/*
* 处理网站根目录的访问请求
*/
void handleRoot()
{
if (server.hasArg("selectSSID")) {
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>"); //scanNetWprksID是扫描到的wifi
} else {
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
}
}
/*
* 提交数据后的提示页面
*/
void handleConfigWifi() //返回http状态
{
if (server.hasArg("ssid")) //判断是否有账号参数
{
Serial.print("got ssid:");
wifi_ssid = server.arg("ssid"); //获取html表单输入框name名为"ssid"的内容
Serial.println(wifi_ssid);
}
else //没有参数
{
Serial.println("error, not found ssid");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid"); //返回错误页面
return;
}
//密码与账号同理
if (server.hasArg("pass"))
{
Serial.print("got password:");
wifi_pass = server.arg("pass"); //获取html表单输入框name名为"pwd"的内容
Serial.println(wifi_pass);
}
else
{
Serial.println("error, not found password");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
return;
}
server.send(200, "text/html", "<meta charset='UTF-8'>SSID:" + wifi_ssid + "<br />password:" + wifi_pass + "<br />已取得WiFi信息,正在尝试连接,请手动关闭此页面。"); //返回保存成功页面
delay(2000);
WiFi.softAPdisconnect(true); //参数设置为true,设备将直接关闭接入点模式,即关闭设备所建立的WiFi网络。
server.close(); //关闭web服务
WiFi.softAPdisconnect(); //在不输入参数的情况下调用该函数,将关闭接入点模式,并将当前配置的AP热点网络名和密码设置为空值.
Serial.println("WiFi Connect SSID:" + wifi_ssid + " PASS:" + wifi_pass);
if (WiFi.status() != WL_CONNECTED) //wifi没有连接成功
{
Serial.println("开始调用连接函数connectToWiFi()..");
connectToWiFi(connectTimeOut_s);
}
else {
Serial.println("提交的配置信息自动连接成功..");
}
}
/*
* 处理404情况的函数'handleNotFound'
*/
void handleNotFound() // 当浏览器请求的网络资源无法在服务器找到时通过此自定义函数处理
{
handleRoot(); //访问不存在目录则返回配置页面
// server.send(404, "text/plain", "404: Not found");
}
/*
* 进入AP模式
*/
void initSoftAP() {
WiFi.mode(WIFI_AP); //配置为AP模式
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //设置AP热点IP和子网掩码
if (WiFi.softAP(AP_SSID)) //开启AP热点,如需要密码则添加第二个参数
{
//打印相关信息
Serial.println("ESP-32S SoftAP is right.");
Serial.print("Soft-AP IP address = ");
Serial.println(WiFi.softAPIP()); //接入点ip
Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str()); //接入点mac
}
else //开启AP热点失败
{
Serial.println("WiFiAP Failed");
delay(1000);
Serial.println("restart now...");
ESP.restart(); //重启复位esp32
}
}
/*
* 开启DNS服务器
*/
void initDNS()
{
if (dnsServer.start(DNS_PORT, "*", apIP)) //判断将所有地址映射到esp32的ip上是否成功
{
Serial.println("start dnsserver success.");
} else {
Serial.println("start dnsserver failed.");
}
}
/*
* 初始化WebServer
*/
void initWebServer()
{
if (MDNS.begin("esp32")) //给设备设定域名esp32,完整的域名是esp32.local
{
Serial.println("MDNS responder started");
}
//必须添加第二个参数HTTP_GET,以下面这种格式去写,否则无法强制门户
server.on("/", HTTP_GET, handleRoot); // 当浏览器请求服务器根目录(网站首页)时调用自定义函数handleRoot处理,设置主页回调函数,必须添加第二个参数HTTP_GET,否则无法强制门户
server.on("/configwifi", HTTP_POST, handleConfigWifi); // 当浏览器请求服务器/configwifi(表单字段)目录时调用自定义函数handleConfigWifi处理
server.onNotFound(handleNotFound); //当浏览器请求的网络资源无法在服务器找到时调用自定义函数handleNotFound处理
server.begin(); //启动TCP SERVER
Serial.println("WebServer started!");
}
/*
* 扫描附近的WiFi,为了显示在配网界面
*/
bool scanWiFi() {
Serial.println("scan start");
Serial.println("--------->");
// 扫描附近WiFi
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
scanNetworksID = "no networks found";
return false;
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
scanNetworksID += "<P>" + WiFi.SSID(i) + "</P>";
delay(10);
}
return true;
}
}
/*
* 连接WiFi
*/
void connectToWiFi(int timeOut_s) {
WiFi.hostname(HOST_NAME); //设置设备名
Serial.println("进入connectToWiFi()函数");
WiFi.mode(WIFI_STA); //设置为STA模式并连接WIFI
WiFi.setAutoConnect(true); //设置自动连接
if (wifi_ssid != "") //wifi_ssid不为空,意味着从网页读取到wifi
{
Serial.println("用web配置信息连接.");
WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str()); //c_str(),获取该字符串的指针
wifi_ssid = "";
wifi_pass = "";
}
else //未从网页读取到wifi
{
Serial.println("用nvs保存的信息连接.");
WiFi.begin(); //begin()不传入参数,默认连接上一次连接成功的wifi
}
int Connect_time = 0; //用于连接计时,如果长时间连接不成功,复位设备
while (WiFi.status() != WL_CONNECTED) //等待WIFI连接成功
{
Serial.print("."); //一共打印30个点点
digitalWrite(LED, !digitalRead(LED));
delay(500);
Connect_time ++;
if (Connect_time > 2 * timeOut_s) //长时间连接不上,重新进入配网页面
{
digitalWrite(LED, LOW);
Serial.println(""); //主要目的是为了换行符
Serial.println("WIFI autoconnect fail, start AP for webconfig now...");
wifiConfig(); //开始配网功能
return; //跳出 防止无限初始化
}
}
if (WiFi.status() == WL_CONNECTED) //如果连接成功
{
Serial.println("WIFI connect Success");
Serial.printf("SSID:%s", WiFi.SSID().c_str());
Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
Serial.print("LocalIP:");
Serial.print(WiFi.localIP());
Serial.print(" ,GateIP:");
Serial.println(WiFi.gatewayIP());
Serial.print("WIFI status is:");
Serial.print(WiFi.status());
digitalWrite(LED, HIGH);
server.stop(); //停止开发板所建立的网络服务器。
}
}
/*
* 配置配网功能
*/
void wifiConfig()
{
initSoftAP();
initDNS();
initWebServer();
scanWiFi();
}
/*
* 删除保存的wifi信息,这里的删除是删除存储在flash的信息。删除后wifi读不到上次连接的记录,需重新配网
*/
void restoreWiFi() {
delay(500);
esp_wifi_restore(); //删除保存的wifi信息
Serial.println("连接信息已清空,准备重启设备..");
delay(10);
blinkLED(LED, 5, 500); //LED闪烁5次 //关于LED,不需要可删除
digitalWrite(LED, LOW); //关于LED,不需要可删除
}
/*
* 检查wifi是否已经连接
*/
void checkConnect(bool reConnect)
{
if (WiFi.status() != WL_CONNECTED) //wifi连接失败
{
if (digitalRead(LED) != LOW)
digitalWrite(LED, LOW);
if (reConnect == true && WiFi.getMode() != WIFI_AP && WiFi.getMode() != WIFI_AP_STA )
{
Serial.println("WIFI未连接.");
Serial.println("WiFi Mode:");
Serial.println(WiFi.getMode());
Serial.println("正在连接WiFi...");
connectToWiFi(connectTimeOut_s); //连接wifi函数
}
}
else if (digitalRead(LED) != HIGH)
digitalWrite(LED, HIGH); //wifi连接成功
}
/*
* LED闪烁函数 //用不上LED可删除
*/
void blinkLED(int led, int n, int t)
{
for (int i = 0; i < 2 * n; i++)
{
digitalWrite(led, !digitalRead(led));
delay(t);
}
}
/*
* LED初始化
*/
void LEDinit()
{
pinMode(LED, OUTPUT); //配置LED口为输出口
digitalWrite(LED, LOW); //初始灯灭
}
/*
* 检测客户端DNS&HTTP请求
*/
void checkDNS_HTTP()
{
dnsServer.processNextRequest(); //检查客户端DNS请求
server.handleClient(); //检查客户端(浏览器)http请求
}
#include "WiFiUser.h"
const int resetPin = 0; //设置重置按键引脚,用于删除WiFi信息
int connectTimeOut_s = 15; //WiFi连接超时时间,单位秒
void setup()
{
pinMode(resetPin, INPUT_PULLUP); //按键上拉输入模式(默认高电平输入,按下时下拉接到低电平)
Serial.begin(115200); //波特率
LEDinit(); //LED用于显示WiFi状态
connectToWiFi(connectTimeOut_s); //连接wifi,传入的是wifi连接等待时间15s
}
void loop()
{
if (!digitalRead(resetPin)) //长按5秒(P0)清除网络配置信息
{
delay(5000); //哈哈哈哈,这样不准确
if (!digitalRead(resetPin))
{
Serial.println("\n按键已长按5秒,正在清空网络连保存接信息.");
restoreWiFi(); //删除保存的wifi信息
ESP.restart(); //重启复位esp32
Serial.println("已重启设备.");//有机会读到这里吗?
}
}
checkDNS_HTTP(); //检测客户端DNS&HTTP请求,也就是检查配网页面那部分
checkConnect(true); //检测网络连接状态,参数true表示如果断开重新连接
delay(30);
}
不想了解代码实现的就不用往下看了,没必要没必要
从setup()中调用了connectToWiFi(connectTimeOut_s);函数,进入连接wifi的入口。
/*
* 连接WiFi
*/
void connectToWiFi(int timeOut_s)
{
WiFi.hostname(HOST_NAME); //设置设备名
Serial.println("进入connectToWiFi()函数");
WiFi.mode(WIFI_STA); //设置为STA模式并连接WIFI
WiFi.setAutoConnect(true); //设置自动连接
if (wifi_ssid != "") //wifi_ssid不为空,意味着从网页读取到wifi
{
Serial.println("用web配置信息连接.");
WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str()); //c_str(),获取该字符串的指针
wifi_ssid = "";
wifi_pass = "";
}
else //未从网页读取到wifi
{
Serial.println("用nvs保存的信息连接.");
WiFi.begin(); //begin()不传入参数,默认连接上一次连接成功的wifi
}
int Connect_time = 0; //用于连接计时,如果长时间连接不成功,复位设备
while (WiFi.status() != WL_CONNECTED) //等待WIFI连接成功
{
Serial.print("."); //一共打印30个点点
digitalWrite(LED, !digitalRead(LED));
delay(500);
Connect_time ++;
if (Connect_time > 2 * timeOut_s) //长时间连接不上,重新进入配网页面
{
digitalWrite(LED, LOW);
Serial.println(""); //主要目的是为了换行符
Serial.println("WIFI autoconnect fail, start AP for webconfig now...");
wifiConfig(); //开始配网功能
return; //跳出 防止无限初始化
}
}
if (WiFi.status() == WL_CONNECTED) //如果连接成功
{
Serial.println("WIFI connect Success");
Serial.printf("SSID:%s", WiFi.SSID().c_str());
Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
Serial.print("LocalIP:");
Serial.print(WiFi.localIP());
Serial.print(" ,GateIP:");
Serial.println(WiFi.gatewayIP());
Serial.print("WIFI status is:");
Serial.print(WiFi.status());
digitalWrite(LED, HIGH);
server.stop(); //停止开发板所建立的网络服务器。
}
}
本函数先检测wifi_ssid是否读进了参数,尝试用wifi_ssid方式和用上次连接成功保存的参数两种方式尝试连接,等待连接后未连接成功将调用wifiConfig()开始配网,连接成功则打印连接数据。
我要是每个函数都拿出来讲是不是很烦人啊~
WiFi.hostname(HOST_NAME); //设置设备名
此函数定义在ESP32官方库的WiFiGenerice库中
函数定义:输入参数手动给ESP32模块设置hostname(主机名)
当联网成功后打开路由器界面,可查看到连接设备:
说明我们设置的没问题。
WiFi.mode(WIFI_STA); //设置为STA模式并连接WIFI
此函数定义在WiFiGenerice库中
函数定义:配置WiFi的工作模式
工作模式一共有三种:接入点模式(AP)、无线终端模式(Station)以及混合模式。
WiFi.setAutoConnect(true); //设置自动连接
此函数定义在WiFiSTA库中
函数定义:激活ESP32模块的自动连接模式。模块会在通电后自动连接到最近连接过的WiFi接入点。
ture:启动自动连接。false:禁用自动连接。
WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str()); //c_str(),获取该字符串的指针
此函数定义在WiFiSTA库中
函数定义:此函数用于连接WiFi,需要传入的函数是指针类型的。如果不传入参数,默认连接已保存的wifi。
WiFi.status() != WL_CONNECTED
此函数定义在WiFiSTA库中
函数定义:判断wifi连接状态
//WebServer server(webPort);
server.stop();
此函定义在WebServer库中
函数定义:本函数用于停止开发板所建立的网络服务器。
/*
* 配置配网功能
*/
void wifiConfig()
{
initSoftAP();
initDNS();
initWebServer();
scanWiFi();
}
此函数调用四个函数实现配网功能的开启。
/*
* 进入AP模式
*/
void initSoftAP() {
WiFi.mode(WIFI_AP); //配置为AP模式
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //设置AP热点IP和子网掩码
if (WiFi.softAP(AP_SSID)) //开启AP热点,如需要密码则添加第二个参数
{
//打印相关信息
Serial.println("ESP-32S SoftAP is right.");
Serial.print("Soft-AP IP address = ");
Serial.println(WiFi.softAPIP()); //接入点ip
Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str()); //接入点mac
}
else //开启AP热点失败
{
Serial.println("WiFiAP Failed");
delay(1000);
Serial.println("restart now...");
ESP.restart(); //重启复位esp32
}
}
主要是配置为AP热点模式
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //设置AP热点IP和子网掩码
此函数定义在WiFiAP库
函数定义:配置接入点网络信息
三个参数分别为:接入点ip地址,网关ip地址,子虚掩码(均为IPAddress类型)
不懂就照着写吧!
WiFi.softAP(AP_SSID)
此函数定义在WiFiAP库
函数定义:启动校验式wifi网络或开放式wifi网络。
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false);
此函数参数有:网络名称、密码、信道、wifi是否隐藏标志变量、最大允许接入数量(最多4个)
其他都默认就行。密码默认NULL
一般用不到其他功能。
WiFi.softAPmacAddress()
此函数定义在WiFiAP库
函数定义:建立wifi接入点后,我们可以使用本函数获取开发板的mac地址。
另一种使用方法
WiFi.softAPmacAddress(macAddr)
读mac地址:
macAddr[0]:macAddr[1]:macAddr[2]:macAddr[3]:macAddr[4]:macAddr[5]这种形式!!
void initDNS()
{
if (dnsServer.start(DNS_PORT, "*", apIP)) //判断将所有地址映射到esp32的ip上是否成功
{
Serial.println("start dnsserver success.");
} else {
Serial.println("start dnsserver failed.");
}
}
DNS:域名服务器。域名服务器_百度百科
此函数没有考虑开启失败的问题!!
dnsServer.start(DNS_PORT, "*", apIP)
此函数定义在DNSServer库
函数定义:以无线终端模式工作时,调用本函数可以启动ESP32模块的DNS服务
函数有三个参数:
返回值:是否开启成功
这里的 * 替换成你想要的网站,例如:www.example.com 。可以替换成你想要的网址。当做项目时,替换成一个能代表你的网址就显得专业了~哈哈哈哈!实际访问的还是配网的ip地址。
void initWebServer()
{
if (MDNS.begin("esp32")) //给设备设定域名esp32,完整的域名是esp32.local
{
Serial.println("MDNS responder started");
}
//必须添加第二个参数HTTP_GET,以下面这种格式去写,否则无法强制门户
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
server.on("/", HTTP_GET, handleRoot); // 当浏览器请求服务器根目录(网站首页)时调用自定义函数handleRoot处理,设置主页回调函数,必须添加第二个参数HTTP_GET,否则无法强制门户
server.on("/configwifi", HTTP_POST, handleConfigWifi); // 当浏览器请求服务器/configwifi(表单字段)目录时调用自定义函数handleConfigWifi处理
server.onNotFound(handleNotFound); //当浏览器请求的网络资源无法在服务器找到时调用自定义函数handleNotFound处理
server.begin(); //启动TCP SERVER
Serial.println("WebServer started!");
}
此函数创建了网络服务器。
MDNS.begin("esp32") //给设备设定域名esp32,完整的域名是esp32.local
多播DNS
这个问题我不会!尴尬了!!
server.on("/", HTTP_GET, handleRoot); // 当浏览器请求服务器根目录(网站首页)时调用自定义函数handleRoot处理,设置主页回调函数,必须添加第二个参数HTTP_GET,否则无法强制门户
此函数定义在 WebServer库
函数定义:每当有客户端向服务器发送HTTP请求时,我们可以利用on函数来设置HTTP请求回调函数。
通过HTTP请求回调函数,我们可以让ESP32服务器生成响应信息并发送给HTTP请求客户端。
第二个参数为数据传输方法。
关键字:
server.onNotFound(handleNotFound); //当浏览器请求的网络资源无法在服务器找到时调用自定义函数handleNotFound处理
此函数定义在 WebServer库
函数定义:每当有客户端向服务器发送HTTP请求时,我们可以利用onNotFound函数来设置HTTP请求无效地址的回调函数。
参数:处理无效地址请求的回调函数
server.begin(); //启动TCP SERVER
此函数定义在 WebServer库
函数定义:启动开发板所建立的网络服务器。
/*
* 扫描附近的WiFi,为了显示在配网界面
*/
bool scanWiFi() {
Serial.println("scan start");
Serial.println("--------->");
// 扫描附近WiFi
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
scanNetworksID = "no networks found";
return false;
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
scanNetworksID += "<P>" + WiFi.SSID(i) + "</P>";
delay(10);
}
return true;
}
}
此函数扫描可搜索到的wifi,附加在HTML代码后。
WiFi.scanNetworks()
此函数定义在WiFiScan库
函数定义:扫描到ESP8266开发板所在环境中的可用WIFI网络,并且将WiFi网络信息保存到内存中。通过调用SSID、RSSI等函数,我们还可以得到这些扫描到的WIFI的更多信息。
此函数一次性得到完整的WiFi列表,并且将WiFi列表保存在内存中。
返回值:扫描到可用的网络数量
(WiFi.encryptionType(i) == WIFI_AUTH_OPEN
此函数定义在WiFiScan库
函数定义:通过此函数,我们可以获取扫描到的WiFi网络信息中的网络加密类型。
参数为扫描到的wifi的序列号
返回值:返回的wifi加密类型
WiFi.SSID(i)
此函数定义在WiFiScan库
函数定义:获取扫描到的WiFi网络信息中的网络名称(SSID)信息。
返回:扫描到的WiFi网络信息中的网络名称(SSID)信息(类型:String)
/*
* 处理网站根目录的访问请求
*/
void handleRoot()
{
if (server.hasArg("selectSSID")) {
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>"); //scanNetWprksID是扫描到的wifi
} else {
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
}
}
server.hasArg("selectSSID")
此函数定义在WebServer库中
函数定义:可以获取客户端向ESP32物联网服务器发送的请求信息中有无指定的参数。
传入参数:需要确认的请求体中的参数名
返回值:是否存在指定参数
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
//这里拆开是为了添加上wifi目录
此函数定义在WebServer库中
函数定义:如果有客户端向ESP8266服务器发送HTTP请求,ESP8266服务器可使用本函数向客户端发送响应信息。
参数:响应状态码,响应内容类型,响应内容
/*
* 提交数据后的提示页面
*/
void handleConfigWifi() //返回http状态
{
if (server.hasArg("ssid")) //判断是否有账号参数
{
Serial.print("got ssid:");
wifi_ssid = server.arg("ssid"); //获取html表单输入框name名为"ssid"的内容
Serial.println(wifi_ssid);
}
else //没有参数
{
Serial.println("error, not found ssid");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid"); //返回错误页面
return;
}
//密码与账号同理
if (server.hasArg("pass"))
{
Serial.print("got password:");
wifi_pass = server.arg("pass"); //获取html表单输入框name名为"pwd"的内容
Serial.println(wifi_pass);
}
else
{
Serial.println("error, not found password");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
return;
}
server.send(200, "text/html", "<meta charset='UTF-8'>SSID:" + wifi_ssid + "<br />password:" + wifi_pass + "<br />已取得WiFi信息,正在尝试连接,请手动关闭此页面。"); //返回保存成功页面
delay(2000);
WiFi.softAPdisconnect(true); //参数设置为true,设备将直接关闭接入点模式,即关闭设备所建立的WiFi网络。
server.close(); //关闭web服务
WiFi.softAPdisconnect(); //在不输入参数的情况下调用该函数,将关闭接入点模式,并将当前配置的AP热点网络名和密码设置为空值.
Serial.println("WiFi Connect SSID:" + wifi_ssid + " PASS:" + wifi_pass);
if (WiFi.status() != WL_CONNECTED) //wifi没有连接成功
{
Serial.println("开始调用连接函数connectToWiFi()..");
connectToWiFi(connectTimeOut_s);
}
else {
Serial.println("提交的配置信息自动连接成功..");
}
}
读输入的参数,写入wifi账号密码。
wifi_ssid = server.arg("ssid"); //获取html表单输入框name名为"ssid"的内容
此函数定义在WebServer库中
函数定义:获取客户端向ESP8266物联网服务器发送的指定参数的数值。
参数:请求体中的参数名(参数类型: String)
返回值:指定参数的数值(类型:String)
WiFi.softAPdisconnect(true); //参数设置为true,设备将直接关闭接入点模式,即关闭设备所建立的WiFi网络。
此函数定义在WiFiAP库
函数定义:可用于关闭开发板的接入点模式,即关闭开发板所建立的WiFi网络。
传入参数:
参数类型为bool。如果将该参数设置为true,设备将直接关闭接入点模式。
在不输入参数的情况下调用该函数,设备会将当前配置的网络名和密码设置为空值。
返回值:返回设置是否成功的结果。设置成功返回true。数据类型为bool型。
server.close(); //关闭web服务
此函数定义在WebServer库
函数定义:本函数用于停止ESP32开发板所建立的网络服务器。
/*
* 处理404情况的函数'handleNotFound'
*/
void handleNotFound() { // 当浏览器请求的网络资源无法在服务器找到时通过此自定义函数处理
handleRoot(); //访问不存在目录则返回配置页面
// server.send(404, "text/plain", "404: Not found");
}
/*
* 删除保存的wifi信息,这里的删除是删除存储在flash的信息。删除后wifi读不到上次连接的记录,需重新配网
*/
void restoreWiFi() {
delay(500);
esp_wifi_restore(); //删除保存的wifi信息
Serial.println("连接信息已清空,准备重启设备..");
delay(10);
blinkLED(LED, 5, 500); //LED闪烁5次 //关于LED,不需要可删除
digitalWrite(LED, LOW); //关于LED,不需要可删除
}
#include <esp_wifi.h> //用于esp_wifi_restore() 删除保存的wifi信息
esp_wifi_restore(); //删除保存的wifi信息
/*
* 检查wifi是否已经连接
*/
void checkConnect(bool reConnect)
{
if (WiFi.status() != WL_CONNECTED) //wifi连接失败
{
if (digitalRead(LED) != LOW)
digitalWrite(LED, LOW);
if (reConnect == true && WiFi.getMode() != WIFI_AP && WiFi.getMode() != WIFI_AP_STA )
{
Serial.println("WIFI未连接.");
Serial.println("WiFi Mode:");
Serial.println(WiFi.getMode());
Serial.println("正在连接WiFi...");
connectToWiFi(connectTimeOut_s); //连接wifi函数
}
}
else if (digitalRead(LED) != HIGH)
digitalWrite(LED, HIGH); //wifi连接成功
}
里面包含的函数上面都说过了。
/*
* 检测客户端DNS&HTTP请求
*/
void checkDNS_HTTP()
{
dnsServer.processNextRequest(); //检查客户端DNS请求
server.handleClient(); //检查客户端(浏览器)http请求
}
要放在loop函数中,检测http和dns消息。然后 server.on 函数定义的回调函数。
/*
* LED闪烁函数 //用不上LED可删除
*/
void blinkLED(int led, int n, int t)
{
for (int i = 0; i < 2 * n; i++)
{
digitalWrite(led, !digitalRead(led));
delay(t);
}
}
/*
* LED初始化
*/
void LEDinit()
{
pinMode(LED, OUTPUT); //配置LED口为输出口
digitalWrite(LED, LOW); //初始灯灭
}
这一部分没啥好说的了吧 ~
呼 ~ 累死我了!!
终于写完了,不怕以后忘记了!!!哈哈哈哈哈哈
如果你看到这里了,觉得本文对你有帮助,那就帮我 点~点~关~注~
哈哈哈哈 ~ 开心吗 ~ 学习到小知识真的很开心呢~
加油鸭!!!!!!!!
【2023年3月3日】更新:
有人问到WebServer的库没有找到,现在附上库的链接:
文章浏览阅读727次。全局变量和局部变量在看了一个博主写的关于js全局变量的的介绍后,自己也跟着做了一下,并且记录在这里。原博客地址:谈谈JS的全局变量跟局部变量。博主说的比较详细,也比我的表达好,如果不是没耐心,建议去看看原博主的文章先上一段代码:<script type="text/javascript"> var a =1; function test(){ alert(a); a=4; aler_var a=‘test’ function test(){ alart(a) var a=‘run’ alart(a)} test();
文章浏览阅读373次。Vue3带来了什么?1.性能的提升 *打包大小减少41%;*初次渲染快55%, 更新渲染快133% ;*内存减少54% … ;2.源码的升级 *使用Proxy代替defineProperty实现响应式 ;*重写虚拟DOM的实现和Tree-Shaking … ;3.新的特性 1.Composition API(组合API);*setup配置 *ref与reactive *watch与watchEffect * provide与inject 2. 新的内置组件 *Fragment * Teleport ....
文章浏览阅读185次。11.管理网络1.ip基础知识1.ipv42进制32位-----10进制172.25.0.10/255.255.255.0172.25.0.10:ip地址255.255.255.0:子网掩码子网掩码255位对应的ip位为网络位子网掩码0对应的ip位为主机位####2.配置ip####<<图形化>>1.图形界面nm-connection-editor2.文本化图形nmtui&..._网关数据解压配置
文章浏览阅读257次。一、Dijkstra邻接矩阵算法题目链接:https://www.acwing.com/problem/content/851/代码:#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int N = 510;int g[N][N];int dist[N];bool st[N];int n,m;int Dijkstra(){ _c语言 图 prim算法 kruskal floyd dijkstra
文章浏览阅读1.6k次,点赞25次,收藏16次。FPGA高端项目:FPGA基于GS2971的SDI视频接收+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持_gtx解码
文章浏览阅读2.5k次,点赞6次,收藏32次。文章目录前言一、监督分类介绍1. 定义2. 监督分类方法二、geemap中监督分类的详细步骤1. 加载地图底图2. 加载研究区影像数据3. 创建训练样本4. 分类器训练5. 影像监督分类6. 分类结果颜色修改7. 添加图例和可视化展示8. 分类结果导出总结前言本节以一个具体遥感影像处理的案例——基于遥感影像的监督分类,介绍一下使用Earth Engine对遥感影像进行监督分类的具体操作流程。一、监督分类介绍1. 定义监督分类:监督分类是遥感图像分类的一种,即用被确认类别的样本像元去识别其他未知_smilecart
文章浏览阅读615次。一、开发环境OSWindows 7 Ultimate 64 BitIDEVisual Studio 2012 Premium (MSVC++ 11.0)Qt5 Visual Studio Add-in 1.2.3External LibrariesQt 5.3 32-bit for Desktop (MSVC 2012 OpenGL) [GPL]OGDF ..._vc能实现可视化qt吗
文章浏览阅读5.2k次,点赞10次,收藏38次。存储消息的队列。消息:比如字符串,对象,二进制数据,json等等。队列:先进先出的数据结构。耗时的场景(比如支付结果查询)异步化的场景(比如远程控制)应用解耦的场景消息队列的好处异步处理削峰填谷应用解耦要给系统引入额外的中间件,维护成本,资源成本,学习成本。消息队列:就需要考虑,消息丢失,消费消息,数据的一致性。中间件消息队列也是中间件的一种,我们可以注意到,它是作为生产和消费的中间人,进行传递消息,实现解耦。
文章浏览阅读1.3k次。提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档C++中的数据前言一、C++的数据变量的存储方式类型1.1 自动存储1.2 静态存储变量1.3 动态存储二、数据变量的存储持续性、作用域和链接性2.1 存储的持续性2.2 作用域和链接性2.2.1 自动变量的作用域和链接性2.2.2 静态变量的作用域和链接性2.2.3 静态变量的外部链接性2.2.3.1 单定义规则2.2.4 静态变量的内部链接性2.2.5 静态变量的无链接性三、存储说明符和限定符前言 本文主要介绍C++中变量的存_c++ 高频存储数据
文章浏览阅读492次。output_path: “/home/tong/output/”,改成自己的,其他的看自己用的啥相机,改话题名字和相关参数。当前帧在滑动窗口优化一次即吐出位姿。_vins-fusion运行
文章浏览阅读3.3k次,点赞10次,收藏54次。STM32单片机、有人云平台的使用、4G模块连接有人云平台、云平台、小程序数据显示_小程序接收4g模组数据
文章浏览阅读320次,点赞3次,收藏3次。对于imageProjection的原理分析。对于其中的数学原理进行一次解析,与代码配合使用。_空间域image projection