全部产品
云市场
云游戏

自定义协议

更新时间:2020-01-06 18:31:52

Link IoT Edge提供设备接入SDK(Link Edge Device Access,简称LEDA)方便您开发自己的驱动,SDK目前支持C、Node.js和Python三种版本的语言。本章节通过实现一个LED灯设备接入Link IoT Edge,介绍自定义驱动开发流程。
设备接入SDK支持的三种开发语言详细内容,请参见CNode.jsPython

背景信息

本驱动示例实现如下场景:通过自定义驱动,实现一个LED灯设备接入Link IoT Edge,您可以通过物联网平台控制台,控制LED灯设备的开关操作,也可以主动查询灯设备的当前温度。如下图所示:
123

在Link IoT Edge官方驱动中并没有可以完成该需求的驱动,因此需要在LinkIoT Edge上开发LED设备驱动。

1.驱动编码

本章主要描述,在驱动开发中如何进行驱动编码。进行驱动编码前,需要了解Link IoT Edge的驱动信息配置和设备信息配置相关内容。

1.1 驱动信息配置

部署边缘实例时,驱动配置信息会被部署到边缘网关,其内容以json格式存储在Link IoT Edge配置中心,可以通过leda_get_driver_info接口获取。
驱动信息配置有如下三种配置格式:

  1. {
  2. "kv":[
  3. {
  4. "key":"ip",<
  5. "value":"127.0.0.1",
  6. "note":"ip地址"
  7. },
  8. { "key":"port",
  9. "value":"54321",
  10. "note":"port端口"
  11. }
  12. ]
  13. }

格式参数说明,如下图所示:
124

l JSON格式

  1. {
  2. "json":{
  3. "ip":"127.0.0.1",
  4. "port":54321
  5. }
  6. }

格式参数说明,如下图所示:
125

l 配置文件

  1. {
  2. "fileList":[
  3. {
  4. "path":"device_config.json"
  5. }
  6. ]
  7. }

格式参数说明如下:
126

1.2 设备信息配置

部署边缘实例时,设备信息配置会被部署到边缘网关,其内容以json格式存储,可以通过leda_get_device_info接口获取。
设备信息配置格式定义:

  1. {
  2. "deviceList": [{
  3. "custom": {
  4. "ip":"127.0.0.1",
  5. "port":22322
  6. }, // 设备自定义配置
  7. "productKey": "xxxxxxxxxxx", // 产品ProductKey,在创建产品时生成
  8. "deviceName": "demo_led", // 设备DeviceName,在创建设备时生成
  9. }]
  10. }

设备信息配置参数说明,如下图所示:
127

1.3 操作步骤

1.3.1 初始化驱动资源

调用leda_init接口完成资源初始化。

  1. int main (int argc, char** argv)
  2. {
  3. ...
  4. /* init driver */
  5. if (LE_SUCCESS != (ret = leda_init(WORKER_THREAD_NUMS)))
  6. {
  7. log_e(TAG_NAME_LED_DRIVER, "leda_init failed\n");
  8. return ret;
  9. }
  10. ...
  11. return LE_SUCCESS;
  12. }

1.3.2 解析驱动配置,完成设备上线

