JSON(JavaScript Object Notation) 是一种通用的轻量级数据交换文本格式。它很容易让人阅读和编写,也便于机器进行解析和生成。它使用JavaScript语法来存储和描述数据对象,但是JSON完全独立于JavaScript。JSON可适用于多种流行编程语言。这些特性使JSON成为理想的数据交换格式。
JSON数据以“名”“值”对呈现。数据“名”“值”由冒号分隔。JSON数据的书写格式是:
“JSON数据名”:JSON数据值
JSON数据举例:
“Year”: 2016
“URL”:”www.taichi-maker.com”
"info": [
{
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
},
{
"year": 2020,
"month": 12,
"day": 30
}
]
"info": {
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
}
JSON对象在大括号{}中书写,对象可以包含单个或者多个JSON数据。
对象(object) 是一个无序的数据集合(“‘名/值’对”集合)。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名/值’ 对”之间使用“,”(逗号)分隔。
以下是含有单个数据的JSON对象示例:
{
"name" : "taichi-maker"
}
以下是含有多个数据的JSON对象示例。该对象由两个JSON数据组成。
{
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
}
多个数据的JSON对象示例该对象包含两个JSON数据。而每一个JSON数据又包含一个JSON对象。
{
"info": {
"name": "taichi-maker",
"website": "www.taichi-maker.com"
},
"date": {
"year": 2020,
"month": 12,
"day": 30
}
}
注意:对象不能直接存放对象,以下示例是错误的。
{ { "name": "taichi-maker", "website": "www.taichi-maker.com" }, { "year": 2020, "month": 12, "day": 30 } }
注意:对象也不能直接存放数组,以下示例是错误的。
{ "info": { "name": "taichi-maker", "website": "www.taichi-maker.com" }, [ { "temperature" : 15 } ] }
数组可包含一个或者多个对象。以下是包含单个对象的数组示例:
[
{
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
}
]
以下是包含多个对象的数组示例:
[
{
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
},
{
"year": 2020,
"month": 12,
"day": 30
}
]
数组也可以包含单个或多个数组,如下所示:
[
[
{
"name" : "taichi-maker",
"website" : "www.taichi-maker.com"
},
{
"year": 2020,
"month": 12,
"day": 30
}
],
[
{
"temperature" : 15,
}
]
]
注意:数组不能直接存放JSON数据。以下示例是错误的。
[
"date": "2020-02-02",
"weekday": "THU"
]
{
"results": [
{
"location": {
"name": "Beijing",
"country": "CN"
},
"now": {
"text": "Clear",
"code": "1",
"temperature": "3"
},
"last_update": "2020-03-01T20:10:00+08:00"
}
]
}
JSON文件乍一看很复杂,但只要注意以下几点就可以分析出JSON数据内容。
首先注意以下符号的含义:
:用于分隔数据的“名”和“值”
{} 标注对象内容
[]标注数组内容
,分隔数据、对象和数组
另外注意:
对象用于存放数据(名值对)。
对象不能直接存放对象或数组。
数组存放元素有序号(序号起始值0)。
数组不能直接存放数据(名值对)。
官网:https://arduinojson.org/
{
"name": "taichi-maker",
"number": 1
}
/**********************************************************************
项目名称/Project : 零基础入门学用物联网
程序名称/Program name : arduinojosn_1_object
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 20200424
程序目的/Purpose :
此程序用于演示如何使用arduinojson库解析以下json信息。该json包含一个对象,
对象中有一个数据。
{
"name": "taichi-maker",
"number": 1
}
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/
#include
void setup() {
Serial.begin(9600);
Serial.println("");
// 重点1:DynamicJsonDocument对象
const size_t capacity = JSON_OBJECT_SIZE(2) + 30;
DynamicJsonDocument doc(capacity);
// 重点2:即将解析的json文件
String json = "{\"name\":\"taichi-maker\",\"number\":1}";
// 重点3:反序列化数据
deserializeJson(doc, json);
// 重点4:获取解析后的数据信息
String nameStr = doc["name"].as();
int numberInt = doc["number"].as();
// 通过串口监视器输出解析后的数据信息
Serial.print("nameStr = ");Serial.println(nameStr);
Serial.print("numberInt = ");Serial.println(numberInt);
}
void loop() {}
语句讲解
重点1:
const size_t capacity = JSON_OBJECT_SIZE(2) + 30;
DynamicJsonDocument doc(capacity);
这里我们建立了DynamicJsonDocument对象,该对象名称为doc。在建立该对象时需要提供一个参数,也就是括号中的参数capacity。这个capacity参数的作用是告诉ESP8266我们所建立的DynamicJsonDocument对象将要占用多大的内存空间。这个空间大小是由语句const size_t capacity = JSON_OBJECT_SIZE(2) + 30;
计算出来的。在这里我们回顾一下需要解析的JSON信息内容如下所示:{ "name": "taichi-maker", "number": 1 }
我们可以看到,以上JSON信息中包含一个对象,该对象含有两个数据。因此在计算DynamicJsonDocument对象占用空间大小时,使用了JSON_OBJECT_SIZE(2)这条指令。其中指令括号中的2即代表对象包含有两个数据。
我们再看一个例子,假设我们即将解析的JSON如下:
{ "name": "taichi-maker", "url": "www.taichi-maker.com", "number": 1 }
以上JSON对象中包含有3个数据。在计算解析它所需要占用的内存大小时,我们将要使用语句:
const size_t capacity = JSON_OBJECT_SIZE(3) + 60;
讲到这里可能细心的朋友已经发现了,在以上语句中除了JSON_OBJECT_SIZE指令以外还使用+ 60来额外增加数值。这些额外增加的数值是由于ArduinoJson库在解析信息时,需要额外的空间来复制JSON信息。但是具体这个额外增加的数值是多少呢,请您先把这个问题留在心里,后面我们会给您做讲解。
重点2:
String json = "{\"name\":\"taichi-maker\",\"number\":1}";
这条语句的作用是建立字符串变量,改变里用于存储需要解析的JSON信息。重点3:
deserializeJson(doc, json);
这部分语句的作用是使用deserializeJson来对JSON文件进行解析。其中第一个参数是我们重点1讲解的DynamicJsonDocument对象,第二个参数是重点2讲解的json字符串。重点4:
String nameStr = doc["name"].as();
int numberInt = doc["number"].as();这两条语句用于获取解析后的JSON信息,其中
doc["name"].as
将会返回“name”的值。这条语句中.as将会让“name”的值以字符串的形式返回。另一条语句中
doc["number"].as()
自然就是以整数形式来返回”number”的数据值。
以下示例演示了如何使用ArduinoJson库解析一个JSON数组信息。该信息如下:
[
{
"name": "taichi-maker"
},
{
"website": "www.taichi-maker.com"
}
]
以下是示例程序内容
/**********************************************************************
项目名称/Project : 零基础入门学用物联网
程序名称/Program name : arduinojosn_2_array
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 20200424
程序目的/Purpose :
此程序用于演示如何使用arduinojson库解析以下json信息,该json包含一个数组,
数组有两个元素,每个元素都是一个对象,每一个对象都有一个数据。
[
{
"name": "taichi-maker"
},
{
"website": "www.taichi-maker.com"
}
]
-----------------------------------------------------------------------
本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/
***********************************************************************/
#include
void setup() {
Serial.begin(9600);
// 重点1:DynamicJsonDocument对象
const size_t capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(1) + 60;
DynamicJsonDocument doc(capacity);
// 重点2:即将解析的json文件
String json = "[{\"name\":\"taichi-maker\"},{\"website\":\"www.taichi-maker.com\"}]";
// 重点3:反序列化数据
deserializeJson(doc, json);
String nameStr = doc[0]["name"].as();
String websiteStr = doc[1]["website"].as();
// 通过串口监视器输出解析后的数据信息
Serial.print("nameStr = ");Serial.println(nameStr);
Serial.print("websiteStr = ");Serial.println(websiteStr);
}
void loop() {}
语句讲解
重点1:
DynamicJsonDocument doc(capacity);
与以上示例相同,这里我们建立了DynamicJsonDocument对象,该对象名称为doc。doc对象的capacity参数用于设置解析JSON所需要的内存大小。这个空间大小是由语句const size_t capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(1) + 60;
计算出来的。在这里我们同样回顾一下需要解析的JSON信息内容:[ { "name": "taichi-maker" }, { "website": "www.taichi-maker.com" } ]
我们可以看到,以上JSON信息是一个数组,该数组含有两个元素。因此,我们在计算capacity时首先使用了语句
JSON_ARRAY_SIZE(2)
来获得含有两个元素的数组所占用内存的大小。另外,这两个数组元素都是含有一个数据的对象。因此,我们在计算capacity时使用了语句
2*JSON_OBJECT_SIZE(1)
。其中JSON_OBJECT_SIZE(1)
可以获得含有一个数据的对象大小,我们将它乘以2是因为这里有两个含有一个数据的对象。在计算capacity的时候,我们还在计算的最后增加60。这么做是由于ArduinoJson库在解析信息时,需要额外的空间来复制JSON信息。
计算capacity可以使用ArduinoJson官网的在线工具。您可以点击这里打开该工具页面。如您需要了解该工具的具体使用方法,欢迎您收看太极创客团队制作的《零基础入门学用物联网》教程,您可以点击这里打开具体介绍该工具使用方法的教程页面。
重点2
String json = "[{\"name\":\"taichi-maker\"},{\"website\":\"www.taichi-maker.com\"}]";
这条语句的作用是建立字符串变量,改变里用于存储需要解析的JSON信息。重点3:
deserializeJson(doc, json);
这部分语句的作用是使用deserializeJson来对JSON文件进行解析。其中第一个参数是我们重点1讲解的DynamicJsonDocument对象,第二个参数是重点2讲解的json字符串。
ESP8266客户端请求JSON信息
ESP8266客户端请求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 : cgj_server_1
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 2020305
程序目的/Purpose :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端。
本程序为服务器程序,功能如下:
1. 实时读取A0、 D1、D2以及D3引脚的读数。
2. 当有客户端请求信息时,将会通过http响应将引脚读数等信息发送给客户端。
信息发送格式为json格式。
3. 本程序使用了wifi.config对开发板的IP进行了配置。
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
20200511 CYNO朔 001 1 移除handleNotFound使教程代码更加精简
2 改请求路径为update
***********************************************************************/
#include // 本程序使用 ESP8266WiFi库
#include // ESP8266WiFiMulti库
#include // 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("taichi-maker1", "12345678"); // 这三条语句通过调用函数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那么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\": \"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;
}
客户端程序的主要功能:
1. 向服务器端请求json数据信息
2. 解析服务器端响应的json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用服务器端D3引脚(按键引脚)读数来控制客户端开发板上LED的点亮和熄灭
/**********************************************************************
项目名称/Project : 零基础入门学用物联网
程序名称/Program name : cgj_client_1
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 20200228
程序目的/Purpose :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端。
本程序为客户端程序,功能如下:
1. 通过http协议向服务器端请求json数据信息
2. 解析服务器端响应的json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用服务器端D3引脚(按键引脚)读数来控制客户端开发板上LED的点亮和熄灭
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
20200302 CYNO朔 001 添加arduinojson解析错误识别
20200511 CYNO朔 002 改请求路径为update
20200511 CYNO朔 003 parse过程使用函数完成
***********************************************************************/
#include
#include
#include
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("ssid_from_AP_1", "your_password_for_AP_1"); // 将需要连接的一系列WiFi ID和密码输入这里
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的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();
bool d3_bool = digital_pin["d3"].as();
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点亮和熄灭。
{
"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 : cgj_server_1
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 2020305
程序目的/Purpose :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端。
本程序为服务器程序,功能如下:
1. 实时读取A0、 D1、D2以及D3引脚的读数。
2. 当有客户端请求信息时,将会通过http响应将引脚读数等信息发送给客户端。
信息发送格式为json格式。
3. 本程序使用了wifi.config对开发板的IP进行了配置。
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
20200511 CYNO朔 001 1 移除handleNotFound使教程代码更加精简
2 改请求路径为update
***********************************************************************/
#include // 本程序使用 ESP8266WiFi库
#include // ESP8266WiFiMulti库
#include // 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("taichi-maker1", "12345678"); // 这三条语句通过调用函数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那么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\": \"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;
}
客户端程序的主要功能:
1. 向服务器端请求json数据信息
2. 解析服务器端响应的json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用服务器端D3引脚(按键引脚)读数来控制客户端开发板上LED的点亮和熄灭
/**********************************************************************
项目名称/Project : 零基础入门学用物联网
程序名称/Program name : cgj_client_1
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : CYNO朔
日期/Date(YYYYMMDD) : 20200228
程序目的/Purpose :
本实例用于演示esp8266的json数据通讯。
操作测试本程序需要使用两台8266开发板。其中一台为服务器端,一台为客户端。
本程序为客户端程序,功能如下:
1. 通过http协议向服务器端请求json数据信息
2. 解析服务器端响应的json信息内容。
3. 将解析后的数据信息显示于串口监视器
4. 利用服务器端D3引脚(按键引脚)读数来控制客户端开发板上LED的点亮和熄灭
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
20200302 CYNO朔 001 添加arduinojson解析错误识别
20200511 CYNO朔 002 改请求路径为update
20200511 CYNO朔 003 parse过程使用函数完成
***********************************************************************/
#include
#include
#include
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("ssid_from_AP_1", "your_password_for_AP_1"); // 将需要连接的一系列WiFi ID和密码输入这里
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的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();
bool d3_bool = digital_pin["d3"].as();
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);
}