一、JSON简介

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。

1.1 JSON 语法规则

在 JS 语言中,一切都是对象。 因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:

● 对象表示为键值对
● 数据由逗号分隔
● 花括号保存对象
● 方括号保存数组

1.2 JSON 键/值对

JSON 键值对是用来保存 JS 对象的一种方式,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:

{"firstName": "Json"}

二、JSON接口

JSON 接口位于 ESP8266_NONOS_SDK/include/json/jsonparse.hjsontree.h

2.1 相关宏定义

// json.h
#define JSON_TYPE_ARRAY '['    // 数组类型
#define JSON_TYPE_OBJECT '{'   // 对象类型
#define JSON_TYPE_PAIR ':'     // 键值对类型
#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */
#define JSON_TYPE_STRING '"'
#define JSON_TYPE_INT 'I'
#define JSON_TYPE_NUMBER '0'
#define JSON_TYPE_ERROR 0#define JSON_TYPE_CALLBACK 'C'  // 回调类型
// jsontree.h
/*------------------------- 生成一个JSON键值对 -------------------------*/
// 第一个参数是键名,第二个参数是键值
#define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)}/*------------------------- 生成一个回调指针 -------------------------*/
// 第一个参数JSON输出回调,第二个JSON输入回调,哪个没有就填NULL
#define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)}/*------------------------- 生成一个JSON树的对象 -------------------------*/
// JSONTREE_OBJECT(name, ...) 第一个参数是该对象的名称
#define JSONTREE_OBJECT(name, ...)                                      \static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__};   \static struct jsontree_object name = {                                \JSON_TYPE_OBJECT,                          \sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair),          \jsontree_pair_##name }/*------------------------- 生成一个JSON键值对数组 -------------------------*/
#define JSONTREE_PAIR_ARRAY(value) (struct jsontree_value *)(value)
/*------------------------- 生成一个JSON数组 -------------------------*/
#define JSONTREE_ARRAY(name, ...)                                      \static struct jsontree_value* jsontree_value_##name[] = {__VA_ARGS__};   \static struct jsontree_array name = {                                \JSON_TYPE_ARRAY,                          \sizeof(jsontree_value_##name)/sizeof(struct jsontree_value*),          \jsontree_value_##name }

2.2 接口函数








三、生成JSON数据

3.1 字符串类型数据

以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.cwifi_station 参数设置为例。
JSON树结构图:

/******************************************************************************* FunctionName : wifi_station_get* Description  : set up the station paramer as a JSON format* Parameters   : js_ctx -- A pointer to a JSON set up* Returns      : result
*******************************************************************************/
LOCAL int ICACHE_FLASH_ATTR
wifi_station_get(struct jsontree_context *js_ctx)
{const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1);  // 获取JSON树参数struct ip_info ipconfig;                                           // 定义一个IP信息结构体uint8 buf[20];os_bzero(buf, sizeof(buf));                                        // 清空数组wifi_station_get_config(sta_conf);                                 // 查询Wi-Fi Station接口的当前配置参数wifi_get_ip_info(STATION_IF, &ipconfig);                           // 查询Wi-Fi Station接口的IP地址if (os_strncmp(path, "ssid", 4) == 0) {                            // 搜索到有"ssid"这个字符串jsontree_write_string(js_ctx, sta_conf->ssid);                 // 将Station接口中ssid这个参数的字符串写入JSON树} else if (os_strncmp(path, "password", 8) == 0) {                 // 以下操作同上......jsontree_write_string(js_ctx, sta_conf->password);} else if (os_strncmp(path, "ip", 2) == 0) {os_sprintf(buf, IPSTR, IP2STR(&ipconfig.ip));jsontree_write_string(js_ctx, buf);} else if (os_strncmp(path, "mask", 4) == 0) {os_sprintf(buf, IPSTR, IP2STR(&ipconfig.netmask));jsontree_write_string(js_ctx, buf);} else if (os_strncmp(path, "gw", 2) == 0) {os_sprintf(buf, IPSTR, IP2STR(&ipconfig.gw));jsontree_write_string(js_ctx, buf);}return 0;
}LOCAL struct jsontree_callback wifi_station_callback =JSONTREE_CALLBACK(wifi_station_get, wifi_station_set);
// 第一个回调函数用于生成JSON数据格式,第二个回调函数用于解析JSON格式数据(本部分不列出)JSONTREE_OBJECT(get_station_config_tree,JSONTREE_PAIR("ssid", &wifi_station_callback),JSONTREE_PAIR("password", &wifi_station_callback));
JSONTREE_OBJECT(ip_tree,JSONTREE_PAIR("ip", &wifi_station_callback),JSONTREE_PAIR("mask", &wifi_station_callback),JSONTREE_PAIR("gw", &wifi_station_callback));JSONTREE_OBJECT(get_station_tree,JSONTREE_PAIR("Connect_Station", &get_station_config_tree),JSONTREE_PAIR("Ipinfo_Station", &ip_tree));JSONTREE_OBJECT(get_wifi_station_info_tree,JSONTREE_PAIR("Station", &get_station_tree));