通过leda_get_device_info_size接口和leda_get_device_info接口获取设备配置,按照驱动配置格式解析,根据解析后的驱动配置连接设备并调用leda_register_and_online_by_device_name接口完成设备注册上线到阿里云物联网平台
驱动信息配置格式定义请参见本文上方驱动与设备信息配置内容。

  1. static int online_devices()
  2. {
  3. ... /* 获取驱动设备配置 */``
  4. size = leda_get_device_info_size();
  5. if (size >0)
  6. {
  7. device_config = (char*)malloc(size);
  8. if (NULL == device_config)
  9. {
  10. log_e(TAG_DEMO_LED, "allocate memory failed\n");
  11. return LE_ERROR_INVAILD_PARAM;
  12. }
  13. if (LE_SUCCESS != (ret = leda_get_device_info(device_config, size)))
  14. {
  15. log_e(TAG_DEMO_LED, "get device config failed\n");
  16. return ret;
  17. }
  18. }
  19. /* 解析驱动设备配置 */
  20. devices = cJSON_Parse(device_config);
  21. if (NULL == devices)
  22. {
  23. log_e(TAG_DEMO_LED, "device config parser failed\n");
  24. return LE_ERROR_INVAILD_PARAM;
  25. }
  26. cJSON_ArrayForEach(item, devices)
  27. {
  28. if (cJSON_Object == item->type)
  29. {
  30. /* 解析配置内容 */
  31. result= cJSON_GetObjectItem(item, "productKey");
  32. productKey= result->valuestring;
  33. result= cJSON_GetObjectItem(item, "deviceName");
  34. deviceName= result->valuestring;
  35. result= cJSON_GetObjectItem(item, "custom");
  36. if (NULL != result)
  37. {
  38. log_i(TAG_DEMO_LED, "custom content: %s\n", cJSON_Print(result));
  39. }
  40. /* 注册并上线设备 */
  41. device_cb.get_properties_cb=get_properties_callback_cb;
  42. device_cb.set_properties_cb=set_properties_callback_cb;
  43. device_cb.call_service_cb= call_service_callback_cb;
  44. device_cb.service_output_max_count= 5;
  45. dev_handle=leda_register_and_online_by_device_name(productKey, deviceName, &device_cb, NULL);
  46. if (dev_handle < 0)
  47. {
  48. log_e(TAG_DEMO_LED, "product:%s device:%s register failed\n", productKey, deviceName);
  49. continue;
  50. }
  51. g_dev_handle = dev_handle;
  52. log_i(TAG_DEMO_LED, "product:%s device:%s register success\n", productKey, deviceName);
  53. }
  54. }
  55. ...
  56. return LE_SUCCESS;
  57. }

1.3.3 将收到的设备数据转换为阿里云IoT物模型

格式并上报到物联网平台,调用ledareport_properties接口上报设备属性数据,调用leda_report_event接口上报设备事件。
**
说明** 此处使用虚拟设备,直接构造物模型格式的数据进行上报。_

  1. /* 上报数据 */
  2. while (1)
  3. {
  4. /* 上报属性 */
  5. leda_device_data_t dev_proper_data[1] =
  6. {
  7. {
  8. .type = LEDA_TYPE_INT,
  9. .key = {"temperature"},
  10. .value = {0}
  11. }
  12. };
  13. sprintf(dev_proper_data[0].value, "%d", g_dev_temperature);
  14. leda_report_properties(g_dev_handle, dev_proper_data, 1);
  15. /* 上报事件 */
  16. if (g_dev_temperature > 50)
  17. {
  18. leda_device_data_t dev_event_data[1] =
  19. {
  20. {
  21. .type = LEDA_TYPE_INT,
  22. .key = {"temperature"},
  23. .value = {0}
  24. }
  25. };
  26. sprintf(dev_event_data[0].value, "%d", g_dev_temperature);
  27. leda_report_event(g_dev_handle, "high_temperature", dev_event_data, 1);
  28. }
  29. sleep(5);
  30. }

1.3.4 处理云端服务请求

实现服务请求的三个回调函数如下所示。

  • get接口: 处理获取设备属性的请求。
  • set接口: 处理设置设备属性的请求。
  • service接口:处理调用设备自定义方法的请求。
    说明 本示例使用get_properties_callback_cb、set_properties_callback_cb和call_service_callback_cb三个回调函数实现服务请求。
    1. static int get_properties_callback_cb(device_handle_t device_handle,leda_device_data_t properties[], int properties_count, void *usr_data)
    2. {
    3. ...
    4. return ret;
    5. }
    6. static int set_properties_callback_cb ( device_handle_t device_handle, const leda_device_data_t properties[], int properties_count, void *usr_data)
    7. {
    8. ...
    9. return ret;
    10. }
    11. static int call_service_callback_cb ( device_handle_t device_handle, const char *service_name, const eda_device_data_t data[], int data_count, leda_device_data_t output_data[], void *usr_data)
    12. {
    13. ...
    14. return ret;
    15. }

