2

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①-一叶孤沙...

 4 years ago
source link: https://blog.51cto.com/14616151/2481856
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

前言

本文研究如何使用RT_Thread onenet组件将设备连接到中移onnet云平台,onenet组件提供多种方式连接云平台,本文使用mqtt方式连接,完成一个三色灯项目。

一、理论基础

1.onenet平台介绍

OneNET定位为PaaS服务,即在物联网应用和真实设备之间搭建高效、稳定、安全的应用平台:面向设备,适配多种网络环境和常见传输协议,提供各类硬件终端的快速接入方案和设备管理服务;面向企业应用,提供丰富的API和数据分发能力以满足各类行业应用系统的开发需求,使物联网企业可以更加专注于自身应用的开发,而不用将工作重心放在设备接入层的环境搭建上,从而缩短物联网系统的形成周期,降低企业研发、运营和运维成本。

中移OneNET是中国移动基于物联网技术和产业特点打造的开放平台和生态环境,将面向智能家居、可穿戴设备、车联网、移动健康、智能创客等多个领域开放。

以上介绍过于官方,我来从开一个开发者的视角说下哈,目前onnet是国内比较早的一批做云的平台,论坛十分活跃,各种技术分享资料层出不穷,非常适合希望了解物联网的朋友深入学习,下图是目前onenet社区的会员和帖子总体情况:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

二、使用实例

1.云端创建产品

接下来咱们进入正题,首先需要在云端创建一个产品,步骤如下:

创建产品
登录onenet官网,注册一个账号,地址:https://open.iot.10086.cn, 点进开发者中心,创建产品,产品配置信息如下:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

注意;操作系统这里使用RT_Thread,没有此选项,选用linux即可

创建数据点
数据流模板->添加数据流模板

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

创建产品数据点,此处创建power和color两个数据点,power表示总开关,power为0时候,灯关闭;power不为0的时候,color数值起作用,用以选择不同模式。

创建后台显示数据面板
应用管理->独立应用->添加应用

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

注意:红色、绿色、蓝色按钮和颜色显示图片均链接color数据点,颜色显示图片仅显示左右,按钮可以下发选择不同的灯颜色。

到此为止,我们已经完成了产品的创建工作,接下来将要处理设备接入问题。

2.设备SDK移植

下载onenet组件包
打开包管理工具,进入RT-Thread online packages/IOT-internet of things目录,选择Paho MQTT、webClient、cJSON组件,如下所示:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

选择IOT Cloud --->进入配置页面,将创建的产品信息配置进去,onenet配置信息如下:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

注意:选择Enable OneNET automatic register device,设备可以注册到云端,而不需要每个设备都手动在平台注册,然后把设备信息再写入设备中,这样一来将为工厂产线减少工作量,解决烧录容易出现设备信息写错等问题。

下载fal、easyflash组件
这两个组件主要是用来存放设备自动注册获取的设备认证信息,下次设备启动检测是否含有设备信息,如果有可以直接进行mqtt连云,否则需要重新注册。

进入RT-Thread online packages/system packages目录,选择fal组件,如下所示:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

进入RT-Thread online packages/tools packages目录,选择easyflash组件,如下所示:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

移植fal、easyflash组件

在w60x路径下新建ports文件夹,然后在ports下创建两个移植组件fal和easyflash,注意fal下SConscrip指定Group名字为fal和packages/fal-latest中对应,easyflash亦然;至于移植细节,之后会另行介绍,现在着重开发项目。

修改onenet组件

a.修改函数指针:cmd_rsp_cb

函数指针cmd_rsp_cb指向一个函数,用来接收onenet下发的数据,RT_Thread中的处理方式是云端下发数据后,通过调用onenet_mqtt.cmd_rsp_cb,将数据抛给应用层的一个函数,并通过参数uint8_t *resp_data获取应用层处理后的结果,紧接着返回给onenet;我这里所作的修改是用户自行控制上发数据,因此不需要原函数中后两个参数,此外增加了char topic_name,字段,因为用户自己控制上报数据时候,需要区分数据是云端下发的相应还是设备触发的主动上报。

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

设备主动上报topic_name是$dp,需要调用:
send_mq_msg("$dp", send_msg.data_ptr, send_msg.data_size);

设备应答云端下发的topic_name通过cmd_rsp_cb对应的回调函数可以获得,回调函数中首先获取数据,然后调用:
send_mq_msg(topic_name, (uint8_t *)res_buf, rt_strlen(res_buf));

