ESP8266学习记录

一、接入点模式

NodeMCU可以建立WiFi网络供其它设备连接。当NodeMCU以此模式运行时,我们可以使用手机搜索NodeMCU所发出的WiFi网络并进行连接。

通过以下示例程序,NodeMCU将会建立一个名为我将点燃大海的WiFI。您可以使用手机或电脑连接该WiFi从而实现与NodeMCU的网络通讯。

#include <ESP8266WiFi.h>        // 本程序使用ESP8266WiFi库const char *ssid = "我将点燃大海"; // 这里定义将要建立的WiFi名称。此处以"taichi-maker"为示例// 您可以将自己想要建立的WiFi名称填写入此处的双引号中const char *password = "12345678";  // 这里定义将要建立的WiFi密码。此处以12345678为示例// 您可以将自己想要使用的WiFi密码放入引号内// 如果建立的WiFi不要密码,则在双引号内不要填入任何信息void setup() {Serial.begin(9600);              // 启动串口通讯WiFi.softAP(ssid, password);     // 此语句是重点。WiFi.softAP用于启动NodeMCU的AP模式。// 括号中有两个参数,ssid是WiFi名。password是WiFi密码。// 这两个参数具体内容在setup函数之前的位置进行定义。Serial.print("Access Point: ");    // 通过串口监视器输出信息Serial.println(ssid);              // 告知用户NodeMCU所建立的WiFi名Serial.print("IP address: ");      // 以及NodeMCU的IP地址Serial.println(WiFi.softAPIP());   // 通过调用WiFi.softAPIP()可以得到NodeMCU的IP地址
}void loop() { 
}

NodeMCU在每次启动以后,都会自动启动接入点模式。接入点WiFi的详细信息会通过串口监视器输出给用户查看。

接下来就可以连接了,密码是12345678,当然他只是个wifi ,不能实现联网功能,但可以实现接受与发送消息,也可以cmd 输入ipconfig 查看ip,然后ping通。

二、NodeMCU开发板的无线终端模式

1、连接指定WiFI

如图所示,ESP8266可通过WiFi连接无线路由器。这与用您的手机通过WiFi连接无线路由器的模式相同,说白了就是可以连接自己的wifi 或者手机热点,是个人pc与8266在同一个局域网里面。

#include <ESP8266WiFi.h>        // 本程序使用ESP8266WiFi库const char* ssid     = "快去摸鱼";      // 连接WiFi名(此处使用taichi-maker为示例)// 请将您需要连接的WiFi名填入引号中
const char* password = "12345678aqz";          // 连接WiFi密码(此处使用12345678为示例)// 请将您需要连接的WiFi密码填入引号中void setup() {Serial.begin(9600);         // 启动串口通讯WiFi.begin(ssid, password);                  // 启动网络连接Serial.print("Connecting to ");              // 串口监视器输出网络连接信息Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值}                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。// 这个读秒是通过变量i每隔一秒自加1来实现的。Serial.println("");                          // WiFi连接成功后Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
}void loop() {                                   
}

打开串口助手,就可以看到打印的信息了。

2、自动连接最强信号WiFi网络

假如我们的NodeMCU只在一个地方使用,它也就只需要知道一个WiFi网络的连接信息。但是如果NodeMCU需要在多个地方使用,这时候就需要它能存储多个地点的WiFi信息。通过以下示例程序,NodeMCU可以在它所处的网络环境里搜索预先存储好的WiFi。一旦找到预存的WiFi名称,NodeMCU将会使用预存的密码信息尝试连接该WiFi。如果同时找到多个预存WiFi,NodeMCU将会尝试连接信号最强的WiFi。

#include <ESP8266WiFi.h>          // 本程序使用ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   // 本程序使用ESP8266WiFiMulti库ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'void setup() {Serial.begin(9600);            // 启动串口通讯//通过addAp函数存储  WiFi名称       WiFi密码wifiMulti.addAP("xxx1", "12345678");  // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。wifiMulti.addAP("xxx2", "87654321"); // 这3个WiFi网络名称分别是taichi-maker, taichi-maker2, taichi-maker3。wifiMulti.addAP("xxx3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。// 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。// 另外这里只存储了3个WiFi信息,您可以存储更多的WiFi信息在此处。Serial.println("Connecting ...");         // 通过串口监视器输出信息告知用户NodeMCU正在尝试连接WiFiint i = 0;                                 while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCUSerial.print('.');                       // 将会连接信号最强的那一个WiFi信号。}                                           // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是// 此处while循环判断是否跳出循环的条件。Serial.println('\n');                     // WiFi连接成功后Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。Serial.println(WiFi.SSID());              // 连接的WiFI名称Serial.print("IP address:\t");            // 以及Serial.println(WiFi.localIP());           // NodeMCU的IP地址
}void loop() { 
}

三、NodeMCU 网络服务器

1、NodeMCU 建立网络服务器

网络服务器有很多种类型,它们的功能也十分丰富。通常承担网络服务器工作的设备都是运算能力比较强大的电脑。我们的ESP866-NodeMCU虽然也能实现网络服务器的一些功能,但是毕竟它的运算能力是无法与那些昂贵的服务器电脑相媲美的,因此ESP8266-NodeMCU只能实现一些基本的网络服务功能。不过这些基本的网络服务功能已经足够我们开发物联网项目了,准确来说把板子当作服务器,让他们处在同一个局域网里面,然后ip + 端口的方式连接。

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,对象名称为esp8266_server// 括号中的数字是网路服务器响应http请求的端口号// 网络服务器标准http端口号为80,因此这里使用80为端口号void setup(void){Serial.begin(9600);          // 启动串口通讯//通过addAp函数存储  WiFi名称       WiFi密码wifiMulti.addAP("快去摸鱼", "12345678aqz");  // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。int i = 0;                                 while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCUSerial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。}                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是// 此处while循环判断是否跳出循环的条件。// WiFi连接成功后将通过串口监视器输出连接成功信息 Serial.println('\n');                     // WiFi连接成功后Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。Serial.println(WiFi.SSID());              // 连接的WiFI名称Serial.print("IP address:\t");            // 以及Serial.println(WiFi.localIP());           // NodeMCU的IP地址//--------"启动网络服务功能"程序部分开始-------- esp8266_server.begin();                  esp8266_server.on("/", handleRoot);     // 路径为 / ,调用 handleRoot 函数esp8266_server.onNotFound(handleNotFound);         // 未找到路径,调用handleNotFound
//--------"启动网络服务功能"程序部分结束--------Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}void loop(void){esp8266_server.handleClient();     // 处理http服务器访问
}// 进入首页,返回200
void handleRoot() {   //处理网站根目录“/”的访问请求 esp8266_server.send(200, "text/plain", "Hello from ESP8266");   // NodeMCU将调用此函数。
}// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