这里生成的JSON是:

"Station" :
{"Connect_Station" :{"ssid" : "xxxx" ,"password" : "xxxx"} ,"Ipinfo_Station" :{"ip" : "xxxx" ,"mask" : "xxxx" ,"gw" : "xxxx"}
}

"Station" 是用来给后面调用生成Json数据格式的,传输时不存在,即
"Connect_Station" :{"ssid" : "xxxx" ,"password" : "xxxx"} ,"Ipinfo_Station" :{"ip" : "xxxx" ,"mask" : "xxxx" ,"gw" : "xxxx"}

/******************************************************************************* FunctionName : json_send* Description  : processing the data as json format and send to the client or server* Parameters   : arg -- argument to set for client or server*                ParmType -- json format type* Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
json_send(void *arg, ParmType ParmType)
{char *pbuf = NULL;pbuf = (char *)os_zalloc(2048);switch (ParmType) {case WIFI:json_ws_send((struct jsontree_value *)&get_wifi_station_info_tree, "Station", pbuf);break;default :break;}data_send(ptrespconn, true, pbuf);    // TCP发送数据os_free(pbuf);                        // 释放内存pbuf = NULL;
}

这里有个 json_ws_send 函数,就是生成JSON数据格式字符串,然后给data_send函数TCP发送出去

/******************************************************************************* FunctionName : json_ws_send* Description  : set up the JSON format tree for string* Parameters   : tree -- A pointer to the JSON format tree*                path -- A pointer to the JSON format tree's path*                pbuf -- A pointer for the data sent* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
json_ws_send(struct jsontree_value *tree, const char *path, char *pbuf)
{struct jsontree_context json;/* maxsize = 128 bytes */json_buf = (char *)os_malloc(jsonSize);/* reset state and set max-size *//* NOTE: packet will be truncated at 512 bytes */pos = 0;size = jsonSize;json.values[0] = (struct jsontree_value *)tree;jsontree_reset(&json);            // 设置JSON树find_json_path(&json, path);      // 查找JSON格式树路径json.path = json.depth;json.putchar = json_putchar;while (jsontree_print_next(&json) && json.path <= json.depth);  // 不断获取 JSON 树下⼀个元素json_buf[pos] = 0;os_memcpy(pbuf, json_buf, pos);os_free(json_buf);
}

3.2 整型数据

以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.cswitch 参数设置为例。

/******************************************************************************* FunctionName : status_get* Description  : set up the device status as a JSON format* Parameters   : js_ctx -- A pointer to a JSON set up* Returns      : result
*******************************************************************************/
LOCAL int ICACHE_FLASH_ATTR
status_get(struct jsontree_context *js_ctx)
{if (user_plug_get_status() == 1) {    // 获取继电器状态jsontree_write_int(js_ctx, 1);} else {jsontree_write_int(js_ctx, 0);}return 0;
}

生成JSON格式:

"status" :0/1

3.3 数组类型数据

3.3.1 整型数组

LOCAL int ICACHE_FLASH_ATTR
jsonTree_get(struct jsontree_context *js_ctx)
{const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1);//生成"String":"data"if (os_strncmp(path, "String", os_strlen("String")) == 0) {jsontree_write_string(js_ctx, "data");//生成"Integer":1} else if (os_strncmp(path, "Integer", os_strlen("Integer")) == 0) {jsontree_write_int(js_ctx, 1);//生成"Array":[0,1,2]} else if (os_strncmp(path, "Array", os_strlen("Array")) == 0) {int array[3] = {0,1,2};jsontree_write_atom(js_ctx, "[");jsontree_write_int_array(js_ctx, array, 3);jsontree_write_atom(js_ctx, "]");}return 0;
}