b.发送队列统一发送数据,解决高频控制或常问题

send_mq_msg()函数实际上是把数据扔进发送队列中,发送队列在一个线程中等待,检测到有内容扔进队列的时候,则从队列中取出数据发送给onenet,实现代码如下所示:

static void onenet_upload_entry(void *parameter)
{
    mq_send_msg_t send_msg = { 0x00 };
    led_blue_on();
    send_mq_msg("$dp", (uint8_t *)POST_DATA4, rt_strlen((char *)POST_DATA4));

    while (1)
    {
        rt_memset(&send_msg, 0x00, sizeof(send_msg));
        if (RT_EOK == rt_mq_recv(mq_send, &send_msg, sizeof(send_msg), RT_WAITING_FOREVER))
        {
            if (onenet_mqtt_upload_data(send_msg.topic_name, (const char *)send_msg.data_ptr))
            {
                rt_kprintf("upload has an error, stop uploading\n");
                break;
            }
            else
            {
                if (NULL==rt_strstr(send_msg.topic_name, "$dp"))  //上次上报是返回给mqtt服务器, 需要更新下数据以求同步数据到onnect后台web页面
                {
                    send_mq_msg("$dp", send_msg.data_ptr, send_msg.data_size);
                }
                rt_kprintf("buffer : %s\ntopic_name is:%s", send_msg.data_ptr, send_msg.topic_name);
                rt_free(send_msg.data_ptr);
            }
        }
        rt_thread_mdelay(50);
    }
    exit:
    rt_kprintf("upload thread exit!!!");
}

c.发送所有状态数据到onenet

RT_Thread提供的是一次性发送一个数据点给云端,我修改后也支持一次性上报所有数据,这样APP只需要每次刷新各个状态就行,不需要判断是哪个数据发生了改变。

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

函数具体实现如下:

rt_err_t onenet_mqtt_upload_data(const char *topic_name, const char *msg_str)
{
    char *send_buffer = RT_NULL;
    rt_err_t result = RT_EOK;
    size_t length = 0;

    assert(msg_str);

  send_buffer = ONENET_MALLOC(strlen(msg_str) + 4);
    if (!(send_buffer))
    {
        log_e("ONENET mqtt upload string data failed! No memory for send buffer!");
        return -RT_ENOMEM;
    }
  *(send_buffer + strlen(msg_str) + 3) = 0x00;

    strncpy(&send_buffer[3], msg_str, strlen(msg_str));
    length = strlen(msg_str);
    /* mqtt head and json length */
    send_buffer[0] = 0x03;
    send_buffer[1] = (length & 0xff00) >> 8;
    send_buffer[2] = length & 0xff;
  length += 3;

    result = onenet_mqtt_publish(topic_name, (uint8_t *)send_buffer, length);
    if (result < 0)
    {
        log_e("onenet mqtt publish digit data failed!");
        goto __exit;
    }

__exit:
    if (send_buffer)
    {
        ONENET_FREE(send_buffer);
    }

    return result;
}

3.程序分析

mqtt组件入口
main()函数中注册网络状态变化函数,然后连接网络,连接成功后,调用onenet_mqtt_init()开启mqtt服务:首先获取设备信息,如果获取不到,则进行注册流程,获取设备信息后,进行mqtt初始化设置,设置认证参数和数据接收、连接状态变化回调函数。

int onenet_mqtt_init(void)
{
    int result = 0;

    if (init_ok)
    {
        LOG_D("onenet mqtt already init!");
        return 0;
    }

    if (onenet_get_info() < 0)
    {
        result = -1;
        goto __exit;
    }

    onenet_mqtt.onenet_info = &onenet_info;
    onenet_mqtt.cmd_rsp_cb = RT_NULL;

    if (onenet_mqtt_entry() < 0)
    {
        result = -2;
        goto __exit;
    }

__exit:
    if (!result)
    {
        LOG_I("RT-Thread OneNET package(V%s) initialize success.", ONENET_SW_VERSION);
        init_ok = RT_TRUE;
    }
    else
    {
        LOG_E("RT-Thread OneNET package(V%s) initialize failed(%d).", ONENET_SW_VERSION, result);
    }

    return result;
}

数据下发入口

