【平头哥RVB2601创意应用开发】7. 物联网控制
<p><strong>一. 前言</strong></p><p> RVB2601搭载的板载w800 wifi模块可以方便的接入阿里云的飞燕平台,本文将讲解如何上传单片机数据到飞燕平台以及在飞燕平台上下传数据到我们的单片机。</p>
<p> </p>
<p><strong>二. 在飞燕平台上创建产品</strong></p>
<p> 1. 打开飞燕平台,登录自己的阿里云账号</p>
<p> 网址:<a href="https://living.aliyun.com/" target="_blank">https://living.aliyun.com/</a></p>
<p> 2. 新建项目,我在这里已经创建了一个网络闹钟的项目,这也是我本次比赛完成的作品,点击新创建的项目进行下一步。</p>
<p></p>
<p> 3. 点击创建新产品,我这里创建了一个网络闹钟的新产品,产品相关参数根据实际情况填写,这个不是很重要,因为后面的数据点都没有使用默认的,都是我自己新建的。因为选择的产品里面没有闹钟,所以我选择了一个手表。点击新创建的产品进行下一步。</p>
<p></p>
<p> </p>
<p> 4. 添加功能,我将标准功能都删除了,因为在我的产品中用不到这些,选择自定义功能,添加我自己的一些数据属性就行了。</p>
<p> 下图只展示我创建的一部分属性,属性的类型根据自己的实际情况来。</p>
<p></p>
<p> 5. 点击下一步,跳转到人机交互页面,这块根据自己的需求添加,不在赘述。</p>
<p> 6. 点击下一步,跳转到设备调试页面,在这里需要选择一个wifi模块,随便选择一个即可,然后点击新增调试设备。</p>
<p> <strong>注:页面右上方的Product Key以及Product Secret需要记住,这个在代码中需要使用到。</strong></p>
<p> 点击查看证书,可以查看到一些key,代码中设置五元组时需要用到。</p>
<p></p>
<p> </p>
<p> 7. 调试属性,走到这一步基本上算是创建设备成功了,如果需要在线调试的话,点击调试,调试的前提是我们在单片机上完成了与平台的数据交互,下一步开始单片机代码的开发。</p>
<p> </p>
<p><strong>三. 代码开发</strong></p>
<p><strong> </strong>初始化与连接路由器的相关操作不在赘述,可以参考web_player demo工程,下面只讲述RVB2601如何与云平台进行数据交互。</p>
<p> 关于使用w800连接云平台的相关AT指令,可以参考官方文档《RVB2601_W800网络透传AT指令集.pdf》 。</p>
<p></p>
<p> 1. 新建一个task,专门用来处理数据交互,Iot_TaskEntry是task入口函数,我们在这里面处理周期性任务;</p>
<p> 2. 注册属性数据接收下发任务,atparser_oob_create(g_atparser_uservice_t, "+IDMPS:", Iot_recv_handler, NULL);是安装属性数据接收服务函数,当收到了属性数据之后自动进入到函数Iot_recv_handler,我们将在这个函数中处理收到的CJSON数据;</p>
<p> 3. 注册平台里连接状态下发任务,atparser_oob_create(g_atparser_uservice_t, "+IDMSTA:", Iot_connsta_handler, NULL);是安装连接状态服务函数,当检测到状态变化的时候会自动进入到这个函数,我们将在这个函数中来判断我们是否连接到了云平台;</p>
<pre>
<code>/* 初始化函数 */
void Iot_Init(void)
{
int task_s;
//属性设置OOB注册
atparser_oob_create(g_atparser_uservice_t, "+IDMPS:", Iot_recv_handler, NULL);
//连接状态OOB注册
atparser_oob_create(g_atparser_uservice_t, "+IDMSTA:", Iot_connsta_handler, NULL);
aos_mutex_new(&iot_cmd_mutex);
task_s = aos_task_new_ext(&iot_task_h,
"iot_task",
Iot_TaskEntry,
NULL,
2048,
6);
if (0 == task_s)
{
printf("APP_IOT Task create success\r\n");
}
else
{
printf("APP_IOT Task create failed\r\n");
}
}</code></pre>
<p> 4. 设置设备五元组</p>
<p> 要要想成功连接到云平台,需要先设置设备五元组,函数实现如下:</p>
<pre>
<code>char *my_key = "xxxx"; //ProductKey
char *my_name = "test"; //DeviceName
char *my_secret = "xxxx";//DeviceSecret
char *my_p_secret = "xxxxx";//Product Secret
/* 设置设备五元组 */
static int Iot_w800_living_idmau(const char *mykey,const char *myname,const char *mysecret,const char *mypsecret)
{
int ret = -1;
aos_mutex_lock(&iot_cmd_mutex, AOS_WAIT_FOREVER);
atparser_clr_buf(g_atparser_uservice_t);
if (atparser_send(g_atparser_uservice_t,"AT+IDMAU=\"%s\",\"%s\",\"%s\",\"%s\"", mykey , myname , mysecret ,mypsecret) == 0)
{
if (atparser_recv(g_atparser_uservice_t, "OK\n") == 0)
{
ret = 0;
}
else
{
printf("AT+IDMAU: 五元组设置失败!\r\n");
}
}
atparser_cmd_exit(g_atparser_uservice_t);
if (ret == 0)
{
printf("AT+IDMAU: 设置五元组成功!\r\n");
}
aos_mutex_unlock(&iot_cmd_mutex);
return ret;
}</code></pre>
<p> 5. 连接飞燕平台</p>
<p> </p>
<pre>
<code>/* 连接飞燕物联网平台 */
static int Iot_w800_living_idmcon(void)
{
int ret = -1;
aos_mutex_lock(&iot_cmd_mutex, AOS_WAIT_FOREVER);
atparser_clr_buf(g_atparser_uservice_t);
if (atparser_send(g_atparser_uservice_t, "AT+IDMCON") == 0)
{
if (atparser_recv(g_atparser_uservice_t, "OK\n") == 0)
{
ret = 0;
}
else
{
printf("AT+IDMCON Destination Host Unreachable!\r\n");
}
}
atparser_cmd_exit(g_atparser_uservice_t);
if (ret == 0)
{
printf("AT+IDMCON: 连接飞燕平台成功 \r\n");
}
aos_mutex_unlock(&iot_cmd_mutex);
return ret;
}</code></pre>
<p> 6. 断开飞燕平台</p>
<pre>
<code>/* 断开飞燕物联网平台 */
static int Iot_w800_living_idmcls(void)
{
int ret = -1;
aos_mutex_lock(&iot_cmd_mutex, AOS_WAIT_FOREVER);
atparser_clr_buf(g_atparser_uservice_t);
if (atparser_send(g_atparser_uservice_t, "AT+IDMCLS") == 0)
{
if (atparser_recv(g_atparser_uservice_t, "OK\n") == 0)
{
ret = 0;
}
else
{
printf("AT+IDMCLS: 连接不到飞燕平台\r\n");
}
}
atparser_cmd_exit(g_atparser_uservice_t);
if (ret == 0)
{
printf("AT+IDMCLS: 断开飞燕平台 \r\n");
}
aos_mutex_unlock(&iot_cmd_mutex);
return ret;
}</code></pre>
<p> 7. 上报属性数据</p>
<p> 属性上报使用这个函数,第一个参数是设备ID,默认就是0,如果只有一个设备,就是0,第二个数要上传的数据,是一个JSON数据,第三个id也是默认0</p>
<pre>
<code>/* 上报状态 */
static int Iot_w800_living_idmpp(const char *dev_id, const char *msg, int *packet_id)
{
int ret = -1;
int rsp_dev_id = -1;
int rsp_packet_id = -1;
int rsp_code = -1;
int rsp_reply_len = -1;
char event_str;
char at_string_msg;
if ((!dev_id) || (!msg) || (!packet_id))
{
return ret;
}
aos_mutex_lock(&iot_cmd_mutex, AOS_WAIT_FOREVER);
atparser_clr_buf(g_atparser_uservice_t);
/* 上传报文生成 */
sprintf(at_string_msg, "AT+IDMPP=0,\"%s\"", msg);
printf("Send msg: %s\r\n", at_string_msg);
if (atparser_send(g_atparser_uservice_t, at_string_msg) == 0)
{
if (((atparser_recv(g_atparser_uservice_t, "+IDMPP:%d\n", packet_id) == 0) &&
(atparser_recv(g_atparser_uservice_t, "OK\n") == 0)) ||
(atparser_recv(g_atparser_uservice_t, "+IDMPP:%d,%d,%d,%d,%s\n",
&rsp_dev_id, &rsp_packet_id, &rsp_code, &rsp_reply_len, event_str) == 0))
{
ret = 0;
printf("AT+IDMPP: 数据上传成功\r\n");
}
}
else
{
printf("AT+IDMSTA FAILED\r\n");
}
atparser_cmd_exit(g_atparser_uservice_t);
aos_mutex_unlock(&iot_cmd_mutex);
return ret;
}</code></pre>
<p> 8. 状态服务函数</p>
<p> 在这个函数中判断平台连接状态,要上传或者下传数据,都需要先确保状态连接成功,返回值2表示连接成功,详见《RVB2601_W800网络透传AT指令集.pdf》</p>
<pre>
<code>/*云连接状态上报OOB处理*/
static int Iot_connsta_handler(atparser_uservice_t *at, void *priv, oob_data_t *oob_data)
{
int ret_status;
LOGI(TAG,"Iot==>connect status: %s(%d)", oob_data->buf, oob_data->len);
/* 将连接状态转换为数字 */
ret_status = oob_data->buf - 0x30U;
if((0 == ret_status) || (1 == ret_status) || (2 == ret_status))
{
dev_conn_st = ret_status;
}
return 0;
}</code></pre>
<p> 9. 属性数据接收处理函数</p>
<p> 这里主要是处理收到的JSON数据,需要导入Cjson库,详见我的上一篇帖子。</p>
<p> 其中Iot_apply需要小伙伴自己实现,data就是json数据,用于小伙伴自行处理,如果不清楚怎么处理,我看看我提交的作品贴子代码中有完成的处理方式。</p>
<pre>
<code>* 数据接收回调处理函数 */
static int Iot_recv_handler(atparser_uservice_t *at, void *priv, oob_data_t *oob_data)
{
int id = 0;
int len = 0;
char data = {0};
LOGI(TAG, "%s(%d)", oob_data->buf, oob_data->len);
char *str = strchr(oob_data->buf, ':');
if (str != NULL)
{
sscanf(oob_data->buf, "%d,%d,%s\r\n", &id, &len, data);
LOGI(TAG, "==>Iot received: %d(%d):%s\r\n", id, len, data);
Iot_apply(data);
}
/* recv data is not enough need recv more */
return 0;
}</code></pre>
<p> 10. 数据上传举例</p>
<p> 这里将用一个例子来说明如果将我们的属性数据转换为JSON格式上传到物联网平台</p>
<p> 我在之前创建属性的截图中有一个ntpEn属性,以这个为例,代码实现如下,</p>
<p> 在这个例子中,这个函数时在飞燕平台连接状态为2的时候才会调用,第一次调用的时候会自动发送一次数据,目的是和云平台的数据对齐。后续如果要发送的数据出现了变化之后才会再次发送,具体使用方式可以参考我的作品提交代码。</p>
<pre>
<code>/* 上报NTP设置状态 */
static void Iot_NtpSettingUpload(void)
{
static uint8_t last_ntp_status = 0;
static uint8_t first_enter = 1; /* 是否第一次进入这个函数 */
char msg_buf;
int pkt_id = 0;
uint8_t ntp_en_status;
int ret = -1;
ntp_en_status = 0; /*0 或者 1,这里写用户的函数。返回状态*/
/* 数据变化了或者第一次进入都上报状态 */
if ((ntp_en_status != last_ntp_status) || (1 == first_enter))
{
first_enter = 0;
sprintf(msg_buf, "{\\\"ntpEn\\\":%d}", ntp_en_status); /*将需要上传的属性变为json格式*/
ret = Iot_w800_living_idmpp("0", msg_buf, &pkt_id); /* 上传数据 */
if (-1 == ret)
printf(">>ntpEn setting data upload error\n");
else
printf(">>ntpEn Data Upload Success\n");
}
last_ntp_status = ntp_en_status;
}</code></pre>
<p> </p>
<p><strong>四. 调试</strong></p>
<p> 我们连接到了飞燕平台之后,测试设备状态会显示连接,此时我们点击调试进入调试界面。</p>
<p></p>
<p> </p>
<p><strong>五. 创建web可视化开发页面</strong></p>
<p> 为了方便我们进行操作,我们需要在web可视化界面上制作一些按钮或者编辑框来发送数据。</p>
<p> web可视化界面创建教程链接:<a href="https://help.aliyun.com/document_detail/141613.html" target="_blank">https://help.aliyun.com/document_detail/141613.html</a></p>
<p> 应用开发网址:<a href="https://studio.iot.aliyun.com/?spm=a2c4g.11186623.0.0.58531a5fYJegwy" target="_blank">https://studio.iot.aliyun.com/?spm=a2c4g.11186623.0.0.58531a5fYJegwy</a></p>
<p> 接下来开始创建一个web可视化界面。</p>
<p> 1. 新建web应用</p>
<p> 这里可以选择web应用或者移动应用,其实都是一样的,只是移动应用在手机上看起来方便一些。</p>
<p></p>
<p> 2. 新建开关</p>
<p> 这里以只以创建一个开关举例,需要创建其他的控件请参考文档,不在赘述。</p>
<p></p>
<p> 3. 配置数据源</p>
<p> 选中开关,在右边的扩展窗口菜单中点击配置数据源</p>
<p> 这个配置是用来获取下位机(单片机)端上传的属性数据的。<br />
</p>
<p> 4.配置数据交互</p>
<p> 选中交互,这里是配置开关动作的功能的,这里选择值改变,意思是开关值改变了之后就发送属性数据到下位机。</p>
<p></p>
<p> 5. 经过上面的步骤,我们已经完成了一个简单的web交互页面,其他的比如编辑框可以参考这个设置,逻辑是一样的。</p>
<p> </p>
<p><strong>六. 测试</strong></p>
<p> web页面编辑好了之后点击右上角的预览,可以开始验证通信是否成功了。</p>
<p></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
页:
[1]