生成JSON格式:

"String": "data",
"Integer": 1,
"Array": [0, 1, 2]

3.3.2 字符串数组

LOCAL int ICACHE_FLASH_ATTR
jsonArray_get(struct jsontree_context *js_ctx)
{const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1);if (os_strncmp(path, "K1", os_strlen("K2")) == 0) {jsontree_write_string(js_ctx, "D1");} else if (os_strncmp(path, "K2", os_strlen("K2")) == 0) {jsontree_write_string(js_ctx, "D2");} else if (os_strncmp(path, "K3", os_strlen("K3")) == 0) {jsontree_write_string(js_ctx, "D3");}return 0;
}//初始化一个Json数据回调函数
//JSONTREE_CALLBACK第一个参数为生成Json数据的函数指针,第二个为获取Json数据的函数指针
LOCAL struct jsontree_callback jsonArrayCallback =JSONTREE_CALLBACK(jsonArray_get, NULL);JSONTREE_OBJECT(jsonArrayData,JSONTREE_PAIR("K1", &jsonArrayCallback),JSONTREE_PAIR("K2", &jsonArrayCallback),JSONTREE_PAIR("K3", &jsonArrayCallback));
JSONTREE_ARRAY(jsonArray,JSONTREE_PAIR_ARRAY(&jsonArrayData),JSONTREE_PAIR_ARRAY(&jsonArrayData),JSONTREE_PAIR_ARRAY(&jsonArrayData));LOCAL struct jsontree_callback jsonCallback =JSONTREE_CALLBACK(jsonTree_get, NULL);JSONTREE_OBJECT(jsonObject,JSONTREE_PAIR("String", &jsonCallback),JSONTREE_PAIR("Integer", &jsonCallback),JSONTREE_PAIR("JsonArray", &jsonArray));

生成JSON格式:

"String": "data",
"Integer": 1,
"JsonArray": [
{"K1": "D1","K2": "D2","K3": "D3"
},
{"K1": "D1","K2": "D2","K3": "D3"
},
{"K1": "D1","K2": "D2","K3": "D3"
}
]

四、解析JSON数据

以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.cwifi_station 参数设置为例。