当有平台数据下发,设备会进入mqtt_callback()回调函数,回调函数中处理数据,然后抛给应用层数据接收处理函数onenet_cmd_rsp_cb(),可通过onenet_set_cmd_rsp_cb(onenet_cmd_rsp_cb)在应用层设置。

static void onenet_cmd_rsp_cb(char *topic_name, uint8_t *recv_data, size_t recv_size)
{
    char res_buf[128] = { 0 };
  int value = 0;

    rt_kprintf("recv data is %.*s\n", recv_size, recv_data);

  value = atoi((char *)recv_data);
  rt_kprintf("recv int data is:%d\r\n", value);
    /* match the command */
    if (value == 10) //总开关,默认为红色
    {
        /* led on */
        led_red_on();

        rt_snprintf(res_buf, sizeof(res_buf), "{\"power\":\"10\",\"color\":\"2\"}");

    }else if (value == 0)
  {
        /* led off */
        led_off();

        rt_snprintf(res_buf, sizeof(res_buf), "{\"power\":\"0\",\"color\":\"1\"}");

  }
  else if (value == 2)//红色
    {
        /* red led on */
        led_red_on();

        rt_snprintf(res_buf, sizeof(res_buf), "{\"power\":\"10\",\"color\":\"2\"}");

    }
    else if (value == 3)//绿色
    {
        /* green led on */
        led_green_on();

        rt_snprintf(res_buf, sizeof(res_buf), "{\"power\":\"10\",\"color\":\"3\"}");

    }
    else if (value == 4)//蓝色
    {
        /* blue led on */
        led_blue_on();

        rt_snprintf(res_buf, sizeof(res_buf), "{\"power\":\"10\",\"color\":\"4\"}");

    }
  send_mq_msg(topic_name, (uint8_t *)res_buf, rt_strlen(res_buf));
}

数据上报入口

当设备通过连接到onenet服务器的时候,会进入mqtt_online_callback()回调函数,数据上报入口函数就是在这里触发,创建一个发送线程,检测发送队列中的数据,一旦有数据需要发送,立刻取出队列发送给云端。

static void mqtt_online_callback(MQTTClient *c)
{
    LOG_D("Enter mqtt_online_callback!");
    onenet_upload_cycle();
}

4.配置

在applications目录下新建一个文件夹:3-cloud/1-onenet_led,然后同理需要修改aplications/SConscript脚本。

Import('RTT_ROOT')
Import('rtconfig')
from building import *

cwd = GetCurrentDir()
src  = Glob('3-cloud/1-onenet_led/*.c')
CPPPATH = [cwd]

group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)

Return('group')

三、下载运行

在ENV控制台,输入scons命令,在build/Bin目录下生成rtthread_1M.FLS,
烧录运行后,设备端按照下图所示连接电路:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①
# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

设备Log如下所示:

 \ | /
- RT -     Thread Operating System
 / | \     4.0.0 build Jun 30 2019
 2006 - 2018 Copyright by rt-thread team
