OneNet真是中移动的良心之作,对比阿里云和庆科云,OneNet不但免费而且功能也足够嵌入式应用,对学生党而言真是大大的福利,感谢中移动!!!。

一、云端创建设备与应用

(1)创建产品:进入开发者中心有个蓝色框点击就可以创建产品,自己使用的时候,产品信息什么的,自己填完整的就好,这里需要说明的是设备接入方式和设备接入协议,设备接入方式一般选择公开协议,调试之用,没必要自己定义协议,设备接入协议选择有个下拉框可供选择:

在右边框框里有简单介绍协议的基本功能,在这里我选择是EDP协议,可以发送数据和接收命令,能完成基本功能就好。关于这些协议具体介绍在云平台公开协议产品指南里有详细介绍:

(2)注册设备:产品注册成功后会提示是否生成设备,这时候就可以填写自己想要接入设备信息,生成之后是酱紫的:

在产品概况界面是如下显示:

这里有个产品ID和APIKey,这个产品ID和设备ID是不同的,但用这个APIKey可以默认访问产品下的所有设备,其实还可以为每个设备申请APIKey的,在设备管理里,,点击“添加APIKey”就可以为当前设备申请APIKey,下面是我申请设备的完整信息,有了设备ID和APIKey,这是访问该设备的最直接办法。

(3)生成应用:为该设备创建数据流和应用:在数据流模板界面有添加数据流按钮,添加一个名为temp的数据流,再在应用管理界面添加一个名为test的应用,使用一个折线图控件来显示当前temp的值。

注意在右边要为当前折线图选择数据流,才能将应用与设备的数据流绑定。

二、利用EdpProtoDebugger调试工具进行数据传输

接下来,我们就为temp传送数据,官方给出了EdpProtoDebugger调试工具,给出下载链接:https://open.iot.10086.cn/doc/art254.html#68

将之前的设备ID和APIKey填进去,默认消息类型是连接云操作,消息子类型是设备ID和APIKey,表示采用设备ID和APIKey方式来访问云端。

先点击“生成编码”再点击发送到设备云,会有如下16进制数据显示,这些数据是有意义的,在刚才给的下载链接里有相关EDP协议具体介绍

在这里,用调试工具自带的翻译器查看一下接收消息的意思

连接成功,在开发者中心的设备管理里,设备前的类似灯的按钮会亮,表示设备在线。如果五分钟之内没有数据发送与接收,云端服务器会自动断开连接。

接下来是传输数据:消息类型选择SaveData类型,消息子类型就选择数据类型一:JSON格式串,同样的这些协议具体内容都在文档里写清楚,慢慢看就能懂。给个JSON格式串参考:

{"datastreams":  [{"id":   "temp","datapoints":   [{"value":        "25"}]}]
}

将上面的JSON串复制到调试工具的数据文本框中,然后点击生成编码,再点击发送到设备,会在云端应用的折线图看到数据,数据发送接收成功。

再看下云端向设备发送命令,先将调试工具连上云端就什么都不干,静静地等待云端命令就好,然后在云端应用中添加一个旋钮控件来发送命令。

将旋钮与设备test绑定,但没有选择数据流,因为我们是希望云端向设备发送命令,这个就不是设备的数据流了。需要注意的这个EDP命令内容,我在这卡了很久表示不理解这到底是个啥(当然,如果你自己已经看懂了这是什么,这里就跳过),这里先留个疑问,等会在代码调试时再回过头来看会更清楚。

旋转按钮时,会向已连接的调试工具发送消息,在调试工具里有接收到消息,会有相应的16进制数据,用翻译器大致看下就好:

第0字节表示命令请求信息,说明确确实实接收到云端的命令请求,达到我们的期望。

到这里,基本上可以完成设备与OneNet云的连接、发送与接收数据。最后是重点,代码如何实现?

三、代码实现上述功能

也许,有心的同学能发现,其实,OneNet文档中心已经给出了代码实例,在git上已经开源SDK,这里给出链接:https://github.com/cm-heclouds/edp_c

