摘要:我们将设备采集到的数据上传到云平台一般有两种主流的方式:二进制码流和json,本章用于讲解在LiteOS仓库中集成的cJson库,用于将需要上报的数据封装为json格式或者将云平台下发的json格式数据解析出来。
一、华为云平台需要的json数据格式
当我们下位机使用mqtt协议来进行通讯并且mcu的ram和flash也比较充裕,我们就可以采用json格式来和云平台进行数据交互。
首先在定义产品的时候协议类型选择MQTT和数据格式选择JSON:
大家可以查看下这个帮助手册,主要说明了华为云平台要求的JSON数据格式的要求,JSON数据格式分为设备命令、设备消息和设备属性,我这里主要说的是设备属性和设备命令:设备属性上报、设备命令下发。
services:类型为list(array),存放设备服务数据
service_id:类型为string,与我们产品中的服务相对应Agriculture
properties:类型为object,存放设备服务的属性,例如Temperature、Humidity等,和属性名称及值对应,在产品中定义的,如下图。
云平台收到的数据必须与我们在产品中定义的数据格式相同,必选的属性必须存在,否则该数据会被丢弃,如果收到的数据正确我们就可以在“设备”页面中看到如下显示:
二、cJSON库简介
到这里大家应该明白了为什么今天我们需要讲解cJson库了,cJson库的作用是什么了。
cJSON库是一个基于MIT的代码,项目仓库地址:https://github.com/DaveGamble/cJSON,我们在LiteOS中主要用到其中的两个文件:cJSON.h和cJSON.c。
该库可以十分方便的将我们的数据结构体,例如:
转换为json格式的,甚至还能直接以非格式化字符的形式打印出来,就是这样的:
,极大的提高了我们处理数据的效率,还能将json格式的数据转换为便于处理的键、值等等。
三、cJson库中封装相关函数详解
这里就以上面的Agriculture的上报属性数据的结构体为例,带领大家将它转换为JSON格式的数据。
几个重要概念
Object和Item:Object和Item是相对的,不是绝对的,这句话有些抽象,我来举个例子向大家说明,例如之前我的定义的json数据:
1、 ①到⑩之间的所有数据可以称为一个Object,②到⑩之间的数据就是它的键为”services”,类型为array的item。
2、 ②到⑩之间的所有数据可以称为一个Object,其中③处的键值对是它的第一个键为“service_id”,类型为string的item,其中④到⑨处的键值对是它的第二个键为“properties”,类型为Object的item。
3、 ④到⑧之间的所有数据可以称为一个Object,其中⑤⑥⑦都是分别是该Object的三个item,他们的类型都是int。
嵌套:嵌套的意思大家只要理解了上面我说的Object和Item的概念就算理解了。Object中嵌套了Object,那这个被嵌套的Object就是Item。
cJSON结构体
该结构体的声明在cJSON.h文件中,大家可以自行查看。
next和prev指针:通过cJSON结构体定义的变量可以实现一个链表,在进行增、删、查、改时通过next和prev指针来完成。
child指针:当我们需要添加一个item到某个Object的时候(嵌套),就将这个item指针挂接到该节点的child成员上。
type变量:用于标记该item的类型,例如string、number、bool、array、object等。
valuestring指针:用于当item类型为string类型时,指向值所对应的字符串。
valueint变量:用于当item类型为number类型时,存储值对应的int类型数据。
Valuedouble变量:用于当item类型为number类型时,存储值对应的double类型数据。
string指针:指向该item键的对应的名称。
当该item为bool类型,其中的值为false或者true时,该值存储于type变量处。
绑定系统特有的内存分配及释放函数
因为在创建object和删除object时需要使用到内存,所以在初始化cJSON库时,我们就需要将系统中进行内存分配及释放的函数注册到cJSON库中。
例如裸机开发时,用malloc分配内存,用free释放内存。
例如用LiteOS_Lab框架开发时,用osal_malloc分配内存,用osal_free释放内存。
通过如下操作即可完成注册:
Object的创建
我们需要进行json格式数据处理时,首先通过JSON数据类型定义一个JSON数据类型变量指针,并通过cJSON_CreateObject为其分配内存并初始化(如果是array类型的object则调用cJSON_CreateArray,其他类型的创建可以自己类比,创建相关函数见下图)。
向Object中添加item
例如我们要创建如下的一个JSON格式的数据。
首先需要创建两个Object,第一个称为root的Object,后面将键为properties的item挂上去,第二个为properties的Object,用于“温度、湿度、光照”键值对的挂接。
代码部分:
unsigned char* str_js = NULL; //定义一个字符串指针
cJSON* cjson_root = NULL; //定义cJSON类型的指针
cJSON* cjson_properties = NULL;
cjson_root = cJSON_CreateObject(); //为上面的指针分配内存并进行初始化
cjson_properties = cJSON_CreateObject();
//将温度、湿度、光照键值对添加到名为properties的Object中
cJSON_AddNumberToObject(cjson_properties, "Temperature", 20);
cJSON_AddNumberToObject(cjson_properties, "Humidity", 18);
cJSON_AddNumberToObject(cjson_properties, "luminance", 50);
//将名为cjson_data的Object挂接到名为cjson_root的Object上
cJSON_AddItemToObject(cjson_root, "properties", cjson_properties);
//将cJSON转换为非格式化字符串打印一下
str_json = cJSON_Print(cjson_root);
printf("Data is %s\r\n", str_json);
//用完之后一定要记得释放
cJSON_Delete(cjson_root);
if(str_json!=NULL)
osal_free(str_json);
效果图如下:
PS:关于指令的解析放在下一篇来说!