ESP8266学习笔记(7)——JSON接口使用
一、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.h 和 jsontree.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.c 中 wifi_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.c 中 switch 参数设置为例。
/******************************************************************************* 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.c 中 wifi_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接口使用相关推荐
- ESP8266学习笔记(1)——搭建环境、编译烧写(NONOS SDK)
RTOS SDK环境搭建参看 ESP8266学习笔记(17)--搭建环境.编译烧写(RTOS SDK) 一.搭建环境 1.1 ESP8266 SDK 入门指南 官网下载:https://www.esp ...
- esp8266舵机驱动_arduino开发ESP8266学习笔记四—–舵机
arduino开发ESP8266学习笔记四-–舵机 使用时发现会有ESP8266掉电的情况,应该是板上的稳压芯片的限流导致的,观测波形,发现当舵机运转时,电源线3.3V不再是稳定的3.3V,大概是在3 ...
- ESP8266学习笔记:实现ESP8266的局域网内通信
ESP8266学习笔记:实现ESP8266的局域网内通信 现在就以实例入手.工程使用的是IOT_DEMO,据DEMO文档可以知道ESP8266初始工作模式为softAP+station共存的模式.于是 ...
- PhalAPI学习笔记 ——— 第二章接口服务请求
PhalAPI学习笔记 --- 第二章接口服务请求 前言 接口服务请求 接口服务请求案例 自定义接口路由 开启匹配路由 配置路由规则 nginx apache 服务请求 结束语 前言 公司业务需要转学 ...
- esp8266 蓝牙耳机_走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二)...
走进物联网智能家居-手把手带你制作wifi智能开关-ESP8266学习笔记(二) 2020-05-09 13:44:11 9点赞 72收藏 6评论 小编注:此篇文章来自即可瓜分10万金币,周边好礼达标 ...
- ESP8266学习笔记6:ESP8266规范wifi连接操作
一.前言 我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分.方便自己和他人.可点此查看,欢迎交流. 之前在笔记4<ESP8266的SmartC ...
- 学习笔记二:接口与继承(内部类)
学习笔记参考来源 java学习路线-推荐链接:java-接口与继承-内部类 学习笔记难免出错 望多指正!!! 什么是内部类呢? 什么是内部类?定义很简单 内部类就是定义在另一个类中的类 内部类的分类 ...
- ESP8266学习笔记5:ESP8266接入yeelink
我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分,方便自己和他人.可点此查看,欢迎交流. 搞定了SmartConfig,前头也用cURL玩过了yee ...
- ESP8266学习笔记7:保存和读取自定义参数
我整理了从2015年至今关于ESP8266的学习笔记,梳理出来了开发环境.基础功能.进阶学习三大部分,方便自己和他人.可点此查看,欢迎交流. 前言 这几天正在使用ESP8266接入机智云,需要保存一些 ...
- ESP8266学习笔记(11)——SNTP接口使用
一.SNTP简介 简单网络时间协议(Simple Network Time Protocol),由 NTP 改编而来,主要用来同步因特网中的计算机时钟 二.SNTP接口 SNTP 接口位于 ESP82 ...
最新文章
- 新技术、新思维开创公共安全管理新模式
- 【Netty】ChannelHandler和ChannelPipeline
- mysql数据库开启慢查询日志
- 从网页(WEB)登录SAP
- leetcode 850. Rectangle Area II | 850. 矩形面积 II(递归分割未重叠矩形)
- C/C++数组指针和指针数组
- php 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别
- java中vector容器,vector向量容器(常用的使用方法总结)
- hive入ES5.6.8
- cpu,内存和disk使用报警脚本
- weixintong ent.php,多商户版微信商城对接微信公众号的方法及设置
- hfs文件服务器打开显示空白,解决Adobe Creative Cloud打开界面一直显示空白的方法...
- jenkins配置Windows节点
- python创建对象_python对象
- 【PLY】Lex和Yacc简单示例
- 计算机思维导图药剂学,思维导图在药剂学教学中的应用
- 对路径“C:\Program Files (x86)\gwssi\CPC客户端\CheckWord.xml”的访问被拒绝。
- sql语句中表格缩写命名_数据库表字段命名规范
- 平板电脑刷机加供电系统改造
- docker容器下mysql主从配置
热门文章
- 给MDK5/KEIL5安装51/ARM编译坏境
- plsql连接mysql教程_plsql直连数据库教程
- goeasy服务器发送(发布)消息,python服务端使用GoEasy实现websocket消息推送
- 相机存储卡格式化了数据能恢复吗,相机储存卡数据误删如何恢复
- 零基础做一个微信答题小程序(一)
- CARNIVAL包的介绍(根据生信技能树Jimmy老师分享的R包资料整理)
- 手机图案密码(3*3点阵)开锁次数 C++
- gsp计算机软件管理,药品进销存管理系统(含GSP管理)
- 【转】haar特征简单分析
- 超全的Linux基础知识思维导图(1)