JSON( JSON基础,ESP8266 JSON解析)ESP8266通过JSON实现物联网数据通讯( ESP8266客户端请求JSON信息, ESP8266客户端发送JSON信息)

JSON

JSON基础

JSON(JavaScript Object Notation) 是一种通用的轻量级数据交换文本格式。它很容易让人阅读和编写,也便于机器进行解析和生成。它使用JavaScript语法来存储和描述数据对象,但是JSON完全独立于JavaScript。JSON可适用于多种流行编程语言。这些特性使JSON成为理想的数据交换格式。

  • 数据以“名”“值”对呈现
  • 数据“名”和“值”之间由冒号分隔
  • 大括号{}用于标注对象内容
  • 中括号[]用于标注数组内容
  • 逗号用于分隔数据、对象、数组

JSON数据

JSON数据以“名”“值”对呈现。数据“名”“值”由冒号分隔。JSON数据的书写格式是:

“JSON数据名”:JSON数据值

JSON数据举例:

“Year”: 2016
“URL”:”www.taichi-maker.com”

JSON数组数据示例
"info": [
    {
        "name" : "taichi-maker",
        "website" : "www.taichi-maker.com"
    },
    {
        "year": 2020,
        "month": 12,
        "day": 30
    }
]
JSON对象数据示例
"info": {
    "name" : "taichi-maker",
    "website" : "www.taichi-maker.com"
}

JSON 对象

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
	}
  ]
}

 JSON 数组

数组可包含一个或者多个对象。以下是包含单个对象的数组示例:

[
    {
        "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"
]

JSON 对象与数组混合存放示例

{
  "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)。
数组不能直接存放数据(名值对)。

ESP8266 JSON解析

官网:https://arduinojson.org/

JSON解析示例-1:单一对象JSON解析

{
  "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”的数据值。

 JSON解析示例-2:JSON数组解析

以下示例演示了如何使用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信息

JSON( JSON基础,ESP8266 JSON解析)ESP8266通过JSON实现物联网数据通讯( ESP8266客户端请求JSON信息, ESP8266客户端发送JSON信息)_第1张图片

 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点亮和熄灭。

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);
}

你可能感兴趣的:(json,物联网,esp8266,嵌入式硬件)