LOCAL void ICACHE_FLASH_ATTR
webserver_recv(void *arg, char *pusrdata, unsigned short length)
{......else if (os_strcmp(pURL_Frame->pFilename, "wifi") == 0) {if (pParseBuffer != NULL) {struct jsontree_context js;...jsontree_setup(&js, (struct jsontree_value *)&wifi_req_tree, json_putchar);  // ⽣成JSON格式数据树json_parse(&js, pParseBuffer);    // 解析JSON格式数据...}}
}

这里有个 json_parse 函数,就是解析JSON格式数据

/******************************************************************************* FunctionName : json_parse* Description  : parse the data as a JSON format* Parameters   : js_ctx -- A pointer to a JSON set up*                ptrJSONMessage -- A pointer to the data* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
json_parse(struct jsontree_context *json, char *ptrJSONMessage)
{/* Set value */struct jsontree_value *v;struct jsontree_callback *c;struct jsontree_callback *c_bak = NULL;while ((v = jsontree_find_next(json, JSON_TYPE_CALLBACK)) != NULL) {  // 查找JSON树元素c = (struct jsontree_callback *)v;if (c == c_bak) {continue;}c_bak = c;if (c->set != NULL) {struct jsonparse_state js;jsonparse_setup(&js, ptrJSONMessage, os_strlen(ptrJSONMessage));  // JSON解析初始化c->set(json, &js);}}
}

JSON树结构图:

/******************************************************************************* FunctionName : wifi_station_set* Description  : parse the station parmer as a JSON format* Parameters   : js_ctx -- A pointer to a JSON set up*                parser -- A pointer to a JSON parser state* Returns      : result
*******************************************************************************/
LOCAL int ICACHE_FLASH_ATTR
wifi_station_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser)
{int type;uint8 station_tree;while ((type = jsonparse_next(parser)) != 0) {  // 解析 JSON 格式下⼀个元素if (type == JSON_TYPE_PAIR_NAME) {char buffer[64];os_bzero(buffer, 64);if (jsonparse_strcmp_value(parser, "Station") == 0) {  // ⽐较解析 JSON 数据与特定字符串station_tree = 1;} else if (jsonparse_strcmp_value(parser, "Softap") == 0) {station_tree = 0;}if (station_tree) {if (jsonparse_strcmp_value(parser, "ssid") == 0) {  // ⽐较解析 JSON 数据与特定字符串jsonparse_next(parser);jsonparse_next(parser);jsonparse_copy_value(parser, buffer, sizeof(buffer));  // 复制当前解析字符串到指定缓存os_memcpy(sta_conf->ssid, buffer, os_strlen(buffer));} else if (jsonparse_strcmp_value(parser, "password") == 0) {jsonparse_next(parser);jsonparse_next(parser);jsonparse_copy_value(parser, buffer, sizeof(buffer));os_memcpy(sta_conf->password, buffer, os_strlen(buffer));}#if ESP_PLATFORMelse if (jsonparse_strcmp_value(parser, "token") == 0) {jsonparse_next(parser);jsonparse_next(parser);jsonparse_copy_value(parser, buffer, sizeof(buffer));                            user_esp_platform_set_token(buffer);}
#endif}}}return 0;
}LOCAL struct jsontree_callback wifi_station_callback =JSONTREE_CALLBACK(wifi_station_get, wifi_station_set);
// 第一个回调函数用于生成JSON数据格式(上一部分已列出),第二个回调函数用于解析JSON格式数据JSONTREE_OBJECT(set_station_config_tree,JSONTREE_PAIR("ssid", &wifi_station_callback),JSONTREE_PAIR("password", &wifi_station_callback),JSONTREE_PAIR("token", &wifi_station_callback));JSONTREE_OBJECT(set_station_tree,JSONTREE_PAIR("Connect_Station", &set_station_config_tree));JSONTREE_OBJECT(set_wifi_tree,JSONTREE_PAIR("Station", &set_station_tree),JSONTREE_PAIR("Softap", &set_softap_tree));JSONTREE_OBJECT(wifi_request_tree,JSONTREE_PAIR("Request", &set_wifi_tree));JSONTREE_OBJECT(wifi_req_tree,JSONTREE_PAIR("wifi", &wifi_request_tree));

这里解析的JSON是:

"wifi" :
{"Request" :{"Station" : {"Connect_Station" : {"ssid" : "xxxx" ,"password" : "xxxx""token" : "xxxx"}}   }
}

• 由 Leung 写于 2018 年 12 月 15 日

• 参考:ESP8266 Non-OS SDK API参考[zj6w]
    【ESP8266】使用ESP8266 NONOS SDK的JSON API

ESP8266学习笔记(7)——JSON接口使用相关推荐

  1. ESP8266学习笔记(1)——搭建环境、编译烧写(NONOS SDK)

    RTOS SDK环境搭建参看 ESP8266学习笔记(17)--搭建环境.编译烧写(RTOS SDK) 一.搭建环境 1.1 ESP8266 SDK 入门指南 官网下载:https://www.esp ...

  2. esp8266舵机驱动_arduino开发ESP8266学习笔记四—–舵机

    arduino开发ESP8266学习笔记四-–舵机 使用时发现会有ESP8266掉电的情况,应该是板上的稳压芯片的限流导致的,观测波形,发现当舵机运转时,电源线3.3V不再是稳定的3.3V,大概是在3 ...

  3. ESP8266学习笔记:实现ESP8266的局域网内通信

    ESP8266学习笔记:实现ESP8266的局域网内通信 现在就以实例入手.工程使用的是IOT_DEMO,据DEMO文档可以知道ESP8266初始工作模式为softAP+station共存的模式.于是 ...

  4. PhalAPI学习笔记 ——— 第二章接口服务请求

    PhalAPI学习笔记 --- 第二章接口服务请求 前言 接口服务请求 接口服务请求案例 自定义接口路由 开启匹配路由 配置路由规则 nginx apache 服务请求 结束语 前言 公司业务需要转学 ...

  5. esp8266 蓝牙耳机_走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二)...

    走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二) 2020-05-09 13:44:11 9点赞 72收藏 6评论 小编注:此篇文章来自即可瓜分10万金币,周边好礼达标 ...

  6. ESP8266学习笔记6:ESP8266规范wifi连接操作

    一.前言 我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分.方便自己和他人.可点此查看,欢迎交流. 之前在笔记4<ESP8266的SmartC ...

  7. 学习笔记二:接口与继承(内部类)

    学习笔记参考来源 java学习路线-推荐链接:java-接口与继承-内部类 学习笔记难免出错 望多指正!!! 什么是内部类呢? 什么是内部类?定义很简单 内部类就是定义在另一个类中的类 内部类的分类 ...

  8. ESP8266学习笔记5:ESP8266接入yeelink

    我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分,方便自己和他人.可点此查看,欢迎交流. 搞定了SmartConfig,前头也用cURL玩过了yee ...

  9. ESP8266学习笔记7:保存和读取自定义参数

    我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分,方便自己和他人.可点此查看,欢迎交流. 前言 这几天正在使用ESP8266接入机智云,需要保存一些 ...

  10. ESP8266学习笔记(11)——SNTP接口使用

    一.SNTP简介 简单网络时间协议(Simple Network Time Protocol),由 NTP 改编而来,主要用来同步因特网中的计算机时钟 二.SNTP接口 SNTP 接口位于 ESP82 ...