2、通过网络服务实现NodeMCU开发板基本控制

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)void setup(void){Serial.begin(9600);   // 启动串口通讯pinMode(LED_BUILTIN, OUTPUT); //设置内置LED引脚为输出模式以便控制LEDwifiMulti.addAP("快去摸鱼", "12345678aqz"); // 将需要连接的一系列WiFi ID和密码输入这里Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。int i = 0;                                 while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCUSerial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。}                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是// 此处while循环判断是否跳出循环的条件。// WiFi连接成功后将通过串口监视器输出连接成功信息 Serial.println('\n');Serial.print("Connected to ");Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称Serial.print("IP address:\t");Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IPesp8266_server.begin();                           // 启动网站服务esp8266_server.on("/", HTTP_GET, handleRoot);     // 设置服务器根目录即'/'的函数'handleRoot'esp8266_server.on("/LED", HTTP_POST, handleLED);  // 设置处理LED控制请求的函数'handleLED'esp8266_server.onNotFound(handleNotFound);        // 设置处理404情况的函数'handleNotFound'Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}void loop(void){esp8266_server.handleClient();                     // 检查http服务器访问
}/*设置服务器根目录即'/'的函数'handleRoot'该函数的作用是每当有客户端访问NodeMCU服务器根目录时,NodeMCU都会向访问设备发送 HTTP 状态 200 (Ok) 这是send函数的第一个参数。同时NodeMCU还会向浏览器发送HTML代码,以下示例中send函数中第三个参数,也就是双引号中的内容就是NodeMCU发送的HTML代码。该代码可在网页中产生LED控制按钮。 当用户按下按钮时,浏览器将会向NodeMCU的/LED页面发送HTTP请求,请求方式为POST。NodeMCU接收到此请求后将会执行handleLED函数内容*/
void handleRoot() {       esp8266_server.send(200, "text/html", "<form action=\"/LED\" method=\"POST\"><input type=\"submit\" value=\"Toggle LED\"></form>");
}//处理LED控制请求的函数'handleLED'
void handleLED() {                          digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));// 改变LED的点亮或者熄灭状态esp8266_server.sendHeader("Location","/");          // 跳转回页面根目录esp8266_server.send(303);                           // 发送Http相应代码303 跳转  
}// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){esp8266_server.send(404, "text/plain", "404: Not found"); // 发送 HTTP 状态 404 (未找到页面) 并向浏览器发送文字 "404: Not found"
}

点击Toggle LED 开发板的LED亮或灭。

3、通过网络服务将开发板引脚状态显示在网页中

D3引脚是与开发板上的FLASH按键开关连接好了,所以当我们按下falsh 按钮,d3的状态刷新。

#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库#define buttonPin D3            // 按钮引脚D3ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)bool pinState;  // 存储引脚状态用变量void setup(){Serial.begin(9600);   // 启动串口通讯pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式wifiMulti.addAP("快去摸鱼", "12345678aqz"); // 将需要连接的一系列WiFi ID和密码输入这里Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。int i = 0;                                 while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCUSerial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。}                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是// 此处while循环判断是否跳出循环的条件。// WiFi连接成功后将通过串口监视器输出连接成功信息 Serial.println('\n');                     // WiFi连接成功后Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。Serial.println(WiFi.SSID());              // 连接的WiFI名称Serial.print("IP address:\t");            // 以及Serial.println(WiFi.localIP());           // NodeMCU的IP地址esp8266_server.begin();                   // 启动网站服务                esp8266_server.on("/", handleRoot);       // 设置服务器根目录即'/'的函数'handleRoot'esp8266_server.onNotFound(handleNotFound);// 设置处理404情况的函数'handleNotFound'        Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}void loop(){esp8266_server.handleClient();     // 处理http服务器访问pinState = digitalRead(buttonPin); // 获取引脚状态
}/* 以下函数处理网站首页的访问请求。此函数为本示例程序重点1
详细讲解请参见太极创客网站《零基础入门学用物联网》
第3章-第2节“通过网络服务将开发板引脚状态显示在网页中”的说明讲解。*/                                                                       
void handleRoot() {   String displayPinState;                   // 存储按键状态的字符串变量if(pinState == HIGH){                     // 当按键引脚D3为高电平displayPinState = "Button State: HIGH"; // 字符串赋值高电平信息} else {                                  // 当按键引脚D3为低电平displayPinState = "Button State: LOW";  // 字符串赋值低电平信息}esp8266_server.send(200, "text/plain", displayPinState); // 向浏览器发送按键状态信息  
}// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){                                        // 当浏览器请求的网络资源无法在服务器找到时,esp8266_server.send(404, "text/plain", "404: Not found");   // NodeMCU将调用此函数。
}

在以上程序的loop函数中,pinState = digitalRead(buttonPin); 语句将不断检查NodeMCU开发板D3引脚状态,也就是检查该引脚所连接的按键是否被按下。该状态将会存储与布尔变量pinState中。

没有按下:Button State: HIGH

按下了:Button State: LOW

但是这个有个缺陷,就是页面要自己手动刷新,才能看到,我们设置个页面每隔几秒刷新一次。

/*
建立用于发送给客户端浏览器的HTML代码。此代码将会每隔5秒刷新页面。
通过页面刷新,引脚的最新状态也会显示于页面中
*/
String sendHTML(bool buttonState){String htmlCode = "<!DOCTYPE html> <html>\n";htmlCode +="<head><meta http-equiv='refresh' content='5'/>\n";htmlCode +="<title>ESP8266 Butoon State</title>\n";htmlCode +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";htmlCode +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";htmlCode +="</style>\n";htmlCode +="</head>\n";htmlCode +="<body>\n";htmlCode +="<h1>ESP8266 BUTTON STATE</h1>\n";if(buttonState){htmlCode +="<p>Button Status: HIGH</p>\n";}else{htmlCode +="<p>Button Status: LOW</p>\n";}htmlCode +="</body>\n";htmlCode +="</html>\n";return htmlCode;
}

四、NodeMCU 闪存文件系统

问:当我们上传程序给ESP8266时,我们的程序具体存放在什么地方呢?

每一个ESP8266都配有一个闪存,这个闪存很像是一个小硬盘,我们上传的文件就被存放在这个闪存里。这个闪存的全称是Serial Peripheral Interface Flash File System(SPIFFS)。

除了可以存放上传的程序以外,我们还可以将网页文件或者系统配置文件存放在ESP8266的闪存中。在这节课里,我们将学习如何利用程序对闪存文件系统(SPIFFS)进行文件读取和修改。

1、写入信息

函数说明:

SPIFFS.open(file_name, "w");

以上函数有两个参数:

第一个参数是被操作的文件名称,本示例中该文件为/notes.txt

第二个参数"w" 代表写入文件信息。(如需了解如何读取信息,请参阅示例程序esp8266-flash-read)。

#include <FS.h>  String file_name = "/taichi-maker/notes.txt"; //被读取的文件位置和名称void setup() {Serial.begin(9600);Serial.println("");Serial.println("SPIFFS format start");SPIFFS.format();    // 格式化SPIFFSSerial.println("SPIFFS format finish");if(SPIFFS.begin()){ // 启动SPIFFSSerial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}File dataFile = SPIFFS.open(file_name, "w");// 建立File对象用于向SPIFFS中的file对象(即/notes.txt)写入信息dataFile.println("Hello IOT World.");       // 向dataFile写入字符串信息dataFile.close();                           // 完成文件写入后关闭文件Serial.println("Finished Writing data to SPIFFS");
}void loop() {
}

2、读取信息

函数说明:

SPIFFS.open(file_name, "r");

以上SPIFFS函数有两个参数:

第一个参数是被操作的文件名称,本示例中该文件为/notes.txt

第二个参数"r" 代表读取文件信息。(如需了解如何写入信息,请参阅示例程序esp8266-flash-write)


#include <FS.h>String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称void setup() {Serial.begin(9600);Serial.println("");if(SPIFFS.begin()){ // 启动闪存文件系统Serial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}//确认闪存中是否有file_name文件if (SPIFFS.exists(file_name)){Serial.print(file_name);Serial.println(" FOUND.");} else {Serial.print(file_name);Serial.print(" NOT FOUND.");}//建立File对象用于从SPIFFS中读取文件File dataFile = SPIFFS.open(file_name, "r"); //读取文件内容并且通过串口监视器输出文件信息for(int i=0; i<dataFile.size(); i++){Serial.print((char)dataFile.read());       }//完成文件读取后关闭文件dataFile.close();                           
}void loop() {
}

3、添加信息

函数说明:

SPIFFS.open(file_name, "a");

以上SPIFFS函数有两个参数:

第一个参数是被操作的文件名称,本示例中该文件为/notes.txt

第二个参数"a" 代表添加文件信息。(如需了解如何读取信息,请参阅示例程序esp8266-flash-read)

此示例程序所演示的是向SPIFFS中的文件里添加信息。这一操作写入信息有所区别。

添加信息是不会删除文件内原有信息,而是在原有信息后面添加新的信息。

但写入操作(示例 esp8266-flash-write.ino)是将文件内容完全清除,重新写入新信息。    

#include <FS.h>String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称void setup() {Serial.begin(9600);Serial.println("");if(SPIFFS.begin()){ // 启动闪存文件系统Serial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}//确认闪存中是否有file_name文件if (SPIFFS.exists(file_name)){Serial.print(file_name);Serial.println(" FOUND.");File dataFile = SPIFFS.open(file_name, "a");// 建立File对象用于向SPIFFS中的file对象(即/notes.txt)写入信息dataFile.println("This is Appended Info."); // 向dataFile添加字符串信息dataFile.close();                           // 完成文件操作后关闭文件   Serial.println("Finished Appending data to SPIFFS");} else {Serial.print(file_name);Serial.print(" NOT FOUND.");}}void loop() {
}

4、读取目录内容

函数说明:

SPIFFS.openDir(folder_name);

以上函数打开指定目录并返回一个目录对象实例。

#include <FS.h>String file_name = "/taichi-maker/myFile.txt"; //被读取的文件位置和名称
String folder_name = "/taichi-maker";         //被读取的文件夹void setup() {Serial.begin(9600);Serial.println("");if(SPIFFS.begin()){ // 启动闪存文件系统Serial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}File dataFile = SPIFFS.open(file_name, "w");// 建立File对象用于向SPIFFS中的file对象(即myFile.txt)写入信息dataFile.println("Hello Taichi-Maker.");    // 向dataFile写入字符串信息dataFile.close();                           // 完成文件写入后关闭文件Serial.println(F("Finished Writing data to SPIFFS"));// 显示目录中文件内容以及文件大小Dir dir = SPIFFS.openDir(folder_name);  // 建立“目录”对象while (dir.next()) {  // dir.next()用于检查目录中是否还有“下一个文件”Serial.println(dir.fileName()); // 输出文件名}
}void loop() {
}

5、删除信息

#include <FS.h>String file_name = "/taichi-maker/notes.txt";              //被读取的文件位置和名称void setup() {Serial.begin(9600);Serial.println("");if(SPIFFS.begin()){ // 启动闪存文件系统Serial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}//从闪存中删除file_name文件if (SPIFFS.remove(file_name)){Serial.print(file_name);Serial.println(" remove sucess");} else {Serial.print(file_name);Serial.println(" remove fail");}                       
}void loop() {
}

通过使用SPIFFS.remove(file_name)file_name所指代的文件进行了删除操作。另外,SPIFFS.remove(file_name)的返回值为布尔型。如果文件删除执行成功则返回真,否则返回假。 

6、显示闪存文件系统信息

#include <FS.h>FSInfo fs_info;void setup() {Serial.begin(9600);SPIFFS.begin();       //启动SPIFFSSerial.println("");Serial.println("SPIFFS Started.");// 闪存文件系统信息SPIFFS.info(fs_info);// 可用空间总和(单位:字节)Serial.print("totalBytes: ");     Serial.print(fs_info.totalBytes); Serial.println(" Bytes"); // 已用空间(单位:字节)Serial.print("usedBytes: "); Serial.print(fs_info.usedBytes);Serial.println(" Bytes"); // 最大文件名字符限制(含路径和'\0')Serial.print("maxPathLength: "); Serial.println(fs_info.maxPathLength);// 最多允许打开文件数量Serial.print("maxOpenFiles: "); Serial.println(fs_info.maxOpenFiles);// 存储块大小Serial.print("blockSize: "); Serial.println(fs_info.blockSize);// 存储页大小Serial.print("pageSize: ");Serial.println(fs_info.pageSize);
}void loop() {
}

五、ESP8266网络客户端基本操作

在我们上网过程中,经常使用网页浏览器来浏览网站信息。在这一场景中,我们的网站浏览器就是一个网络客户端。网络客户端的主要功能就是向服务器发送网络请求。服务器在接收到客户端请求后会将请求的信息回复给客户端。

1、ESP8266HTTPClient库实现网络通讯

重点1. 声明HTTPClient对象,对象名称httpClient。后续程序中,我们将使用对象httpClient控制ESP8266的网络通讯。

重点2. 通过ESP8266HTTPClient库的begin函数来设置ESP8266发送HTTP请求的目标URL。

重点3. 通过ESP8266HTTPClient库的GET函数向服务器发送HTTP请求。

重点4. 以上重点3中GET函数的返回值是网络服务器响应状态码。根据该状态码,我们可以判断服务器是否成功接收到了ESP8266客户端的请求。如果服务器成功接收到请求,我们就可以在接下来使用getString函数来获取服务器响应报文(服务器响应体)信息,并且将该信息传递给responsePayload变量以便我们在后面通过串口监视器显示服务器响应报文。(这一报文信息正是www.example.com网站的首页HTML源代码)。

重点5.执行完以上操作后,我们将关闭ESP8266与服务器连接。这里是通过ESP8266HTTPClient库的end函数来实现这一操作的。

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>// 测试HTTP请求用的URL。注意网址前面必须添加"http://"
String URL = "http://www.example.com";// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "快去摸鱼";
const char* password = "12345678aqz";void setup() {//初始化串口设置Serial.begin(9600);//设置ESP8266工作模式为无线终端模式WiFi.mode(WIFI_STA);//开始连接wifiWiFi.begin(ssid, password);//等待WiFi连接,连接成功打印IPwhile (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.print(".");}Serial.println("");Serial.print("WiFi Connected!");httpClientRequest();  
}void loop() {}// 发送HTTP请求并且将服务器响应通过串口输出
void httpClientRequest(){//重点1 创建 HTTPClient 对象HTTPClient httpClient;WiFiClient wiFiClient;//重点2 通过begin函数配置请求地址。此处也可以不使用端口号和PATH而单纯的httpClient.begin(wiFiClient, URL); Serial.print("URL: "); Serial.println(URL);//重点3 通过GET函数启动连接并发送HTTP请求int httpCode = httpClient.GET();Serial.print("Send GET request to URL: ");Serial.println(URL);//重点4. 如果服务器响应HTTP_CODE_OK(200)则从服务器获取响应体信息并通过串口输出//如果服务器不响应HTTP_CODE_OK(200)则将服务器响应状态码通过串口输出if (httpCode == HTTP_CODE_OK) {// 使用getString函数获取服务器响应体内容String responsePayload = httpClient.getString();Serial.println("Server Response Payload: ");Serial.println(responsePayload);} else {Serial.println("Server Respose Code:");Serial.println(httpCode);}//重点5. 关闭ESP8266与服务器连接httpClient.end();
}