lwIP-2.0.2 initialized!
[32m[5] I/SAL_SOC: Socket Abstraction Layer initialize success.

[0m[32m[64] I/WLAN.dev: wlan init success

[0m[32m[95] I/WLAN.lwip: eth device init ok name:w0

[0m[32m[100] I/WLAN.dev: wlan init success

[0m[32m[132] I/WLAN.lwip: eth device init ok name:w1

[0m[D/FAL] (fal_flash_init:61) Flash device |                nor_flash | addr: 0x00000000 | len: 0x00100000 | blk_size: 0x00001000 |initialized finish.
[32;22m[I/FAL] ==================== FAL partition table ====================[0m
[32;22m[I/FAL] | name      | flash_dev |   offset   |    length  |[0m
[32;22m[I/FAL] -------------------------------------------------------------[0m
[32;22m[I/FAL] | app       | nor_flash | 0x00010000 | 0x00080000 |[0m
[32;22m[I/FAL] | download  | nor_flash | 0x00090000 | 0x00060000 |[0m
[32;22m[I/FAL] | fs_part   | nor_flash | 0x000f0000 | 0x0000b000 |[0m
[32;22m[I/FAL] | easyflash | nor_flash | 0x000fb000 | 0x00001000 |[0m
[32;22m[I/FAL] =============================================================[0m
[32;22m[I/FAL] RT-Thread Flash Abstraction Layer (V0.3.0) initialize success.[0m
[Flash] EasyFlash V3.3.0 is initialize success.
[Flash] You can get the latest version on https://github.com/armink/EasyFlash .
msh />[32m[4268] I/WLAN.mgnt: wifi connect success ssid:LBAGMY

[0m[D/ONENET] (onenet_mqtt_init:201) onnect mqtt init
[D/ONENET] (mqtt_connect_callback:85) Enter mqtt_connect_callback!
[36;22m[I/ONENET] RT-Thread OneNET package(V1.0.0) initialize success.[0m
[32m[5296] I/WLAN.lwip: Got IP address : 192.168.1.6

[0m[32m[5477] I/MQTT: MQTT server connect success

[0m[D/ONENET] (mqtt_online_callback:90) Enter mqtt_online_callback!
buffer : {"power":"10","color":"4"}
topic_name is:$dp[31m[30547] E/MQTT: [30547] wait Ping Response res: 0

[0m[D/ONENET] (mqtt_offline_callback:96) Enter mqtt_offline_callback!
[D/ONENET] (mqtt_connect_callback:85) Enter mqtt_connect_callback!
[32m[35662] I/MQTT: MQTT server connect success

[0m[D/ONENET] (mqtt_online_callback:90) Enter mqtt_online_callback!
buffer : {"power":"10","color":"4"}
topic_name is:$dp[D/ONENET] (mqtt_callback:60) topic $creq/a2a663b4-5b87-57ad-81d8-9e563659e540 receive a message
[D/ONENET] (mqtt_callback:62) message length is 1
recv data is 2
recv int data is:2

buffer : {"power":"10","color":"2"}
topic_name is:$crsp/a2a663b4-5b87-57ad-81d8-9e563659e540buffer : {"power":"10","color":"2"}
topic_name is:$dp[D/ONENET] (mqtt_callback:60) topic $creq/e08cd093-66ec-5e43-812c-ae7d2cd2cf5c receive a message
[D/ONENET] (mqtt_callback:62) message length is 1
recv data is 3
recv int data is:3

buffer : {"power":"10","color":"3"}
topic_name is:$crsp/e08cd093-66ec-5e43-812c-ae7d2cd2cf5cbuffer : {"power":"10","color":"3"}
topic_name is:$dp[D/ONENET] (mqtt_callback:60) topic $creq/65824a18-f17c-5286-b4b6-7f13a4d76246 receive a message
[D/ONENET] (mqtt_callback:62) message length is 1
recv data is 4
recv int data is:4

buffer : {"power":"10","color":"4"}
topic_name is:$crsp/65824a18-f17c-5286-b4b6-7f13a4d76246buffer : {"power":"10","color":"4"}
topic_name is:$dp

后台显示:

红色灯模式

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

绿色灯模式

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

蓝色灯模式

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

四、结语

1.总结:

本节完,实际操作过程中需要注意的地方有如下几点:

(1) 组件方式调整

之前的教程都是,每篇当作一个新的项目来做,每次都重新拉取组件包,但是更新本篇内容时候,我发现有时候组件包和RT_Thread menuconfig控制工具没有很好的协调一致,比如本篇中用到的W600组件包,wm_libraries,这次配置工具并没有该选项,于是通过RT_Thread官网寻找wm_libraries组件,提示可以在包管理工具中选择,如下:

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

实际包管理工具如下图所示,并没有wm_libraries,但是有realtek的RTL8710组件,这也为之后做个铺垫,接下来会出一些RTL8710的教程,敬请期待。

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

考虑到目前存在的问题,为了防止大家在使用的时候遇到和我类似的问题,从本篇开始,项目使用到的组件都会上传到github,大家下载后,配置SConscript选择需要运行的应用即可。

(2) 修改了RT_Thread的连接onenet连接组件包

a. 修改数据上报逻辑
原有组件包是每次回复单个数据点的数据,修改后支持一次性上报所有数据点,同时调整mqtt数据上报处理逻辑。

b. 增加队列缓冲发送机制
解决连续两次调用数据发送接口,仅有第一次发出去的问题。

(3)资料获取

如您在使用过程中有任何问题,请加QQ群进一步交流,也可以github提Issue。

QQ交流群:906015840 (备注:物联网项目交流)

关注公众后,回复w600获取资料

一叶孤沙出品:一沙一世界,一叶一菩提

# IT明星不是梦 # WIFI模块开发教程之W600连云篇1:onenet三色灯项目mqtt篇①

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK