视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=18&vd_source=b91967c499b23106586d7aa35af46413

程序链接:http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/esp8266-client-sends-json/


注意,以下示例中的服务器端和客户端ESP8266必须连接同一WiFi网络,方可实现数据通讯。

在学习本节课的内容之前,需要先学习 WiFiServer 库的基本操作。

WiFiServer 库的基本操作

该库的介绍链接: http://www.taichi-maker.com/homepage/iot-development/iot-dev-reference/esp8266-c-plus-plus-reference/wifiserver/

从名称看,这个库将是控制 ESP8266 以服务器的形式来工作的。而在之前的学习中,当让 ESP8266 以服务器的形式来工作时,使用的是 ESP8266WebServer 库。

WiFiServer 库 和 ESP8266WebServer 库之间有什么区别吗?

这两个库从功能上来说,是非常相似的,假如我们让 ESP8266 以服务器的模式来工作,再让服务器获取客户端的请求信息中的详细内容(请求体)时,就必须要使用 WiFiServer 库了。


下面来演示下如何使用程序对 WiFiServer 库进行基本操作,

使用 WiFiServer 库,首先要添加头文件 #include <ESP8266WiFi.h>。

/**********************************************************************
项目名称/Project          : 零基础入门学用物联网
程序名称/Program name     : wifiServer_example
团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author              : CYNO朔
日期/Date(YYYYMMDD)     : 20200521
程序目的/Purpose          :
本实例用于演示如何使用WiFiServer库利用ESP8266开发板建立基本网络服务器。
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/
#include <ESP8266WiFi.h>const char* ssid = "taichimaker";
const char* password = "12345678";WiFiServer server(80);void setup() {Serial.begin(9600);Serial.println();WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(F("."));}// 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地址// 启动服务器server.begin();
}void loop() {runServer();  // 运行服务器
}void runServer(){// 建立WiFiClient对象用于处理客户端请求信息WiFiClient incomingClient = server.available();// 如果没有客户端请求信息,则“跳过”函数中后续程序内容if (!incomingClient) {return;}Serial.println("====Client  Connected===");// 通过串口监视器输出客户端请求信息String clientRequest = incomingClient.readString();Serial.print(clientRequest);// 建立服务器响应信息String httpResponse ="HTTP/1.0 200 OK\r\n""Connection: close\r\n""Content-Type: text/plain;\r\n""\r\n""client_request_received";// 向客户端发送以上服务器响应信息incomingClient.print(httpResponse); incomingClient.stop();  Serial.println("incomingClient stop");
}

在上述程序中,重点是要说明下 runServer(); 这个函数,这个函数的作用是运行服务器。在 runServer 函数中,首先是

 // 建立WiFiClient对象用于处理客户端请求信息WiFiClient incomingClient = server.available();

可能会有疑问,这里不是服务器端的程序吗,为什么要建立一个客户端对象呢?这是因为这段程序虽然是在服务器上运行的,但其主要作用是用来处理客户端的请求信息的。既然是处理客户端的请求信息的,因此就必须建立一个客户端的对象。

此外,在建立对象的右边还有 server.available() ,这部分的操作呢是一旦有客户端连接到服务器上,并且向服务器发送请求信息,我们将利用建立的 incomingClient 对象来处理向服务器发送的请求信息。

接着是

  // 如果没有客户端请求信息,则“跳过”函数中后续程序内容if (!incomingClient) {return;}

这里,为什么可以使用 incomingClient 这个对象来作为判断条件,通常都是使用 bool 类型的变量来作为判断条件的,那这是为什么呢?

对于 ESP8266 平台来说,当有客户端向服务器发送请求信息,对于该信息的处理是以 Stream 数据来处理的,而这个 Stream 数据,它总是要有一个载体的。而这个载体正是 incomingClient 这个对象。当然,incomingClient 作为 WiFiClient 对象,它不光只是一个载体,还会有其他的功能。

这个程序虽然说的是 WiFiServer 库,但是实际上,大量利用的是 WiFiClient 对象,因为 WiFiServer 库和WiFiClient 对象是密不可分的,我们在进行 WiFiServer 库的操作时,会用到很多 WiFiClient 对象中的内容来处理客户端请求信息,并且发送服务器响应信息。

下面来测试下程序,打开串口监视器

再打开浏览器,输入网址,

可见,服务器收到浏览器(客户端)的请求信息(串口中打印的数据)后,做出了响应(client_request_received)。

关于的浏览器图标文件 favicon.ico 的说明

浏览器调用 favicon 的原理是首先在网页所在目录(服务器端)寻找 favicon.ico 文件(这也是上图浏览器出现太极图标的原因,之前上传过文件系统。),如果没有找到就去浏览器的根目录下寻找(一般采用浏览器默认图标)。所以最简单的方法就是将制作好的 favicon 文件命名为favicon.ico然后上传到网站的根目录下。

客户端程序

主要功能:

  1. 实时读取 A0、 D1、D2 以及 D3 引脚的读数。
  2. 向服务器发送 Json 信息。发送的信息中包含有 D3 引脚状态从而控制服务器开发板上的LED点亮或熄灭。

以下为该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"}
}

具体客户端代码如下,

/**********************************************************************
项目名称/Project          : 零基础入门学用物联网
程序名称/Program name     : csj_client_one_json
团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author              : Dapenson
日期/Date(YYYYMMDD)     : 20200425
程序目的/Purpose          :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端本程序为客户端程序,功能如下:
1. 实时读取A0、 D1、D2以及D3引脚的读数。
2. 向服务器发送Json信息。发送的信息中包含有D3引脚状态从而控制服务器开发板上的LED点亮或熄灭
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
20200520      CYNO朔           001        修改httpRequest将两个“/r/n”合并
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/http-request/
***********************************************************************/
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>ESP8266WiFiMulti wifiMulti;           // 建立ESP8266WiFiMulti对象const char* host = "192.168.2.44"; // 网络服务器地址
const int httpPort = 80;            // http端口80void setup(){Serial.begin(9600);          Serial.println("");// 将引脚设置为输入上拉模式pinMode(D1, INPUT_PULLUP);pinMode(D2, INPUT_PULLUP);pinMode(D3, INPUT_PULLUP);   // NodeMCU开发板按键连接在D3(GPIO0)引脚上//通过addAp函数存储  WiFi名称       WiFi密码wifiMulti.addAP("FAST_153C80", "123456798");  // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。wifiMulti.addAP("taichi-maker2", "87654321"); // 这3个WiFi网络名称分别是taichi-maker, taichi-maker2, taichi-maker3。wifiMulti.addAP("taichi-maker3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。// 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。// 另外这里只存储了3个WiFi信息,您可以存储更多的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地址
}void loop(){// 发送HTTP请求httpRequest();    delay(3000);
}// 向服务器发送HTTP请求,请求信息中包含json信息
void httpRequest(){// 建立WiFi客户端对象,对象名称clientWiFiClient client;    // 重点1: 建立JSON,此JSON包含需要发送的信息StaticJsonDocument<384> doc;JsonObject info = doc.createNestedObject("info");info["name"] = "taichimaker";info["url"] = "www.taichi-maker.com";info["email"] = "taichimaker@163.com";JsonObject digital_pin = doc.createNestedObject("digital_pin");digital_pin["d1"] = String(digitalRead(D1));digital_pin["d2"] = String(digitalRead(D2));digital_pin["d3"] = String(digitalRead(D3));doc["analog_pin"]["a0"] = String(analogRead(A0));String payloadJson;serializeJson(doc, payloadJson);// 建立字符串,用于HTTP请求String httpRequest =  String("GET /") + " HTTP/1.1\r\n" +"Host: " + host + "\r\n" +"Connection: close\r\n\r\n" + payloadJson;// 通过串口输出连接服务器名称以便查阅连接服务器的网址                      Serial.print("Connecting to "); Serial.print(host); if (client.connect(host, httpPort)){ Serial.println(" Success!");            // 连接成功后串口输出“Success”信息client.print(httpRequest);              // 向服务器发送请求Serial.println("Sending request: ");    // 通过串口输出HTTP请求信息内容以便查阅Serial.println(httpRequest);     Serial.println("Web Server Response:"); // 通过串口监视输出服务器响应信息        while (client.connected() || client.available()){ if (client.available()){String line = client.readStringUntil('\n');Serial.println(line);}} } else{    // 如果连接不成功则通过串口输出“连接失败”信息Serial.println(" failed!");} client.stop();                      // 断开与服务器的连接Serial.print("Disconnected from "); // 并且通过串口输出断开连接信息Serial.println(host);
}

原网页代码中没有加上LED的初始化设置,pinMode(D3, INPUT_PULLUP); 所以运行结果有问题。

这里还需要注意的是用于 HTTP 请求的信息,

 // 重点1: 建立JSON,此JSON包含需要发送的信息String payloadJson = "{\"info\": {\"name\": \"taichimaker\",\"url\": \"www.taichi-maker.com\",\"email\": \"taichimaker@163.com\"},\"digital_pin\": {\"d1\": \"";payloadJson += String(digitalRead(D1));  payloadJson += "\",\"d2\": \""; payloadJson += String(digitalRead(D2));  payloadJson += "\",\"d3\": \""; payloadJson += String(digitalRead(D3));  payloadJson += "\"},\"analog_pin\": {\"a0\": \"";payloadJson += String(analogRead(A0));payloadJson += "\"}}";

上述代码可以使用前面介绍的自动生成 JSON 代码的网站自动生成。

// 建立字符串,用于HTTP请求String httpRequest =  String("GET /") + " HTTP/1.1\r\n" +"Host: " + host + "\r\n" +"Connection: close\r\n\r\n" + payloadJson;

需要注意,通常 http 请求包含三个部分,分别是请求行、请求头和请求体。这里的

String("GET /") + " HTTP/1.1\r\n" +

是请求行,

"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n" +

是请求头,之后间隔一个空行,所以建立的 JSON 信息 payloadJson 是位于请求体中的内容。

服务器端程序

在掌握了如何使用 WiFiServer 库来获取客户端请求信息后,接下来我们开始学习服务器端示例程序。该程序将会实现以下功能。

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

具体服务器端代码如下,

/**********************************************************************
项目名称/Project          : 零基础入门学用物联网
程序名称/Program name     : csj_server
团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author              : CYNO朔
日期/Date(YYYYMMDD)     : 20200425
程序目的/Purpose          :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端。
本程序为服务器程序,功能如下:1. 获取客户端请求信息中的json。
2. 解析json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用json中客户端D3引脚(按键引脚)读数来控制服务器端开发板上LED的点亮和熄灭
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date    作者/Author      参考号/Ref    修订说明/Revision Description
20200520      CYNO朔           001        修改parseInfo部分,使其与cgj_client_2更加一致
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <ESP8266WiFiMulti.h>   ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是'wifiMulti'IPAddress local_IP(192, 168, 2, 44); // 设置ESP8266-NodeMCU联网后的IP
IPAddress gateway(192, 168, 2, 1);    // 设置网关IP(通常网关IP是WiFI路由IP)
IPAddress subnet(255, 255, 255, 0);   // 设置子网掩码
IPAddress dns(192,168,2,1);           // 设置局域网DNS的IP(通常局域网DNS的IP是WiFI路由IP)// 建立WiFiServerSecure对象
WiFiServer server(80);void setup() {Serial.begin(9600);Serial.println();pinMode(LED_BUILTIN, OUTPUT);digitalWrite(LED_BUILTIN, HIGH);// 设置开发板网络环境if (!WiFi.config(local_IP, gateway, subnet)) {Serial.println("Failed to Config ESP8266 IP"); } //通过addAp函数存储  WiFi名称       WiFi密码wifiMulti.addAP("FAST_153C80", "123456798"); // 这三条语句通过调用函数addAP来记录3个不同的WiFi网络信息。wifiMulti.addAP("taichi-maker2", "87654321"); // 这3个WiFi网络名称分别是taichi-maker, taichi-maker2, taichi-maker3。wifiMulti.addAP("taichi-maker3", "13572468"); // 这3个网络的密码分别是123456789,87654321,13572468。// 此处WiFi信息只是示例,请在使用时将需要连接的WiFi信息填入相应位置。// 另外这里只存储了3个WiFi信息,您可以存储更多的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地址// 启动服务器server.begin();
}void loop() {runServer();  // 运行服务器
}// 运行服务器
void runServer(){// 重点1:建立WiFiClient对象用于处理客户端请求信息WiFiClient incomingClient = server.available();// 如果没有客户端连接服务器,则“跳过”本函数中后续程序内容if (!incomingClient) {return;}Serial.println("====Client  Connected===");// 重点2:如果有客户端连接服务器,则尝试使用find跳过HTTP请求头if (incomingClient.find("\r\n\r\n")) {Serial.println("Found Header End. Start Parsing.");}// 解析请求体中的json信息 parseInfo(incomingClient);// 建立服务器响应信息String httpResponse ="HTTP/1.0 200 OK\r\n""Connection: close\r\n""Content-Type: text/plain;\r\n""\r\n""client_message_received";// 向客户端发送以上服务器响应信息incomingClient.print(httpResponse); incomingClient.stop();  Serial.println("incomingClient stop");
}// 重点3:解析请求体中的json信息
void parseInfo(WiFiClient client){bool d3_bool;          // 建立变量存储客户端开发板按键信息String info_name_str;  // 建立变量存储字符串信息int a0_int; // 建立变量存储客户端开发板模拟输入引脚读数StaticJsonDocument<384> doc;DeserializationError error = deserializeJson(doc, client);if (error) {Serial.print(F("deserializeJson() failed: "));Serial.println(error.f_str());return;}JsonObject info = doc["info"];if(info){Serial.println("Server Json has info: true");info_name_str = info["name"].as<String>(); // "taichimaker"Serial.print("info_name_str = ");Serial.println(info_name_str);}else{Serial.println("Server Json has info: false");}JsonObject digital_pin = doc["digital_pin"];if(digital_pin){Serial.println("Server Json has digital_pin: true");d3_bool = digital_pin["d3"].as<int>(); // "1"d3_bool == 0 ? digitalWrite (LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);Serial.print("d3_bool = ");Serial.println(d3_bool);}else{Serial.println("Server Json has digital_pin: false");}const char* analog_pin_a0 = doc["analog_pin"]["a0"]; // "500"if(analog_pin_a0){Serial.println("Server Json has analog_pin_a0: true");a0_int = doc["analog_pin"]["a0"].as<int>(); Serial.print("a0_int = ");Serial.println(a0_int);}else{Serial.println("Server Json has analog_pin_a0: false");}
}

运行代码后,服务器端运行结果如下,

客户端程序运行结果如下,

后面还有一部分是讲解使用 ESP8266 客户端发送多种 JSON 数据信息的例子,但是大同小异,需要的话再来仔细研究下。

目前,我们使用的是都是局域网实现的,还没有使用互联网来实现,后面的学习将使用互联网实现。

学习太极创客 — ESP8226 (九)JSON 数据通讯 三相关推荐

  1. 学习太极创客 — ESP8226 (八)JSON 数据通讯 二

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=17&vd_source=b91967c499b23106586d7aa35af46413 ...

  2. 学习太极创客 — ESP8226 (七)JSON 数据通讯 一

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=16&vd_source=b91967c499b23106586d7aa35af46413 ...

  3. 学习太极创客 — ESP8226 (十)HTTP API 应用

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=19&vd_source=b91967c499b23106586d7aa35af46413 ...

  4. 学习太极创客 — ESP8226 (四)Stream

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=12&vd_source=b91967c499b23106586d7aa35af46413 ...

  5. 学习太极创客 — ESP8226 (十二)ESP8266 多任务处理

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=22&spm_id_from=333.851.header_right.history_l ...

  6. 学习太极创客 — ESP8226 (十一)用 WiFiManager 库配网

    视频链接:https://www.bilibili.com/video/BV1L7411c7jw?p=21&spm_id_from=333.880.my_history.page.click& ...

  7. 学习太极创客 — ESP8226 (十三)OTA

    视频链接: https://www.bilibili.com/video/BV1L7411c7jw?p=23&vd_source=b91967c499b23106586d7aa35af4641 ...

  8. 学习太极创客 — MQTT(四)服务端连接操作

    视频链接:https://www.bilibili.com/video/BV1T54y1k7MQ/?spm_id_from=trigger_reload&vd_source=b91967c49 ...

  9. 学习太极创客 — MQTT(八)ESP8266订阅MQTT主题

    视频链接:https://www.bilibili.com/video/BV1Wz4y1k7Fs/?spm_id_from=333.788.recommend_more_video.-1&vd ...

最新文章

  1. 面试官:为什么需要 Hystrix?
  2. HTML与CSS基础知识补遗(一)
  3. 领域驱动设计案例:Tiny Library:领域模型
  4. Linux cd后显示文件,关于linux系统显示文件的问题!
  5. 怎么把java程序放进php_如何在php脚本中执行Java程序?
  6. 笑跪!博士写论文解释科学擀面,学霸们每天都在想些啥…
  7. Spring Bean装配(上)
  8. [转载] python 判断字符串是否包含另一个字符串_强烈推荐:Python字符串(string)方法整理(一)...
  9. 徐家骏写给任正非的辞职信
  10. CKeditor与CKfinder的简单配置
  11. android 资源文件
  12. 浅谈三种使用Redis实现MQ的方式
  13. python 安装包的默认路径与更改
  14. spnc币吧_CCIEC币-目前是CPUsolo独自开采。CPU服务器独自开采钱包上挖新币教程!...
  15. Axure RP 8--模板的使用
  16. 微信公众号开发(1)微信公众号简介
  17. 在哪儿比较好下载建筑学西方近现代的外文文献?
  18. Kiwi Syslog日志服务器的安装及配置使用
  19. 名字真好听的五子棋——12周进度
  20. 微信小程序访问豆瓣电影API 403 400

热门文章

  1. CREO图文教程:三维设计案例之一排曲柱(基准点+参照阵列设计)图文教程之详细攻略
  2. python高级数据筛选_python高级编程,列表字典集合相关的数据筛选
  3. Jena Ontology API
  4. 村淘披露年货节数据:北上广领衔买土货 “农民伯伯”爱数码
  5. 淘宝App惊现“内测版本弹屏”P0级事故!5张淘宝架构PPT,剖析事故始末
  6. kindeditor富文本编辑器初步使用教程
  7. games101:作业7+Microfacet微平面理论+cook-torranceBRDF方程计算+作业7拓展
  8. visual basic VB.NET实例系列教程第二节(好玩又有趣的龟兔赛跑程序)
  9. 线性代数之各种各样的矩阵
  10. HTML5 form表单 调查问卷制作(内含超详细代码解读)