2、使用WiFiClient库实现网络通讯

#include <ESP8266WiFi.h>const char* host = "www.example.com"; // 网络服务器地址
const int httpPort = 80;              // http端口80// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "快去摸鱼";
const char* password = "12345678aqz";void setup() {//初始化串口设置Serial.begin(9600);Serial.println("");//设置ESP8266工作模式为无线终端模式WiFi.mode(WIFI_STA);//开始连接wifiWiFi.begin(ssid, password);//等待WiFi连接,连接成功打印IPwhile (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.print(".");}Serial.println("");Serial.println("WiFi Connected!");wifiClientRequest();  
}void loop(){}// 向服务器发送HTTP请求
void wifiClientRequest(){// 建立WiFi客户端对象,对象名称clientWiFiClient client;    // 建立字符串,用于HTTP请求String httpRequest =  String("GET /") + " HTTP/1.1\r\n" +"Host: " + host + "\r\n" +"Connection: close\r\n" +"\r\n";// 通过串口输出连接服务器名称以便查阅连接服务器的网址                      Serial.print("Connecting to "); Serial.print(host); // 连接网络服务器,以下段落中的示例程序为本程序重点1// 请参考太极创客网站中关于本程序的讲解页面获取详细说明信息。网址:// http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/http-request/if (client.connect(host, httpPort)){ Serial.println(" Success!");        // 连接成功后串口输出“Success”信息client.print(httpRequest);          // 向服务器发送HTTP请求Serial.println("Sending request: ");// 通过串口输出HTTP请求信息内容以便查阅Serial.println(httpRequest);     // 通过串口输出网络服务器响应信息, 以下段落中的示例程序为本程序重点2// 请参考太极创客网站中关于本程序的讲解页面获取详细说明信息。网址:// http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/http-request/Serial.println("Web Server Response:");        while (client.connected() || client.available()){ if (client.available()){String line = client.readStringUntil('\n');Serial.println(line);}}client.stop();                      // 断开与服务器的连接Serial.print("Disconnected from "); // 并且通过串口输出断开连接信息Serial.print(host);} else{    // 如果连接不成功则通过串口输出“连接失败”信息Serial.println(" connection failed!");client.stop();}  
}

六、ESP8266通过JSON实现物联网数据通讯

1、请求JSON数据信息

示例分为两部分,一部分为服务器程序,另一部分为客户端程序。

服务器端程序主要功能:

1. 实时读取A0、 D1、D2以及D3引脚的读数。
2. 当有客户端请求时,通过响应信息将引脚读数和测试数据信息发送给客户端。
信息发送格式为json格式。以下为该json信息的示例:


{"info": {"name": "taichimaker","url": "www.taichi-maker.com","email": "taichimaker@163.com"},"digital_pin": {"d1": "1","d2": "0","d3": "1"},"analog_pin": {"a0": "500"}
}
#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库#define buttonPin D3            // 按钮引脚D3ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'ESP8266WebServer esp8266_server(80);// 建立网络服务器对象,该对象用于响应HTTP请求。监听端口(80)IPAddress local_IP(192, 168, 0, 123); // 设置ESP8266-NodeMCU联网后的IP
IPAddress gateway(192, 168, 0, 1);    // 设置网关IP(通常网关IP是WiFI路由IP)
IPAddress subnet(255, 255, 255, 0);   // 设置子网掩码
IPAddress dns(192,168,0,1);           // 设置局域网DNS的IP(通常局域网DNS的IP是WiFI路由IP)void setup(){Serial.begin(9600);          // 启动串口通讯Serial.println("");// 将引脚设置为输入上拉模式pinMode(D1, INPUT_PULLUP);pinMode(D2, INPUT_PULLUP);pinMode(buttonPin, INPUT_PULLUP);   // NodeMCU开发板按键连接在D3引脚上// 设置开发板网络环境if (!WiFi.config(local_IP, gateway, subnet)) {Serial.println("Failed to Config ESP8266 IP"); } //通过addAp函数存储  WiFi名称       WiFi密码wifiMulti.addAP("xxx", "12345678"); // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。int i = 0;                                 while (wifiMulti.run() != WL_CONNECTED) {  // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前delay(1000);                             // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCUSerial.print(i++); Serial.print(' ');    // 将会连接信号最强的那一个WiFi信号。}                                          // 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是// 此处while循环判断是否跳出循环的条件。// WiFi连接成功后将通过串口监视器输出连接成功信息 Serial.println('\n');                     // WiFi连接成功后Serial.print("Connected to ");            // NodeMCU将通过串口监视器输出。Serial.println(WiFi.SSID());              // 连接的WiFI名称Serial.print("IP address:\t");            // 以及Serial.println(WiFi.localIP());           // NodeMCU的IP地址esp8266_server.on("/", handleRoot);          esp8266_server.begin();  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}void loop(){// 处理http服务器访问esp8266_server.handleClient(); 
}                                                                   void handleRoot() {   //处理网站目录“/”的访问请求 esp8266_server.send(200, "application/json", rootJson());  
}// 实时获取ESP8266开发板引脚信息并且建立JSON信息
// 以便ESP8266服务器通过响应信息发送给客户端
String rootJson(){String jsonCode = "{\"info\": {\"name\": \"taichimaker\",\"url\": \"www.taichi-maker.com\",\"email\": \"taichimaker@163.com\"},\"digital_pin\": {\"d1\": \"";jsonCode += String(digitalRead(D1));  jsonCode += "\",\"d2\": \""; jsonCode += String(digitalRead(D2));  jsonCode += "\",\"d3\": \""; jsonCode += String(digitalRead(D3));  jsonCode += "\"},\"analog_pin\": {\"a0\": \"";jsonCode += String(analogRead(A0));jsonCode += "\"}}";  Serial.print("jsonCode: ");Serial.println(jsonCode);return jsonCode;
}

rootJson:该信息将会通过服务器响应信息发送给请求这一信息的客户端。

客户端程序的主要功能:

1. 向服务器端请求json数据信息
2. 解析服务器端响应的json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用服务器端D3引脚(按键引脚)读数来控制客户端开发板上LED的点亮和熄灭

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>ESP8266WiFiMulti wifiMulti;           // 建立ESP8266WiFiMulti对象const char* host = "192.168.0.123";   // 将要连接的服务器地址  
const int httpPort = 80;              // 将要连接的服务器端口      void setup(){Serial.begin(9600);          Serial.println("");// 设置开发板LED引脚pinMode(LED_BUILTIN, OUTPUT);digitalWrite(LED_BUILTIN, HIGH);wifiMulti.addAP("xxx", "12345678"); // 将需要连接的一系列WiFi ID和密码输入这里Serial.println("Connecting ..."); int i = 0;  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。delay(1000);Serial.print(i++); Serial.print(' ');}// WiFi连接成功后将通过串口监视器输出连接成功信息 Serial.println("");Serial.print("Connected to ");Serial.println(WiFi.SSID());              // WiFi名称Serial.print("IP address:\t");Serial.println(WiFi.localIP());           // IP
}void loop(){httpRequest();delay(3000);
}// 向服务器请求信息并对信息进行解析
void httpRequest(){WiFiClient client;String httpRequest = String("GET /") + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n";Serial.print("Connecting to "); Serial.print(host);if (client.connect(host, 80)){Serial.println(" Success!");// 向服务器发送http请求信息client.print(httpRequest);Serial.println("Sending request: ");Serial.println(httpRequest);  // 获取并显示服务器响应状态行 String status_response = client.readStringUntil('\n');Serial.print("status_response: ");Serial.println(status_response);// 使用find跳过HTTP响应头if (client.find("\r\n\r\n")) {Serial.println("Found Header End. Start Parsing.");}parseInfo(client); }else {Serial.println(" connection failed!");}   //断开客户端与服务器连接工作client.stop(); 
}void parseInfo(WiFiClient client){const size_t capacity = JSON_OBJECT_SIZE(1) + 3*JSON_OBJECT_SIZE(3) + 140;DynamicJsonDocument doc(capacity);deserializeJson(doc, client);JsonObject info = doc["info"];const char* info_name = info["name"]; // "taichimaker"const char* info_url = info["url"]; // "www.taichi-maker.com"const char* info_email = info["email"]; // "taichimaker@163.com"JsonObject digital_pin = doc["digital_pin"];const char* digital_pin_d1 = digital_pin["d1"]; // "1"const char* digital_pin_d2 = digital_pin["d2"]; // "0"const char* digital_pin_d3 = digital_pin["d3"]; // "1"const char* analog_pin_a0 = doc["analog_pin"]["a0"]; // "500"String info_name_str = info["name"].as<String>();bool d3_bool = digital_pin["d3"].as<int>();Serial.print("info_name_str = ");Serial.println(info_name_str);Serial.print("d3_bool = ");Serial.println(d3_bool);d3_bool == 0 ? digitalWrite (LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);
}

以上程序中最重点的部分是函数httpRequest。该函数向服务器发送HTTP请求,并且对服务器相应的JSON信息进行了解析。解析后的数据信息将通过串口监视器显示,其中服务器按键引脚的状态信息还被用于控制客户端板上的LED点亮和熄灭。

2、心知天气使用

如今互联网上有很多天气信息平台,心知天气是我们使用过的信息最准确,服务最稳定的平台。难能可贵的是,心知天气所提供的基础服务是完全免费的。这些免费天气信息包括天气预报信息(3日),实时天气以及生活指数。

心知天气首页地址:心知天气 - 高精度气象数据 - 天气数据API接口 - 行业气象解决方案

注册登录之后,去控制台获取私钥,注:私钥不要随便分享给别人,否则后果自负。

2.1、获取实时天气信息(温度,天气)

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>const char* ssid     = "快去摸鱼";       const char* password = "12345678aqz";       const char* host = "api.seniverse.com";     // 将要连接的服务器地址  
const int httpPort = 80;                    // 将要连接的服务器端口      // 心知天气HTTP请求所需信息
String reqUserKey = "S-xxxxx";   // 私钥
String reqLocation = "Nanchang";            // 城市
String reqUnit = "c";                      // 摄氏/华氏void setup(){Serial.begin(9600);          Serial.println("");// 连接WiFiconnectWiFi();
}void loop(){// 建立心知天气API当前天气请求资源地址String reqRes = "/v3/weather/now.json?key=" + reqUserKey ++ "&location=" + reqLocation + "&language=en&unit=" +reqUnit;// 向心知天气服务器服务器请求信息并对信息进行解析httpRequest(reqRes);delay(3000);
}// 向心知天气服务器服务器请求信息并对信息进行解析
void httpRequest(String reqRes){WiFiClient client;// 建立http请求信息String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n";Serial.println(""); Serial.print("Connecting to "); Serial.print(host);// 尝试连接服务器if (client.connect(host, 80)){Serial.println(" Success!");// 向服务器发送http请求信息client.print(httpRequest);Serial.println("Sending request: ");Serial.println(httpRequest);  // 获取并显示服务器响应状态行 String status_response = client.readStringUntil('\n');Serial.print("status_response: ");Serial.println(status_response);// 使用find跳过HTTP响应头if (client.find("\r\n\r\n")) {Serial.println("Found Header End. Start Parsing.");}// 利用ArduinoJson库解析心知天气响应信息parseInfo(client); } else {Serial.println(" connection failed!");}   //断开客户端与服务器连接工作client.stop(); 
}// 连接WiFi
void connectWiFi(){WiFi.begin(ssid, password);                  // 启动网络连接Serial.print("Connecting to ");              // 串口监视器输出网络连接信息Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值}                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。// 这个读秒是通过变量i每隔一秒自加1来实现的。                                              Serial.println("");                          // WiFi连接成功后Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
}// 利用ArduinoJson库解析心知天气响应信息
void parseInfo(WiFiClient client){const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;DynamicJsonDocument doc(capacity);deserializeJson(doc, client);JsonObject results_0 = doc["results"][0];JsonObject results_0_now = results_0["now"];const char* results_0_now_text = results_0_now["text"]; // "Sunny"const char* results_0_now_code = results_0_now["code"]; // "0"const char* results_0_now_temperature = results_0_now["temperature"]; // "32"const char* results_0_last_update = results_0["last_update"]; // "2020-06-02T14:40:00+08:00" // 通过串口监视器显示以上信息String results_0_now_text_str = results_0_now["text"].as<String>(); int results_0_now_code_int = results_0_now["code"].as<int>(); int results_0_now_temperature_int = results_0_now["temperature"].as<int>(); String results_0_last_update_str = results_0["last_update"].as<String>();   Serial.println(F("======Weahter Now======="));Serial.print(F("Weather Now: "));Serial.print(results_0_now_text_str);Serial.print(F(" "));Serial.println(results_0_now_code_int);Serial.print(F("Temperature: "));Serial.println(results_0_now_temperature_int);Serial.print(F("Last Update: "));Serial.println(results_0_last_update_str);Serial.println(F("========================"));
}

可以看出,温度22度,多云,以及数据最后更新的时间。

2.2、获取天气预报信息

获取天气预报信息包括:温度,天气,降水概率,风力,风向,湿度

