快速体验

更新时间:2018-10-24 22:23:37

本章描述在Linux环境下通过已有示例代码来开发设备,让设备厂商对如何在阿里云IoT开发设备有个大概的了解。文档中将会描述如何通过MQTT协议以topic的编程方式、以及通过物模型的编程方式向阿里云IoT物联网平台上报和接收业务报文。</span>

准备开发环境

本地安装Ubuntu及相关软件

安装Ubuntu 16.04

本SDK的编译环境是64位主机上的Ubuntu16.04, 推荐安装与阿里一致的发行版

如果您使用Windows操作系统, 建议安装虚拟机软件Virtualbox, 下载地址: https://www.virtualbox.org/wiki/Downloads

然后安装64位的Desktop版本的Ubuntu 16.04.x LTS, 下载地址: http://releases.ubuntu.com/16.04

安装必备软件

本SDK的开发编译环境使用如下软件: make-4.1, git-2.7.4, gcc-5.4.0, gcov-5.4.0, lcov-1.12, bash-4.3.48, tar-1.28, mingw-5.3.1

可使用如下命令行安装必要的软件:

apt-get install -y build-essential make git gcc

通过Hacklab WebIDE进行开发

如果您不打算在您的PC或者笔记本电脑上安装Linux,也可通过阿里云IoT提供的Hacklab WebIDE环境直接进行设备开发,Hacklab WebIDE是一个云端的Linux开发环境,已经将必要的软件安装完毕,只要您拥有一个阿里云账号,就可以通过浏览器登录进行开发,点击此处</span>登录Hacklab WebIDE</span>

以MQTT Topic编程方式接入设备

创建产品和设备

请登录阿里云IoT物联网平台进行产品创建,登录时通过您的阿里云账号进行登录。因为是直接通过MQTT的Topic进行产品功能实现,所以在创建产品时选择“基础版”即可。

创建产品之后可以添加一个具体的设备,阿里云IoT物联网平台会为设备生成身份信息。

如果您对云端如何创建产品不熟悉,请点击此处了解如何在阿里云IoT物联网平台进行产品和设备创建。

产品功能实现

获取C SDK

以获取 V2.2.0 版本SDK为例, 可用如下命令行获取:

cd ${HOME}
mkdir srcs
cd srcs
wget https://linkkit-sdk-download.oss-cn-shanghai.aliyuncs.com/linkkit2.2.tar.gz
tar xvf linkkit2.2.tar.gz

则在 ~/srcs/iotx-sdk-c 目录得到了解压之后的C-SDK,下面将修改示例文件 </span>iotx-sdk-c/examples/mqtt/mqtt-example.c来将设备连接到阿里云IoT平台

建立与云端的MQTT连接

填入设备三元组到示例文件

打开文件 iotx-sdk-c/examples/mqtt/mqtt-example.c, 编辑如下代码段, 填入之前创建设备后得到的设备三元组:

#if defined(SUPPORT_ITLS)

...
...

#else

    #if defined(ON_DAILY)
        ...
        ...
    #else  
        #define PRODUCT_KEY             "a1ExpAkj9Hi"
        #define DEVICE_NAME             "Example1"
        #define DEVICE_SECRET           "cNzcn2Lbqzh4UiXKLwW77hxI9GFmcRgb"
    #endif

#endif

注:在Ubuntu的HAL实现中读取了上面定义的设备三元组信息。

初始化与建立连接

下面的代码片段简单描述了设备的初始化以及连接过程:

int mqtt_client(void)
{
    ...
    ...

在与服务器尝试建立MQTT连接前, 填入设备身份认证信息

    if (0 != IOT_SetupConnInfo(__product_key, __device_name, __device_secret, (void **)&pconn_info)) {
        EXAMPLE_TRACE("AUTH request failed!");
        rc = -1;
        goto do_exit;
    }

    /* Initialize MQTT parameter */
    ...
    ...

尝试建立与服务器的MQTT连接

    pclient = IOT_MQTT_Construct(&mqtt_params);
    if (NULL == pclient) {
        EXAMPLE_TRACE("MQTT construct failed");
        rc = -1;
        goto do_exit;
    }

上报数据到云端

在示例文件中定义了如下的topic:

/* These are pre-defined topics */
#define TOPIC_UPDATE            "/"PRODUCT_KEY"/"DEVICE_NAME"/update"
#define TOPIC_ERROR             "/"PRODUCT_KEY"/"DEVICE_NAME"/update/error"
#define TOPIC_GET               "/"PRODUCT_KEY"/"DEVICE_NAME"/get"
#define TOPIC_DATA              "/"PRODUCT_KEY"/"DEVICE_NAME"/data"

/* These are pre-defined topics format*/
#define TOPIC_UPDATE_FMT            "/%s/%s/update"
#define TOPIC_ERROR_FMT             "/%s/%s/update/error"
#define TOPIC_GET_FMT               "/%s/%s/get"
#define TOPIC_DATA_FMT              "/%s/%s/data"

下面的代码片段示例了如何向topic发送数据:

/* Initialize topic information */
    memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
    strcpy(msg_pub, "update: hello! start!");

    topic_msg.qos = IOTX_MQTT_QOS1;
    topic_msg.retain = 0;
    topic_msg.dup = 0;
    topic_msg.payload = (void *)msg_pub;
    topic_msg.payload_len = strlen(msg_pub);

    rc = IOT_MQTT_Publish(pclient, TOPIC_UPDATE, &topic_msg);
    if (rc < 0) {
        IOT_MQTT_Destroy(&pclient);
        EXAMPLE_TRACE("error occur when publish");
        rc = -1;
        goto do_exit;
    }

    EXAMPLE_TRACE("\n publish message: \n topic: %s\n payload: \%s\n rc = %d", TOPIC_UPDATE, topic_msg.payload, rc);

从云端订阅并处理数据

示例程序向一个topic发送数据,并自己订阅该topic将其从云端将数据接收回来。下面的代码订阅指定的topic并指定接收到数据时的处理函数:

    rc = IOT_MQTT_Subscribe(pclient, TOPIC_DATA, IOTX_MQTT_QOS1, _demo_message_arrive, NULL);
    if (rc < 0) {
        IOT_MQTT_Destroy(&pclient);
        EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc);
        rc = -1;
        goto do_exit;
    }

    IOT_MQTT_Yield(pclient, 200);

    HAL_SleepMs(2000);

    ...
    ...

示例程序中收到来自云端数据时只是把数据打印出来:

static void _demo_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
    iotx_mqtt_topic_info_pt ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg;

    /* print topic name and topic message */
    EXAMPLE_TRACE("----");
    EXAMPLE_TRACE("packetId: %d", ptopic_info->packet_id);
    EXAMPLE_TRACE("Topic: '%.*s' (Length: %d)",
                  ptopic_info->topic_len,
                  ptopic_info->ptopic,
                  ptopic_info->topic_len);
    EXAMPLE_TRACE("Payload: '%.*s' (Length: %d)",
                  ptopic_info->payload_len,
                  ptopic_info->payload,
                  ptopic_info->payload_len);
    EXAMPLE_TRACE("----");
}

下面的代码片段尝试向该topic发送数据:

do {
        cnt++;
        msg_len = snprintf(msg_pub, sizeof(msg_pub), "{\"attr_name\":\"temperature\", \"attr_value\":\"%d\"}", cnt);
        ...
        ...

        rc = IOT_MQTT_Publish(pclient, TOPIC_DATA, &topic_msg);
        if (rc < 0) {
            EXAMPLE_TRACE("error occur when publish");
            rc = -1;
            break;
        }
        EXAMPLE_TRACE("packet-id=%u, publish topic msg=%s", (uint32_t)rc, msg_pub);

编译例子程序

运行如下命令:

cd ~/srcs/iotx-sdk-c
make distclean
make

编译成功完成后, 生成的样例程序在当前路径的 output/release/bin 目录下:

$ tree output/release
output/release/

+-- bin
...
...

|   +-- mqtt-example
...
...

观察数据

之后,可以运行生成的mqtt-example程序:

cd output/release/bin
./mqtt-example

可以在物联网平台的控制台,找到指定的产品,在其日志服务中查看设备上报的消息。可以点击此处了解如何在云端查看设备上报的数据。

在Linux的console里面也可以看见示例程序打印的来自云端的数据:

_demo_message_arrive|166 :: ----
_demo_message_arrive|167 :: packetId: 35641
_demo_message_arrive|171 :: Topic: '/a1ExpAkj9Hi/Example1/data' (Length: 26)
_demo_message_arrive|175 :: Payload: '{"attr_name":"temperature", "attr_value":"1"}' (Length: 45)
_demo_message_arrive|176 :: ----

以物模型编程方式接入设备

创建产品和设备

可以在阿里云IoT物联网平台以及其上承载的多个行业服务中进行产品的创建,此处仍然以在阿里云IoT物联网平台创建产品为例:

在本示例中,需要创建以下的包含如下物模型的产品:

  • 属性DeviceStatus
    标识符:DeviceStatus
    数据类型:text,
    数据长度:2048,
    读写类型:读写

  • 服务Custom
    标识符:Custom
    调用方式:异步
    输入参数:
    {
    标识符:transparency,
    数据类型:int32
    }
    输出参数:
    {
    标识符:Contrastratio
    数据类型:int32
    }

  • 事件
    标识符:Error
    事件类型:信息
    输出参数
    {
    标识符:ErrorCode
    数据类型:enum
    取值范围:0, 1
    }

定义物模型之后云端会为该物模型生成物模型(TSL)描述文件,该文件使用JSON格式进行描述。

产品功能实现

TSL数据转换

在设备端需要将物模型文件从JSON格式转换为一个string使用,因此SDK提供了一个工具用于该数据转换,运行如下命令来生成该转换工具:

make distclean
make

iotx-sdk-c/output/release/bin 目录下会产生一个转义工具 linkkit_tsl_convert, 将产品的物模型文件model.json拷贝到这里, 执行如下命令:

$ ./linkkit_tsl_convert -i model.json

命令执行成功后会在当前目录下产生一个conv.txt文件, 其中包含将物模型从JSON转换为C语言识别的字符串. (JSON转义工具网上很多, 也可自行寻找)

示例程序修改

示例代码文件是iotx-sdk-c/examples/linkkit/linkkit_example_solo.c,</span>存放TSL字符串的文件是iotx-sdk-c/examples/linkkit/solo_tsl.data</span>

首先,将conv.txt文件中的字符串替换example_tsl_solo.data</span>中的字符串:

image.png | left | 747x115

替换示例代码文件iotx-sdk-c/examples/linkkit/linkkit_example_solo.c</span>中的设备三元组:

image.png | left | 704x299

编译与运行程序

iotx-sdk-c/examples/linkkit/linkkit_example_solo.c</span>文件已包含对前面定义的属性、服务、事件的相关代码,所以直接编译 并运行示例程序:

$ make distclean
$ make
$ ./output/release/bin/linkkit-example-solo

观察数据

示例程序会定期将DeviceStatus属性的数值上报云端,因此可以在云端查看收到的属性,并且可以在云端对该属性进行设置,然后再次查看从设备端上报的DeviceStatus已经修改为用户设置的数值。

查看示例代码

属性上报

示例中使用linkkit_post_property上报属性:

/* 此函数在示例代码中每30s被调用一次 */
int post_all_prop(sample_context_t *sample)
{
    /* 这里第二个参数填NULL表示上报所有属性 */
    return linkkit_post_property(sample->thing, NULL, post_property_cb);
}

注:SDK加载TSL文件的时候会为所有的属性创建变量用于记录数据,DeviceStatus的数据类型是text,默认为空字符串,所以可以看见下面的log:

  [dbg] iotx_dm_post_property_end(450): Current Property Post Payload, Length: 19, Payload: {"DeviceStatus":""}
  [dbg] _dm_mgr_search_dev_by_devid(46): Device Found, devid: 0
  [inf] dm_msg_request_all(265): DM Send Message, URI: /sys/a1csED27mp7/AdvExample1/thing/event/property/post, Payload: {"id":"1","version":"1.0","params":{"DeviceStatus":""},"method":"thing.event.property.post"}
  [inf] iotx_cm_conn_mqtt_publish(531): mqtt publish: topic=/sys/a1csED27mp7/AdvExample1/thing/event/property/post, topic_msg={"id":"4","version":"1.0","params":{"DeviceStatus":""},"method":"thing.event.property.post"}

属性设置处理

在示例代码中当收到属性set请求时, 会进入如下回调函数:

static int thing_prop_changed(const void *thing_id, const char *property, void *ctx) {
    ...
    ...

    /* 这里将被设置的属性值发送到云端, 这样在云端控制台才能看到属性的新值 */
    response_id = linkkit_post_property(thing_id, property, post_property_cb);

    EXAMPLE_TRACE("post property(%s) response id: %d\n", property, response_id);
}

可以在云端对DeviceStatus进行设置,然后查看上报的属性是否已经修改。

注:实际的产品收到属性设置时,应该解析属性并进行相应处理而不是仅仅将数值发送回云端。

事件上报

下面的示例代码描述了如何上报属性:

/* 此函数在示例代码中每45s被调用一次 */
int trigger_event(sample_context_t *sample)
{
    char event_output_identifier[64];
    snprintf(event_output_identifier, sizeof(event_output_identifier), "%s.%s", EVENT_ERROR_IDENTIFIER,
             EVENT_ERROR_OUTPUT_INFO_IDENTIFIER);

    /* 设置Error事件的输出参数值 */
    int errorCode = 0;
    linkkit_set_value(linkkit_method_set_event_output_value,
                      sample->thing,
                      event_output_identifier,
                      &errorCode, NULL);

    /* 上报Error事件到云端 */
    return linkkit_trigger_event(sample->thing, EVENT_ERROR_IDENTIFIER, post_property_cb);
}

上面的代码中使用linkkit_set_value()把数据先进行了缓存,然后再调用linkkit_trigger_event()上传数据到云端。

results matching ""

    No results matching ""