最新文章

  1. 新技术、新思维开创公共安全管理新模式
  2. 【Netty】ChannelHandler和ChannelPipeline
  3. mysql数据库开启慢查询日志
  4. 从网页(WEB)登录SAP
  5. leetcode 850. Rectangle Area II | 850. 矩形面积 II(递归分割未重叠矩形)
  6. C/C++数组指针和指针数组
  7. php 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别
  8. java中vector容器,vector向量容器(常用的使用方法总结)
  9. hive入ES5.6.8
  10. cpu,内存和disk使用报警脚本
  11. weixintong ent.php,多商户版微信商城对接微信公众号的方法及设置
  12. hfs文件服务器打开显示空白,解决Adobe Creative Cloud打开界面一直显示空白的方法...
  13. jenkins配置Windows节点
  14. python创建对象_python对象
  15. 【PLY】Lex和Yacc简单示例
  16. 计算机思维导图药剂学,思维导图在药剂学教学中的应用
  17. 对路径“C:\Program Files (x86)\gwssi\CPC客户端\CheckWord.xml”的访问被拒绝。
  18. sql语句中表格缩写命名_数据库表字段命名规范
  19. 平板电脑刷机加供电系统改造
  20. docker容器下mysql主从配置

热门文章

  1. 给MDK5/KEIL5安装51/ARM编译坏境
  2. plsql连接mysql教程_plsql直连数据库教程
  3. goeasy服务器发送(发布)消息,python服务端使用GoEasy实现websocket消息推送
  4. 相机存储卡格式化了数据能恢复吗,相机储存卡数据误删如何恢复
  5. 零基础做一个微信答题小程序(一)
  6. CARNIVAL包的介绍(根据生信技能树Jimmy老师分享的R包资料整理)
  7. 手机图案密码(3*3点阵)开锁次数 C++
  8. gsp计算机软件管理,药品进销存管理系统(含GSP管理)
  9. 【转】haar特征简单分析
  10. 超全的Linux基础知识思维导图(1)