此实例获取三天后的预报信息。

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>const char* ssid     = "快去摸鱼";       const char* password = "12345678aqz";         const char* host = "api.seniverse.com";   // 将要连接的服务器地址  
const int httpPort = 80;              // 将要连接的服务器端口      // 心知天气HTTP请求所需信息
String reqUserKey = "S-xxxxxx";   // 私钥
String reqLocation = "Nanchang";            // 城市
String reqUnit = "c";                      // 摄氏/华氏void setup(){Serial.begin(9600);          Serial.println("");// 连接WiFiconnectWiFi();
}void loop(){// 建立心知天气API当前天气请求资源地址String reqRes = "/v3/weather/daily.json?key=" + reqUserKey ++ "&location=" + reqLocation + "&language=en&unit=" +reqUnit + "&start=0&days=3";// 向心知天气服务器服务器请求信息并对信息进行解析httpRequest(reqRes);delay(3000);
}// 向心知天气服务器服务器请求信息并对信息进行解析
void httpRequest(String reqRes){WiFiClient client;// 建立http请求信息String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n";Serial.println(""); Serial.print("Connecting to "); Serial.print(host);// 尝试连接服务器if (client.connect(host, 80)){Serial.println(" Success!");// 向服务器发送http请求信息client.print(httpRequest);Serial.println("Sending request: ");Serial.println(httpRequest);  // 获取并显示服务器响应状态行 String status_response = client.readStringUntil('\n');Serial.print("status_response: ");Serial.println(status_response);// 使用find跳过HTTP响应头if (client.find("\r\n\r\n")) {Serial.println("Found Header End. Start Parsing.");}// 利用ArduinoJson库解析心知天气响应信息parseInfo(client); }else {Serial.println(" connection failed!");}   //断开客户端与服务器连接工作client.stop(); 
}// 连接WiFi
void connectWiFi(){WiFi.begin(ssid, password);                  // 启动网络连接Serial.print("Connecting to ");              // 串口监视器输出网络连接信息Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值}                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。// 这个读秒是通过变量i每隔一秒自加1来实现的。                                              Serial.println("");                          // WiFi连接成功后Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
}// 利用ArduinoJson库解析心知天气响应信息
void parseInfo(WiFiClient client){const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 3*JSON_OBJECT_SIZE(14) + 860;DynamicJsonDocument doc(capacity);deserializeJson(doc, client);JsonObject results_0 = doc["results"][0];JsonArray results_0_daily = results_0["daily"];JsonObject results_0_daily_0 = results_0_daily[0];const char* results_0_daily_0_date = results_0_daily_0["date"]; const char* results_0_daily_0_text_day = results_0_daily_0["text_day"]; const char* results_0_daily_0_code_day = results_0_daily_0["code_day"];const char* results_0_daily_0_text_night = results_0_daily_0["text_night"]; const char* results_0_daily_0_code_night = results_0_daily_0["code_night"]; const char* results_0_daily_0_high = results_0_daily_0["high"];const char* results_0_daily_0_low = results_0_daily_0["low"]; const char* results_0_daily_0_rainfall = results_0_daily_0["rainfall"];const char* results_0_daily_0_precip = results_0_daily_0["precip"]; const char* results_0_daily_0_wind_direction = results_0_daily_0["wind_direction"]; const char* results_0_daily_0_wind_direction_degree = results_0_daily_0["wind_direction_degree"];const char* results_0_daily_0_wind_speed = results_0_daily_0["wind_speed"];const char* results_0_daily_0_wind_scale = results_0_daily_0["wind_scale"];const char* results_0_daily_0_humidity = results_0_daily_0["humidity"];JsonObject results_0_daily_1 = results_0_daily[1];const char* results_0_daily_1_date = results_0_daily_1["date"];const char* results_0_daily_1_text_day = results_0_daily_1["text_day"];const char* results_0_daily_1_code_day = results_0_daily_1["code_day"];const char* results_0_daily_1_text_night = results_0_daily_1["text_night"]; const char* results_0_daily_1_code_night = results_0_daily_1["code_night"]; const char* results_0_daily_1_high = results_0_daily_1["high"];const char* results_0_daily_1_low = results_0_daily_1["low"]; const char* results_0_daily_1_rainfall = results_0_daily_1["rainfall"]; const char* results_0_daily_1_precip = results_0_daily_1["precip"]; const char* results_0_daily_1_wind_direction = results_0_daily_1["wind_direction"];const char* results_0_daily_1_wind_direction_degree = results_0_daily_1["wind_direction_degree"]; const char* results_0_daily_1_wind_speed = results_0_daily_1["wind_speed"];const char* results_0_daily_1_wind_scale = results_0_daily_1["wind_scale"];const char* results_0_daily_1_humidity = results_0_daily_1["humidity"]; JsonObject results_0_daily_2 = results_0_daily[2];const char* results_0_daily_2_date = results_0_daily_2["date"];const char* results_0_daily_2_text_day = results_0_daily_2["text_day"];const char* results_0_daily_2_code_day = results_0_daily_2["code_day"];const char* results_0_daily_2_text_night = results_0_daily_2["text_night"];const char* results_0_daily_2_code_night = results_0_daily_2["code_night"];const char* results_0_daily_2_high = results_0_daily_2["high"]; const char* results_0_daily_2_low = results_0_daily_2["low"]; const char* results_0_daily_2_rainfall = results_0_daily_2["rainfall"];const char* results_0_daily_2_precip = results_0_daily_2["precip"]; const char* results_0_daily_2_wind_direction = results_0_daily_2["wind_direction"]; const char* results_0_daily_2_wind_direction_degree = results_0_daily_2["wind_direction_degree"]; const char* results_0_daily_2_wind_speed = results_0_daily_2["wind_speed"];const char* results_0_daily_2_wind_scale = results_0_daily_2["wind_scale"]; const char* results_0_daily_2_humidity = results_0_daily_2["humidity"]; const char* results_0_last_update = results_0["last_update"]; // 从以上信息中摘选几个通过串口监视器显示String results_0_daily_0_date_str = results_0_daily_0["date"].as<String>();String  results_0_daily_0_text_day_str = results_0_daily_0["text_day"].as<String>(); int results_0_daily_0_code_day_int = results_0_daily_0["code_day"].as<int>(); String results_0_daily_0_text_night_str = results_0_daily_0["text_night"].as<String>(); int results_0_daily_0_code_night_int = results_0_daily_0["code_night"].as<int>(); int results_0_daily_0_high_int = results_0_daily_0["high"].as<int>();int results_0_daily_0_low_int = results_0_daily_0["low"].as<int>();String results_0_last_update_str = results_0["last_update"].as<String>();Serial.println(F("======Today Weahter ======="));Serial.print(F("DATE: "));Serial.println(results_0_daily_0_date_str);Serial.print(F("Day Weather: "));Serial.print(results_0_daily_0_text_day_str);Serial.print(F(" "));Serial.println(results_0_daily_0_code_day_int);Serial.print(F("Night Weather: "));Serial.print(results_0_daily_0_text_night_str);Serial.print(F(" "));Serial.println(results_0_daily_0_code_night_int);Serial.print(F("High: "));Serial.println(results_0_daily_0_high_int);Serial.print(F("LOW: "));Serial.println(results_0_daily_0_low_int);Serial.print(F("Last Update: "));Serial.println(results_0_last_update_str);Serial.println(F("=============================="));
}

七、WiFiManager库使用说明

在我们开发物联网项目时,经常需要为ESP8266设置WiFi。在之前中,我们的设置WiFi的方法是通过修改程序中的内容来实现的。

但是假如我们做好了物联网制作后送给朋友,而朋友不知道如何写ESP8266程序.这种情况下该如何来让不懂编程的朋友也能设置ESP8266的WiFi连接呢?

我们可以利用一款非常好用的ESP8266第三方库:WiFiManager库。

1、WiFi配置流程

2、WiFi配置示例程序

ESP8266的WiFi设置是储存在它的闪存系统中的。因此在启动ESP8266并连接WiFi时,它都会尝试使用闪存系统中储存的信息来进行WiFi连接。

在开始讲解如何使用WiFiManager库来配置ESP8266的WiFi设置前,我们需要首先清除ESP8266的WiFi连接信息,这样才能看到WiFiManager库的工作效果。(如果ESP8266刚一启动就自动成功连接WiFi了,那么WiFiManager库是不会发挥作用的。)

使用wifiManager.resetSettings()来实现清除ESP8266的闪存中所存储的WiFi连接信息这一操作。

wifiManager.autoConnect("AutoConnectAP"):使用WiFiManager来实现WiFi网络配置。

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> // 测试HTTP请求用的URL。注意网址前面必须添加"http://"
#define URL "http://www.example.com"void setup() {//初始化串口设置Serial.begin(9600);// 建立WiFiManager对象WiFiManager wifiManager;// 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称wifiManager.autoConnect("快去摸鱼", "12345678aqz");Serial.print("WiFi Connected!");httpClientRequest();  
}void loop() {}// 发送HTTP请求并且将服务器响应通过串口输出
void httpClientRequest(){//重点1 创建 HTTPClient 对象HTTPClient httpClient;WiFiClient wifiClient;//重点2 通过begin函数配置请求地址。此处也可以不使用端口号和PATH而单纯的httpClient.begin(wifiClient, URL); Serial.print("URL: "); Serial.println(URL);//重点3 通过GET函数启动连接并发送HTTP请求int httpCode = httpClient.GET();Serial.print("Send GET request to URL: ");Serial.println(URL);//重点4. 如果服务器响应HTTP_CODE_OK(200)则从服务器获取响应体信息并通过串口输出//如果服务器不响应HTTP_CODE_OK(200)则将服务器响应状态码通过串口输出if (httpCode == HTTP_CODE_OK) {// 使用getString函数获取服务器响应体内容String responsePayload = httpClient.getString();Serial.println("Server Response Payload: ");Serial.println(responsePayload);} else {Serial.println("Server Respose Code:");Serial.println(httpCode);}//重点5. 关闭ESP8266与服务器连接httpClient.end();
}

八、Ticker库使用说明

ESP8266在运行过程中,只能一条线式的依次执行任务。但是我们在开发物联网项目时,可能需要ESP8266在执行某一任务的过程中,还能处理其它任务。比如,我们使用ESP8266来控制电机运行的同时,还需要定时检查某一个引脚上连接按钮有没有被用户按下。

利用Ticker库,我们可以让ESP8266定时调用某一个函数。通过以下示例程序我们可以看到,ESP8266将会每隔一秒钟通过串口监视器输出一次信息。我们是通过语句ticker.attach(1, sayHi)来实现这一操作的

#include <Ticker.h>Ticker ticker;// 建立Ticker用于实现定时功能
int count;    // 计数用变量void setup() {Serial.begin(9600);pinMode(LED_BUILTIN, OUTPUT);// 每隔一秒钟调用sayHi函数一次,attach函数的第一个参数// 是控制定时间隔的变量。该参数的单位为秒。第二个参数是// 定时执行的函数名称。ticker.attach(1, sayHi);
}void loop() {// 用LED呼吸灯效果来演示在Tinker对象控制下,ESP8266可以定时// 执行其它任务for (int fadeValue = 0 ; fadeValue <= 1023; fadeValue += 5) {analogWrite(LED_BUILTIN, fadeValue);delay(10);}for (int fadeValue = 1023 ; fadeValue >= 0; fadeValue -= 5) {analogWrite(LED_BUILTIN, fadeValue);delay(10);}delay(3000);
}// 在Tinker对象控制下,此函数将会定时执行。
void sayHi(){count++;Serial.print("Hi ");Serial.println(count);
}

停止定时执行函数:ticker.detach()将会让ticker对象停止调用函数

向定时调用函数传递参数:ticker.attach(1, sayHi, 8)有3个参数。其中第三个参数就是向定时调用的sayHi函数所传递的参数。

注:attach函数所能传递的参数最多只有一个。另外该参数仅能是以下类型中的一种:char, short, int, float, void*, char*。

九、OTA 操作说明

所谓OTA,就是Over-The-Air的缩写。有人将其翻译为“空中下载”,也有翻译为“隔空传输”。无论如何翻译,对于ESP2866来说,通过OTA我们无需将ESP8266与电脑连接,而仅仅通过WiFi就可以用Arduino IDE向ESP8266上传程序。

#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <Ticker.h>// 闪烁时间间隔(秒)
const int blinkInterval = 2; // 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "快去摸鱼";
const char* password = "12345678aqz";Ticker ticker;void setup() {Serial.begin(9600);            Serial.println("");pinMode(LED_BUILTIN, OUTPUT);ticker.attach(blinkInterval, tickerCount);  // 设置Ticker对象connectWifi();// OTA设置并启动ArduinoOTA.setHostname("ESP8266");ArduinoOTA.setPassword("12345678");ArduinoOTA.begin();Serial.println("OTA ready");
}
void loop() {ArduinoOTA.handle();
}// 在Tinker对象控制下,此函数将会定时执行。
void tickerCount(){digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}void connectWifi(){//开始连接wifiWiFi.begin(ssid, password);//等待WiFi连接,连接成功打印IPwhile (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.print(".");}Serial.println("");Serial.println("WiFi Connected!");  Serial.print("IP address:\t");            Serial.println(WiFi.localIP());          
}

OTA的局限性:

1. 程序占用空间变大
在OTA上传新程序过程中, ESP8266开发板将会保持旧程序的运行。这将导致ESP8266开发板的程序占用空间翻倍。假如您的程序非常复杂,占用空间很大,那么使用OTA上传就不太适合了。

2. Arduino IDE无法通过OTA端口与开发板进行串口通讯
当Arduino IDE的上传端口选为“网络端口”,Arduino IDE将无法获取ESP8266的串口通讯数据。不过ESP8266的串口通讯并不会因为OTA功能而受到影响。换句话说,您可以使用其它电脑串口通讯软件,如Putty等,来实现ESP8266与电脑之间的串口通讯。

3.使用OTA上传程序的电脑与ESP8266必须连接同一WiFi
若要使用OTA上传功能,那么电脑和ESP8266必须要在同一WiFi中,否则是无法实现OTA上传的。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图片无损放大工具Topaz Gigapixel AI v7.4.4 绿色版