我自己调试的代码也是根据这写些,我自己调试也花了些时间,共享出来,贴出链接,收点劳动积分,共同学习(注意:我是在Linux环境下调试的C代码):http://download.csdn.net/download/kuangzuxiaon/10201344

主要说一下代码框架,怎么实现发送与接收数据的,涉及到简单socket套接字网络编程。

从git上下载到SDK,主要是几个c文件和对应的h文件,包括,cJSON.c、EdpKit.c、Openssl.c和一个简单的应用例程,这个应用例程是有发送和接收数据框架的。

首先说一下这几个文件的大致作用,cJSON.c其实也是一个开源的软件,是ANSI-C标准的JSON解析器,只包含一个.c和.h文件,移植性和效率都是比较好的;Openssl.c同样是一个开源的库,是一个安全套接字层密码库,说简单点就是用于数据加密;所以真正属于OneNET的是EdpKit.c这个文件,这个也是写应用程序参考的最多的一个文件,主要是采用云平台公开协议对数据进行打包和解析的一些函数;SDK会提供一个应用例程Main.c,这个例程主要是采用命令行交互式操作,主要是为了测试EdpKit而写的,也向用户展示了如何使用EdpKit。总体看来,OneNET应用还是比较简单的。

我首先把这个应用例程做了一些修改,主文件重新命名为main.c,源码在上面CSDN的资源页可以下载,首先看下Makefile,默认是不需要数据加密功能的,在Makefile中将编译Openssl的命令屏蔽掉,在main.c中涉及到Openssl的语句都是采用预编译命令包括的。

连接OneNET云平台:主要是利用socket套接字,与基本网络编程思路是一样的:产生套接字->连接服务器->数据传输三个步骤:

int main(int argc, char *argv[])
{int sockfd, ret=0;EdpPacket* send_pkg;  pthread_t id_1;uint8 sys_time=0, temp=0; char strBuf[25];/*1、 创建一个与服务器的socket连接*/sockfd = Open(SERVER_ADDR, SERVER_PORT);if(sockfd < 0){printf("Connect Server Faild ! \n");return -1;}/* create a recv thread */ret=pthread_create(&id_1,NULL,(void *(*) (void *))recv_thread_func, &sockfd);  //创建接收线程/*2、产生并发送EDP设备连接请求的数据包 */send_pkg = PacketConnect1(DEV_ID, API_KEY);  ret = DoSend(sockfd, (char*)send_pkg->_data, send_pkg->_write_pos);        if((!send_pkg) || (ret <= 0))           //连接失败,直接退出{goto faild;} DeleteBuffer(&send_pkg);while(1){ sleep(5); /*3、产生并发送EDP用户数据包 */bzero(strBuf, sizeof(strBuf));sprintf(strBuf, "%d", sys_time++ % 10);ret = write_func(sockfd, "sys_time", strBuf); if (ret < 0){break;}}/*关闭socket连接*/Close(sockfd);/* 关闭接收线程 */pthread_join(id_1,NULL);return 0;faild:printf("DoSend faild ! (%d)\n", __LINE__); DeleteBuffer(&send_pkg); Close(sockfd);pthread_join(id_1,NULL);return -1; }

数据发送过程:这部分是OneNET文档中心给出的例程做的简单修改,

int write_func(int32 socket_fd, char* value_ID, char* val)
{ int32 sockfd = socket_fd;EdpPacket* send_pkg;cJSON *save_json;int32 ret = 0; char send_buf[100];/*产生JSON串,其中携带了要上传的用户数据*/bzero(send_buf, sizeof(send_buf));strcat(send_buf,"{\"datastreams\": [{");// strcat(send_buf,"\"id\": \"sys_time\",");strcat(send_buf,"\"id\": \"");strcat(send_buf, value_ID);strcat(send_buf, "\",");strcat(send_buf,"\"datapoints\": [");strcat(send_buf,"{\"value\": \""); strcat(send_buf, val); strcat(send_buf,"\"}]}]}"); /*将JSON串封装成EDP数据包*/save_json=cJSON_Parse(send_buf);if(NULL == save_json){printf("[%d]Error before: [%s]\n", __LINE__, cJSON_GetErrorPtr());    return -1;}else{ /* 解析JSON格式,用作调试 */  // printf("[%d]cJSON_Print : \n%s\n", __LINE__, cJSON_Print(save_json)); //带格式输出printf("cJSON_Print : %s (%d)\n", cJSON_PrintUnformatted(save_json), __LINE__);    //不带格式输出} send_pkg = PacketSavedataJson(DEV_ID, save_json, kTypeFullJson, 0); if(NULL == send_pkg){return -1;} cJSON_Delete(save_json);      //删除构造的json对象/*发送EDP数据包上传数据*/ret = DoSend(sockfd, (char*)send_pkg->_data, send_pkg->_write_pos);if(ret < 0){printf("DoSend faild ! (%d)\n", __LINE__); // send_pkg = PacketPing();}DeleteBuffer(&send_pkg);return ret;
}

数据接收过程:这一部分是原来SDK的源码,基本上没有修改,只是添加了几个调试语句

/* * 函数名:  recv_thread_func* 功能:    接收线程函数* 参数:    arg     socket描述符* 说明:    这里只是给出了一个从socket接收数据的例子, 其他方式请查询相关socket api*          一般来说, 接收都需要循环接收, 是因为需要接收的字节数 > socket的读缓存区时, 一次recv是接收不完的.* 相关socket api:  *          recv* 返回值:  无*/
void recv_thread_func(void* arg)
{int sockfd = *(int*)arg;int error = 0;int n, rtn;uint8 mtype, jsonorbin;char buffer[4096];RecvBuffer* recv_buf = NewBuffer();EdpPacket* pkg;char* src_devid;char* push_data;uint32 push_datalen;cJSON* save_json;char* save_json_str;cJSON* desc_json;char* desc_json_str;char* save_bin; uint32 save_binlen;unsigned short msg_id;unsigned char save_date_ret;char* cmdid;uint16 cmdid_len;char*  cmd_req;uint32 cmd_req_len;EdpPacket* send_pkg;char* ds_id;double dValue = 0;int iValue = 0;char* cValue = NULL;char* simple_str = NULL;char cmd_resp[] = "ok";unsigned cmd_resp_len = 0;DataTime stTime = {0};FloatDPS* float_data = NULL;int count = 0;int i = 0;struct UpdateInfoList* up_info = NULL;#ifdef _DEBUGprintf("[%s(%d)] recv thread start ...\n", __func__, __LINE__);
#endifwhile (error == 0){/* 试着接收1024个字节的数据 */n = Recv(sockfd, buffer, sizeof(buffer), MSG_NOSIGNAL);if (n <= 0)break;printf("[%d]recv from server, bytes: %d\n", __LINE__, n);/* wululu test print send bytes */hexdump((const unsigned char *)buffer, n);/* 成功接收了n个字节的数据 */WriteBytes(recv_buf, buffer, n);while (1){/* 获取一个完成的EDP包 */if ((pkg = GetEdpPacket(recv_buf)) == 0){printf("[%d]need more bytes...\n", __LINE__);break;}/* 获取这个EDP包的消息类型 */mtype = EdpPacketType(pkg);printf("EdpPacketType is %d \n", mtype);
#ifdef _ENCRYPTif (mtype != ENCRYPTRESP){if (g_is_encrypt){SymmDecrypt(pkg);}}
#endif/* 根据这个EDP包的消息类型, 分别做EDP包解析 */switch(mtype){
#ifdef _ENCRYPTcase ENCRYPTRESP:                                                            //加密请求响应 (client to server)UnpackEncryptResp(pkg);break;
#endifcase CONNRESP:                                                                //连接请求响应 (client to server)/* 解析EDP包 - 连接响应 */rtn = UnpackConnectResp(pkg);printf("[%d]recv connect resp, rtn: %d\n", __LINE__, rtn);break;case PUSHDATA:                                                                //转发(透传)数据 (双向)/* 解析EDP包 - 数据转发 */UnpackPushdata(pkg, &src_devid, &push_data, &push_datalen);printf("recv push data, src_devid: %s, push_data: %s, len: %d\n",src_devid, push_data, push_datalen);free(src_devid);free(push_data);break;case UPDATERESP:                                                            //平台下发当前最新的软件信息 (client to server)UnpackUpdateResp(pkg, &up_info);while (up_info){printf("name = %s\n", up_info->name);printf("version = %s\n", up_info->version);printf("url = %s\nmd5 = ", up_info->url);for (i=0; i<32; ++i){printf("%c", (char)up_info->md5[i]);}printf("\n");up_info = up_info->next;}FreeUpdateInfolist(up_info);break;case SAVEDATA:                                                             //存储(转发)数据 (双向)/* 解析EDP包 - 数据存储 */if (UnpackSavedata(pkg, &src_devid, &jsonorbin) == 0){if (jsonorbin == kTypeFullJson|| jsonorbin == kTypeSimpleJsonWithoutTime|| jsonorbin == kTypeSimpleJsonWithTime){printf("[%d]json type is %d\n", __LINE__, jsonorbin);/* 解析EDP包 - json数据存储 *//* UnpackSavedataJson(pkg, &save_json); *//* save_json_str=cJSON_Print(save_json); *//* printf("recv save data json, src_devid: %s, json: %s\n", *//*     src_devid, save_json_str); *//* free(save_json_str); *//* cJSON_Delete(save_json); *//* UnpackSavedataInt(jsonorbin, pkg, &ds_id, &iValue); *//* printf("ds_id = %s\nvalue= %d\n", ds_id, iValue); */UnpackSavedataDouble(jsonorbin, pkg, &ds_id, &dValue);printf("[%d]ds_id = %s\nvalue = %f\n", __LINE__, ds_id, dValue);/* UnpackSavedataString(jsonorbin, pkg, &ds_id, &cValue); *//* printf("ds_id = %s\nvalue = %s\n", ds_id, cValue); *//* free(cValue); */free(ds_id);}else if (jsonorbin == kTypeBin){/* 解析EDP包 - bin数据存储 */UnpackSavedataBin(pkg, &desc_json, (uint8**)&save_bin, &save_binlen);desc_json_str=cJSON_Print(desc_json);printf("recv save data bin, src_devid: %s, desc json: %s, bin: %s, binlen: %d\n",src_devid, desc_json_str, save_bin, save_binlen);free(desc_json_str);cJSON_Delete(desc_json);free(save_bin);}else if (jsonorbin == kTypeString ){UnpackSavedataSimpleString(pkg, &simple_str);printf("%s\n", simple_str);free(simple_str);}else if (jsonorbin == kTypeStringWithTime){UnpackSavedataSimpleStringWithTime(pkg, &simple_str, &stTime);printf("time:%u-%02d-%02d %02d-%02d-%02d\nstr val:%s\n", stTime.year, stTime.month, stTime.day, stTime.hour, stTime.minute, stTime.second, simple_str);free(simple_str);}else if (jsonorbin == kTypeFloatWithTime){if(UnpackSavedataFloatWithTime(pkg, &float_data, &count, &stTime)){printf("UnpackSavedataFloatWithTime failed!\n");}printf("read time:%u-%02d-%02d %02d-%02d-%02d\n", stTime.year, stTime.month, stTime.day, stTime.hour, stTime.minute, stTime.second);printf("read float data count:%d, ptr:[%p]\n", count, (FloatDPS*)float_data);for(i = 0; i < count; ++i){printf("ds_id=%u,value=%f\n", float_data[i].ds_id, float_data[i].f_data);}free(float_data);float_data = NULL;}free(src_devid);}else{printf("error\n");}break;case SAVEACK:                                                                           //存储确认(server to client)UnpackSavedataAck(pkg, &msg_id, &save_date_ret);printf("[%d]save ack, msg_id = %d, ret = %d\n", __LINE__, msg_id, save_date_ret);break;case CMDREQ:                                                                           //云端发送命令响应(server to client)if (UnpackCmdReq(pkg, &cmdid, &cmdid_len, &cmd_req, &cmd_req_len) == 0){printf("[%d]cmdid: %s, req:%s, req_len: %d\n", __LINE__, cmdid, cmd_req, cmd_req_len);/** 用户按照自己的需求处理并返回,响应消息体可以为空,此处假设返回2个字符"ok"。* 处理完后需要释放*/
#ifdef _NEEDRESP                     cmd_resp_len = strlen(cmd_resp);send_pkg = PacketCmdResp(cmdid, cmdid_len, cmd_resp, cmd_resp_len);
#ifdef _ENCRYPTif (g_is_encrypt){SymmEncrypt(send_pkg);}
#endifDoSend(sockfd, (const char*)send_pkg->_data, send_pkg->_write_pos);     //将接收的数据上传DeleteBuffer(&send_pkg);
#endif                       free(cmdid);free(cmd_req);}break;case PINGRESP:                                                                            //心跳响应 (client to server)/* 解析EDP包 - 心跳响应 */UnpackPingResp(pkg);printf("recv ping resp\n");break;default:/* 未知消息类型 */error = 1;printf("recv failed...\n");break;}DeleteBuffer(&pkg);}}DeleteBuffer(&recv_buf);#ifdef _DEBUGprintf("[%s(%d)] recv thread end ...\n", __func__, __LINE__);
#endif
} 

主要的代码就是这些,直接看调试结果。

上面的截图显示了连接服务器和数据发送过程的调试打印信息,首先是连接服务器成功,在main函数中创建了一个接收线程,会收到服务器发送的响应信息,与前面用调试工具打印的信息是一致的:四个字节的16进制数:20 02 00 00;然后是向服务器发送数据,在write_func函数中采用拼接字符串的方式来产生需要发送的数据,再利用cJSON_Parse函数将数据打包成JSON串,调试打印对应输出无格式JSON串,然后采用PacketSavedataJson函数将JSON串打包成公开协议EDP数据包消息类型为Savedata。

在while代码块中屏蔽发送相关的语句,代码实现的功能就是连接服务器,然后就是等待服务器向设备发送命令:

注意上面打印信息的[490]这一行,这就是接收到服务器的命令信息,与上面的调试工具是类似的。记得前面还有一个问题,在应用中发送命令时这个EDP的命令内容到底表示什么含义?

根据这里的打印信息可以看到,命令请求是“{setting}22”,我是应用中的旋钮旋转到22的值,还记得在应用中旋钮设置的命令内容吗?我的设置是“{setting}{V}”,在介绍中说{V}表示通配符。通过这个打印信息,那里的命令内容就很显然了,因此,我们在设备端只要解析这个命令字符串就可以实现自己想要操作的设备功能。

在应用中还有一个控件专门用来输入命令的:

同样的,先绑定设备test,下发命令“Hello”,在设备端会接收到消息如下:

打印的命令请求正是“Hello”,至此,设备与OneNET连接和数据传输基本功能基本上是实现了,接下来就是真正的可以在项目中运用了。

OneNET云平台-EDP协议数据传输相关推荐

  1. micropython mqtt_MicroPython使用MQTT协议接入OneNET云平台

    MicroPython使用MQTT协议接入OneNET云平台 [复制链接] 本帖最后由 hanyeguxingwo 于 2016-11-22 11:33 编辑 之前使用Arduino+ESP8266使 ...

  2. 52单片机连接ESP8266烧入固件使用MQTT协议将温湿度上传至OneNET云平台

    52单片机连接ESP8266烧入固件使用MQTT协议连接OneNET云平台 参考: ---------------------------------------------------------- ...

  3. 基于ONENET云平台数据的MQTT协议的使用及模拟数据和搭建。

    登录与添加: 首先,我们打开ONENET云平台 然后选择登录 登录以后我们选择多协议接入中的MQTT 接着我们点击"添加产品"按钮 输入产品名称丶行业丶类别丶简介 技术参数中联网方 ...

  4. [单片机]基于STM32的ONENET云平台操控系统

    目录 1 项目描述 2 项目需求 3 搭建环境 数字温湿度传感器DHT11 光敏传感器 MPU6050 wifi模块ESP8266 OLED屏 RC522 W25Q128 SR04超声波 4 技术描述 ...

  5. 监测现场实时数据上传到中移物联网OneNet云平台

    OneNet,中移物联网云平台,是由中国移动打造的PaaS物联网开放平台.平台能够帮助开发者轻松实现设备接入与设备连接,快速完成产品开发部署,为智能硬件.智能家居产品提供完善的物联网解决方案(摘自36 ...

  6. OneNET云平台设备数据管理工具

    联系电话:15712339322 1 产品介绍 终端设备上报数据到OneNET云平台,除了云平台可以提供的可视化web页面外,还可以通过定制数据管理工具的方式对云数据进行展示.在该版本中提供对最细粒度 ...

  7. 用正点原子的精英版与onenet云平台连接

    关于这个想法我也是做了接近3个月,由于一直没有找到现成的例子,加上修改端口但是看不懂原理,也是不愿意去做的,现在就展示下我这3个月的成品把 ![这是onenet的效果展示](https://img-b ...

  8. 【毕业设计】基于云平台的火灾报警器 - stm32 物联网 单片机 OneNET云平台

    文章目录 0 简介 1 项目简介 2 开发环境 3 火焰传感器 4 连接OneNET云平台 5 演示效果 6 最后 0 简介 Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目 基于云平台的 ...

  9. 基于树莓派+STM32+OneNET云平台打造智能家居系统(一)硬件设计篇

      本次分享的是之前一个课程设计, 会分为几篇博文进行分享.智能家居是目前研究与发展的一大热点,本设计是结合STM32微处理器/树莓派(Raspberry Pi)3b+.温湿度传感器.继电器以及ESP ...

最新文章

  1. 跳槽,你心脚同步吗?
  2. MySQL SELECT同时UPDATE同一张表
  3. python把矩阵存为文件_python 读取文件并把矩阵转成numpy的两种方法
  4. Apollo仿真「训练有素」,长沙无人驾驶出租「轻车熟路」
  5. 【云隐】STM32F103C8T6实现串口IAP方式升级固件
  6. pip报 No module named ‘pip‘ 错误
  7. Java中的四种引用方式的区别
  8. pytorch选出数据中的前k个最大(最小)值及其索引
  9. 《C++ Primer第五版》第一章-------IO机制和注释缩进
  10. lxml处理xml时的字符编码问题
  11. 思科模拟器划分子网实验报告_模拟多子网群集以设置SQL Server Always On可用性组–实验设置
  12. 微信回应 WeTool 被封事件;支付宝小程序开放直播功能;Raspberry Pi 4 发布 8GB 版本| 极客头条...
  13. 【问题解决】线程间操作无效:从不是创建控件“textBox1”的线程访问它
  14. python读音播报-用Python写一个语音播放软件
  15. Java——删除文件
  16. 因子分析在SPSS中的应用
  17. EndNote X7 for Mac破解版
  18. 微信公众号开发诡异问题:errcode:40125,errmsg解决方案
  19. 获取UWP应用的三种方式
  20. Wireshark不同报文颜色的含义

热门文章

  1. python实现ocr识别算法_基于Python的OCR实现示例
  2. @WebServlet注解无效访问servlet接口时报404
  3. 小晶粒zsm分子筛合成表征实验报告_形貌_晶粒大小不同的ZSM_5分子筛的表征及催化性能的研究...
  4. 计算机毕业设计-基于SSM的网上球鞋竞拍购买管理系统
  5. 华为防火墙在NAT安全策略设置的解释
  6. C语言入门:分班级统计每人的体温并判断是否可以进入
  7. python类的定义与实例化
  8. Jarvis OJ pwn guestbook2
  9. Kali Linux 2021.1 详细安装教程
  10. 妙记多「我的主页」升级,日历聚合任务待办,为你打造个人时间管理系统⏰