说明 本示例的完整工程源码请参见Github源码库LED设备驱动

2.驱动打包

设备接入驱动编码完成后,需进行驱动的调试。调试阶段包括:编译打包、上传驱动、创建设备、部署驱动、查看调试信息、调试数据交互和本地替换更新驱动。

2.1 注意事项

基于LinkIoT Edge提供的SDK开发驱动并完成调试后,需将产物打包为.zip包,并确保驱动Binary或index源文件在.zip包第一级目录。
每个版本SDK开发的驱动在打包时,有不同的打包规则。

2.1.1 基于C SDK开发的驱动

对于C语言开发的驱动,驱动包中包含驱动程序和驱动依赖的动态库。如果驱动程序包含依赖库,则需要将依赖库放置指定的位置,即在驱动程序当前路径下的lib文件夹下。具体操作步骤如下:

  1. - 规定驱动程序需命名为main
  2. - main当前路径下创建lib文件夹。
  3. - main依赖的动态库全部拷贝到lib文件夹下。
  4. - 使用zip命令对当前路径下的mainlib进行压缩处理生成zip包。
  1. zip -r your_driver_name.zip main lib

2.1.2 基于Python SDK开发的驱动

驱动包文件中须包含index.py,并且在该文件中定义handler函数。驱动是一个在函数计算引擎中持续运行的函数,所以在驱动包中须包含index.py文件,并且在该文件中定义handler函数。
驱动运行时,会加载index.py文件。而该文件中,函数计算定义的handler函数是不会被调用,因此驱动代码须放在handler函数外,保证加载index.py文件时能直接执行。详情请参考Python版本SDK

2.1.3 基于Node.js SDK开发的驱动

驱动包文件中须包含index.js,并且在该文件中定义handler函数。
驱动运行时,会加载index.js文件。而该文件中,函数计算定义的handler函数是不会被调用,因此驱动代码须放在handler函数外,保证加载index.js文件时能直接执行。详情请参考Nodejs版本SDK

2.2 下载示例代码

  1. git clone https://github.com/aliyun/linkedge-thing-access-sdk-c.git

2.3 代码编译

进入linkedge-thing-access-sdk-c目录,完成示例编译

  1. cd linkedge-thing-access-sdk-c
  2. make prepare && make && make install

2.4 查看示例编译产物

  1. cd build/bin/demo/demo_led/ && ls -l

系统显示类似如下图表示已完成编译并打包。如下图所示:128

2.5 上传驱动

在SI集成工作台si.iot.aliyun.com上,选择设备管理** >网关>协议管理,选择新建协议**。
根据提示设置参数。如下图所示:129130

上传已完成编译并打包的led_driver.zip文件。
完成参数的设置并上传成功驱动文件后,单击确定。您可以在自研驱动列表中看到刚刚创建的驱动。

3.驱动应用

登录SI集成工作台si.iot.aliyun.com,在网关施工页面,点击网关右侧的设置图标,首先,在弹出菜单中选择“添加协议”。如下图所示:131

然后,在下拉选择的协议列表中选择“demo_driver”,选择“确定”。如下图所示:132

3.1 新建设备

如下图所示,通过点击通道右侧的“设置”图标,选择“新建设备”133
如下图所示,进行设备定义:
设备名称:自定义设备名称。
设备别名:自定义设备的别名。
功能定义:用来定义设备的功能,可以选择已有模型(请参照品类管理章节)或者后续添加。
设备配置:编写JSON格式配置内容(内容不可超过1 KB),并校验格式通过后,单击确定134

3.2 功能定义

创建好的设备如下图所列,选择右侧的“功能定义”,根据设备的点位信息为其添加各个功能点。如下图所示:
135

3.1.1 添加属性

为设备的自定义属性设置参数,如下图所示:
136

3.1.2 添加事件

为设备的自定义事件设置参数,如图所示:
137输出参数设置,如下图所示:
138点击确定按钮后,为设备添加的自定义功能,如下图所示:139