Topaz A.I. Gigapixel是这款功能齐全的图象无损变大运用&#xff0c;应用可将智能机拍摄的图象也可以有着专业相机的高质量大尺寸作用。你可以完美地放大你的小照片并大规模打印&#xff0c;它根本不会粘贴。它具有清晰的效果和完美的品质。 借助AIGigapixel&#xff0c;您可以…

SD-WAN企业组网的应用场景

SD-WAN&#xff08;软件定义广域网&#xff09;能够实现企业不同站点之间的高效互联&#xff0c;确保分支机构、总部、数据中心以及云平台等站点的顺畅通信。本文将探讨从企业的WAN业务需求出发&#xff0c;可以将SD-WAN的组网场景分为哪几类。 SD-WAN的典型组网场景 企业站点之…

Java使用dom4j生成kml(xml)文件遇到No such namespace prefix: xxx is in scope on:问题解决

介绍addAttribute和addNamepsace: addAttribute 方法 addAttribute 方法用于给XML元素添加属性。属性&#xff08;Attributes&#xff09;是元素的修饰符&#xff0c;提供了关于元素的额外信息&#xff0c;并且位于元素的开始标签中。属性通常用于指定元素的行为或样式&#…

【华为HCIP实战课程十七】OSPF的4类及5类LSA详解,网络工程师

一、5类LSA详解 由ASBR产生,描述到AS外部的路由,通告到所有的区域(除了STUB区域和NSSA区域)。 我们在R6设备配置引入直连路由,R6的lo10 属于区域2 interface LoopBack10 ip address 6.6.6.6 255.255.255.255 ospf enable 1 area 0.0.0.2 [R6-ospf-1]import-route dire…

Java | Leetcode Java题解之第502题IPO

题目&#xff1a; 题解&#xff1a; class Solution {public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) {int n profits.length;int curr 0;int[][] arr new int[n][2];for (int i 0; i < n; i) {arr[i][0] capital[i];arr[i][1] profi…

深度学习——线性神经网络(五、图像分类数据集——Fashion-MNIST数据集)

目录 5.1 读取数据集5.2 读取小批量5.3 整合所有组件 MNIST数据集是图像分类中广泛使用的数据集之一&#xff0c;但是作为基准数据集过于简单&#xff0c;在本小节将使用类似但更复杂的Fashion-MNIST数据集。 import torch import torchvision from torch.utils import data fr…

2024软考网络工程师笔记 - 第10章.组网技术

文章目录 交换机基础1️⃣交换机分类2️⃣其他分类方式3️⃣级联和堆叠4️⃣堆叠优劣势5️⃣交换机性能参数 &#x1f551;路由器基础1️⃣路由器接口2️⃣交换机路由器管理方式2️⃣交换机路由器管理方式 交换机基础 1️⃣交换机分类 1.根据交换方式分 存储转发式交换(Store…

Hadoop 踩坑汇总

文章目录 一、完整教程二、解决问题问题①&#xff1a; DataNode 没有问题②&#xff1a; 网页打不开 三、大功告成&#xff01;&#xff01; 一、完整教程 这个教程比较详细&#xff0c;博主是按照这个来执行的 https://blog.csdn.net/qq_47831505/article/details/123806514…

保姆级VsCode配置C++编译环境

文章目录 一、下载安装VSCODE二、 安装C拓展三、下载配置MinGW-w64四、下载配置CMake五、 配置vscode中的 json文件六、 谨记 在现代开发中&#xff0c;VSCode以其轻量、强大的扩展生态圈&#xff0c;逐渐成为了众多开发者的首选编辑器&#xff0c;尤其是在C开发环境中&#xf…

全光网络架构

目前组网架构 世界上有一种最快的速度又是光&#xff0c;以前传统以太网络规划满足不了现在的需求。 有线网 无线网 全光网络方案 场景 全光网络分类 以太全光网络 PON&#xff08;Pas-sive-Optical Network 无源光网络&#xff09; 再典型的中大型高校网络中 推荐万兆入…

MySQL程序特别酷

这一篇和上一篇有重合的内容&#xff0c;&#xff0c;我决定从头开始再学一下MySQL&#xff0c;和上一篇的区别是写的更细了&#xff0c;以及写这篇的时候Linux已经学完了 下面就是关于MySQL很多程序的介绍&#xff1a; MySQL安装完成通常会包含如下程序&#xff1a; Linux系…

ArcGIS002:软件自定义设置

摘要&#xff1a;本文详细介绍安装arcgis10.2后软件自定义设置内容&#xff0c;包括工具条的启用、扩展模块的启用、如何加载项管理器、快捷键设置、样式管理器的使用以及软件常规设置。 一、工具条的启用 依次点击菜单栏【自定义】->【工具条】&#xff0c;根据工作需求勾…

基于neo4j的医疗图谱问答与展示

找不到好的毕业设计题材&#xff1f;或者对人工智能领域感兴趣却不知道如何下手&#xff1f;这里给大家推荐一款基于Neo4j的医疗图谱问答系统项目&#xff0c;绝对是毕业设计的不二选择。 这个项目依托于医疗领域的知识图谱&#xff0c;为用户提供交流问答系统。它不仅具有知识…

吃透高并发模型与RPC框架,拿下大厂offer!!!

在当前的互联网市场环境下&#xff0c;竞争愈发激烈&#xff0c;内卷现象严重。在这种背景下&#xff0c;「高并发模型和RPC框架已经成为了大型企业面试的重要环节」。你是否曾因为无法回答相关技术问题而感到尴尬&#xff1f;例如&#xff0c;Java岗位的面试中会询问NIO和Reac…

使用JUC包的AtomicXxxFieldUpdater实现更新的原子性

写在前面 本文一起来看下使用JUC包的AtomicXxxxFieldUpdater实现更新的原子性。代码位置如下&#xff1a; 当前有针对int&#xff0c;long&#xff0c;ref三种类型的支持。如果你需要其他类型的支持的话&#xff0c;也可以照葫芦画瓢。 1&#xff1a;例子 1.1&#xff1a;普…

Java项目-基于springboot框架的学习选课系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

MATLAB图像重心计算

图像重心&#xff08;或质心&#xff09;计算是计算机视觉和图像处理领域 应用领域广泛&#xff1a;包括医疗,生物&#xff0c;动画&#xff0c;机器人等。 该文章通过灰度转换->二值化->质心计算 以下是代码中涉及的一些数学概念和公式&#xff1a; 灰度转换&#xff1a…

力扣困难题汇总(14道)

题4&#xff08;困难&#xff09;&#xff1a; 思路&#xff1a; 找两数组中位数&#xff0c;这个看起来简单&#xff0c;顺手反应就是数第(mn)/2个&#xff0c;这个难在要求时间复杂度为log(mn)&#xff0c;所以不能这样搞&#xff0c;我的思路是&#xff1a;每次切割长度为较…

Systemd:简介

1号进程 Systemd是linux系统的守护进程&#xff0c;它要管理正在运行的 Linux 主机的许多方面&#xff0c;包括挂载文件系统、管理硬件、处理定时器以及启动和管理生产性主机所需的系统服务。 $ ps -u -p 1 USER PID %CPU %MEM VSZ RSS TTY STAT START TI…

R语言机器学习算法实战系列(九)决策树分类算法 (Decision Trees Classifier)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型模型的决策树预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模…