了解JSON JSON(JavaScript Object Notation),即JS对象简谱 , 是一种轻量级的数据交换格式。 实现客户端与服务器之间的数据交换,以前通用的数据交换语言是XML,但是Douglas crockford觉得xml的生成和解析都太麻烦,所以他提出了一种简化格式,也就是json。 相对而言,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
JSON对象格式 举个栗子!试着用不同的语言描述一本书(对象):书名+内容,能够看出JSON在轻量级这块的优势。
用JSON做什么 JSON既然是简化格式,那我们想能不能通过某种办法把JSON字符串变成程序里相应定义的对象、实现对数据方便地操作呢?或者我们想把程序里相应定义的对象的信息变成JSON字符串展示给别人看呢?下面引入JSON解析的概念。
序列化:将程序中的对象快速的转换为 JSON格式的字符串。 反序列化:将JSON格式的字符串, 转换为程序中的对象。
解析JSON格式信息是一个较为繁琐的工作,因此我们将借助解析Arduino – ESP8266平台中解析JSON格式信息的第三方库——ArduionJson库。该库是目前最受好评的解析JSON信息第三方库。其基本信息如下:
作者:BENOIT BLANCHON 官网:https://arduinojson.org/ GitHub: https://github.com/bblanchon/ArduinoJson
点进去后如下,使用示例很简单:
JSON解析示例-1:单一对象JSON解析 以下示例为如何使用ESP8266配合ArduinoJson库来解析只有一个对象的简单JSON信息,该信息如下:
1 2 3 4 { "name" : "taichi-maker" , "number" : 1 }
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 /********************************************************************** 项目名称/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/ ***********************************************************************/ 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<String>(); int numberInt = doc["number" ].as<int>(); // 通过串口监视器输出解析后的数据信息 Serial.print ("nameStr = " );Serial.println(nameStr); Serial.print ("numberInt = " );Serial.println(numberInt); } void loop () {}
语句讲解 重点1:
1 2 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信息内容如下所示:
1 2 3 4 { "name" : "taichi-maker" , "number" : 1 }
我们可以看到,以上JSON信息中包含一个对象,该对象含有两个数据。因此在计算DynamicJsonDocument对象占用空间大小时,使用了JSON_OBJECT_SIZE(2)这条指令。其中指令括号中的2即代表对象包含有两个数据。
再看一个例子,假设我们即将解析的JSON如下:
1 2 3 4 5 { "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:
1 String json = "{\"name\":\"taichi-maker\",\"number\":1}" ;
这条语句的作用是建立字符串变量,该变量用于存储需要解析的JSON信息。
重点3:
1 deserializeJson(doc, json);
这部分语句的作用是使用deserializeJson来对JSON文件进行解析。其中第一个参数是我们重点1讲解的DynamicJsonDocument对象,第二个参数是重点2讲解的json字符串。
重点4:
1 2 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数组信息。该信息如下:
1 2 3 4 5 6 7 8 [ { "name" : "taichi-maker" }, { "website" : "www.taichi-maker.com" } ]
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 /********************************************************************** 项目名称/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/ ***********************************************************************/ 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>(); String websiteStr = doc[1]["website" ].as<String>(); // 通过串口监视器输出解析后的数据信息 Serial.print ("nameStr = " );Serial.println(nameStr); Serial.print ("websiteStr = " );Serial.println(websiteStr); } void loop () {}
语句讲解 重点1:
1 DynamicJsonDocument doc(capacity);
与以上示例相同,这里我们建立了DynamicJsonDocument对象,该对象名称为doc。doc对象的capacity参数用于设置解析JSON所需要的内存大小。这个空间大小是由语句const size_t capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(1) + 60;计算出来的。在这里我们同样回顾一下需要解析的JSON信息内容:
1 2 3 4 5 6 7 8 [ { "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
1 2 String json = "[{\"name\":\"taichi-maker\"},{\"website\":\"www.taichi-maker.com\"}]" ; 这条语句的作用是建立字符串变量,该变量用于存储需要解析的JSON信息。
重点3:
1 deserializeJson(doc, json);
这部分语句的作用是使用deserializeJson来对JSON文件进行解析。其中第一个参数是我们重点1讲解的DynamicJsonDocument对象,第二个参数是重点2讲解的json字符串。
JSON解析示例-3:使用ArduinoJson官网在线工具解析JSON信息 ArduinoJson官网提供了在线工具可帮助我们自动生成JSON解析代码。该工具网址如下:https://arduinojson.org/v6/assistant/
如需了解如何使用ArduinoJson官网在线工具来自动生成解析代码,请参考《零基础入门学用物联网教程》的基础知识篇中3-4 ESP8266-NodeMCU网络客户端部分 的视频教程讲解。
以下是借助ArduinoJson官网在线工具生成的JSON解析代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 /********************************************************************** 项目名称/Project : 零基础入门学用物联网 程序名称/Program name : arduinojson_3_assistant_demo 团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com) 作者/Author : CYNO朔 日期/Date(YYYYMMDD) : 20200514 程序目的/Purpose : 本实例用于演示如何使用ArduinoJson Assistant在线工具生成JSON解析代码。 步骤详解: 1. 使用Serial.begin指令启动串口通讯(此操作用于通过串口监视器检查解析结果) 2. 将需要解析的JSON数据文件复制粘贴到ArduinoJson Assistant在线工具 https://arduinojson.org/v6/assistant/ 3. 将Parsing代码复制粘贴到IDE中 4. 从Parsing代码中找到需要解析的数据所对应的const char* 5. 利用as函数需要解析的数据const char*转换为需要的格式 6. 为了代码精简,可删除无需解析的数据所对应的parsing代码部分 此代码解析的JSON: { "results" : [ { "location" : { "name" : "Beijing" , "country" : "CN" }, "now" : { "text" : "Clear" , "code" : "1" , "temperature" : "3" }, "last_update" : "2020-03-01T20:10:00+08:00" } ] } ***********************************************************************/ void setup () { Serial.begin(9600); const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(3) + 130; DynamicJsonDocument doc(capacity); const char* json = "{\"results\":[{\"location\":{\"name\":\"Beijing\",\"country\":\"CN\"},\"now\":{\"text\":\"Clear\",\"code\":\"1\",\"temperature\":\"3\"},\"last_update\":\"2020-03-01T20:10:00+08:00\"}]}" ; deserializeJson(doc, json); JsonObject results_0 = doc["results" ][0]; const char* results_0_location_name = results_0["location" ]["name" ]; // "Beijing" const char* results_0_location_country = results_0["location" ]["country" ]; // "CN" JsonObject results_0_now = results_0["now" ]; const char* results_0_now_text = results_0_now["text" ]; // "Clear" const char* results_0_now_code = results_0_now["code" ]; // "1" const char* results_0_now_temperature = results_0_now["temperature" ]; // "3" const char* results_0_last_update = results_0["last_update" ]; // "2020-03-01T20:10:00+08:00" String location_name_String = results_0["location" ]["name" ].as<String>(); int now_temperature_int = results_0_now["temperature" ].as<int>(); Serial.println(location_name_String); Serial.println(now_temperature_int); } void loop () { }
JSON解析示例-4:ESP8266闪存存储的JSON解析 我们在开发物联网项目时,可能需要ESP8266解析比较大型的JSON信息。如果这些大型JSON信息存储再程序中,将会占用大量系统动态内存,严重的甚至会出现系统控制程序空间不足问题。因此,我们需要将大型JSON文件存储在ESP8266的闪存系统中。以下示例程序演示如何使用ESP8266读取并且解析存储在闪存中的JSON。
在测试以下示例程序前,请首先将以下zip文件下载并且解压缩。解压缩后将会得到一个JSON文件,该文件含有ESP8266连接WiFi的信息。根据自己的WiFi环境进行相应调整再将文件上传到ESP8266的闪存根目录下。
ESP8266 WiFi 配置 Json 这个链接需要右键另存为; 下面的链接可以直接点击下载:ESP8266 WiFi 配置 Json
接下来将以下示例程序上传给ESP8266。程序上传后,ESP8266将会尝试从SPIFFS闪存文件系统中读取连接WiFi所需要的JSON文件,并且对该文件进行解析然后将解析后的WiFi连接信息应用于程序中,从而实现ESP8266的联网操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 /********************************************************************** 项目名称/Project : 零基础入门学用物联网 程序名称/Program name : arduinojson_spiffs_parse 团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com) 作者/Author : CYNO朔 日期/Date(YYYYMMDD) : 20200303 程序目的/Purpose : 演示如何利用arduinojson库分析SPIFFS系统中的config.json文件内容。 在测试以下示例程序前,请首先将以下zip文件下载并且解压缩。 解压缩后您将会得到一个JSON文件,该文件含有ESP8266连接WiFi的信息。 请根据您的WiFi环境进行相应调整再将文件上传到ESP8266的闪存根目录下。 http://www.taichi-maker.com/wp-content/uploads/2020/04/config.zip ESP8266将会尝试从SPIFFS闪存文件系统中读取连接WiFi所需要的JSON文件, 并且对该文件进行解析然后将解析后的WiFi连接信息应用于程序中,从而实现ESP8266的联网操作。 如果您不清楚如何实现这一操作,请参考《零基础入门学用物联网》教程的ESP8266 NodeMCU 闪存文件系统(SPIFFS)</a>部分。 http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/spiffs/ ***********************************************************************/ // 建立ESP8266WiFiMulti对象 ESP8266WiFiMulti wifiMulti; void setup (){ Serial.begin(9600); Serial.println("" ); // 启动闪存文件系统 if (SPIFFS.begin()){ Serial.println("SPIFFS Started." ); } else { Serial.println("SPIFFS Failed to Start." ); } // 建立DynamicJsonDocument对象 const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 60; DynamicJsonDocument doc(capacity); // 从闪存文件系统中读取即将解析的json文件 File file = SPIFFS.open("/config.json" , "r" ); // 反序列化数据 deserializeJson(doc, file); // 获取解析后的数据信息 const char* wifi_ssid = doc["wifi" ]["ssid" ]; // "taichimaker" const char* wifi_password = doc["wifi" ]["password" ]; // "12345678" // 尝试联网 wifiMulti.addAP(wifi_ssid, wifi_password); wifiMulti.addAP("ssid_from_AP_2" , "your_password_for_AP_2" ); wifiMulti.addAP("ssid_from_AP_3" , "your_password_for_AP_3" ); 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 (){}