目录
一、接入点模式
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正在尝试连接WiFi
int i = 0;
while (wifiMulti.run() != WL_CONNECTED) { // 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
delay(1000); // 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
Serial.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那么NodeMCU
Serial.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引脚为输出模式以便控制LED
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那么NodeMCU
Serial.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的IP
esp8266_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 // 按钮引脚D3
ESP8266WiFiMulti 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那么NodeMCU
Serial.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(); // 格式化SPIFFS
Serial.println("SPIFFS format finish");
if(SPIFFS.begin()){ // 启动SPIFFS
Serial.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(); //启动SPIFFS
Serial.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);
//开始连接wifi
WiFi.begin(ssid, password);
//等待WiFi连接,连接成功打印IP
while (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);
//开始连接wifi
WiFi.begin(ssid, password);
//等待WiFi连接,连接成功打印IP
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi Connected!");
wifiClientRequest();
}
void loop(){}
// 向服务器发送HTTP请求
void wifiClientRequest(){
// 建立WiFi客户端对象,对象名称client
WiFiClient 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": "[email protected]"
},
"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 // 按钮引脚D3
ESP8266WiFiMulti 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那么NodeMCU
Serial.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\": \"[email protected]\"},\"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"]; // "[email protected]"
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("");
// 连接WiFi
connectWiFi();
}
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("");
// 连接WiFi
connectWiFi();
}
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(){
//开始连接wifi
WiFi.begin(ssid, password);
//等待WiFi连接,连接成功打印IP
while (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上传的。