全屋边缘网关SDK开发指南

更新时间:2020-03-17 16:45:04

一 VDA SDK接口

VDA(Vendor Device Access) SDK提供给厂商设备接入阿里人居云端服务的能力,主要有设备上云、数据流转等功能,厂商基于VDA SDK开发出厂商设备对应的driver程序,此driver程序负责与子设备通信。例如,当子设备状态变化时,调用vda_sdk_post_properties或vda_sdk_trigger_event接口上报数据。SDK功能接口都定义在linkedge/include/vda_sdk.h里面,具体说明如下。

1 VDA接口函数

1.1 系统函数

1.1.1 获取系统默认参数

vda_sdk_params_t * vda_sdk_get_default_params (void)

函数功能:获得默认的系统参数,获得的返回值(vda_sdk_params_t类型指针)不需要手动释放。
函数返回值:默认参数值

typedef struct vda_sdk_params_s vda_sdk_params_t;
获得的系统默认参数由vda_sdk_params_s结构体变量表示。具体内容如下:

struct vda_sdk_params_s {
    int maxMsgSize;      //最大消息长度 默认 20480
    int threadStackSize; //线程栈大小
    int log_to_file;     //log 输出文件
    int (event_cb) (vda_sdk_event_t ev, void *ctx); //属性事件处理回调函数集合,ev:传递事件+事件参数
    void *ctx;           //传递给回调函数的参数
}

1.1.2 修改系统参数

int vda_sdk_set_option (vda_sdk_params_t params, int option, void value, int value_len)

函数功能:对VDA SDK的默认系统参数进行修改
函数描述:

  • @param params 系统参数,调用vda_sdk_get_default_params函数的返回值,为系统当前的默认参数值

  • @param option 属性修改选项

option 选项 Default minimum maximum
VDA_OPT_MAX_MSG_SIZE 最大消息长度 20480 512 51200
VDA_OPT_THREAD_STACK_SIZE 线程栈大小 8192 1024 8388608
VDA_OPT_LOG_TO_FILE SDK的log打印方式,0为标准输出,1为输出到文件 1 0 1
  • @param value 对应属性选项要设置的数值

  • @param value_len 数值长度

函数返回值:设置成功返回0,失败返回 -1

1.1.3 设置系统事件回调函数

int vda_sdk_set_event_callback (vda_sdk_params_t* params, event_cb, void *ctx)

函数功能:通过注册事件回调函数来监听系统的内部状态变化,通过下面的接口设置回调函数。
函数描述:

  • @param params 系统参数,vda_sdk_get_default_params(.html)函数获取的返回值

  • @param event_cb 事件发生时的回调函数

  • @param ctx 传递给回调函数的数据

函数返回值:设置成功返回0,失败返回 -1
注意:vda_sdk_set_event_callback在调用vda初始化函数前设置好回调函数,否则回调无法生效。

int (event_cb)(vda_sdk_event_t ev, void *ctx)回调函数参数如下:

其中event_type为事件类型,event_data为对应的数据。
event_data 为union类型,SDK会根据不同的事件类型给event_data的对应成员赋值

typedef struct {
    int event_type;    //对应事件类型
        union {
            struct {
            char *productKey;
            char *deviceName;
            } dev_deleted;       //VDA_EVENT_DEVICE_DELETED
                    ...
          ...
          ...
        } event_data;   //传递事件相关的数据
} vda_sdk_event_t

事件类型:
enum {
    VDA_EVENT_CLOUD_DISCONNECTED = 0,   / cloud disconnected  /
    VDA_EVENT_CLOUD_CONNECTED    = 1,   / cloud connected     /
    VDA_EVENT_DEVICE_DELETED     = 2,   / device deleted      /
    VDA_EVENT_DEVICE_PERMITED     = 3,   / device permit join  /
    VDA_EVENT_DEIVCE_SETUP        = 4,   / device install      /
    VDA_EVENT_DEVICE_DISCOVER     = 5,   / device discover     /
    VDA_EVENT_DEVICE_RESET        = 6,   / device reset        /
};

1.1.4 VDA初始化

int vda_sdk_init(const char *module_name, vda_sdk_params_t *params)

函数功能:VDA接口初始化
函数描述:

  • @param module_name 此模块的名称,用于内部标识。

  • @param params 系统参数,vda_sdk_get_default_params函数获取的返回值。

函数返回值:设置成功返回0,失败返回 -1

1.1.5 VDA退出

int vda_sdk_exit (void)

函数功能:退出VDA实例
函数返回值:成功返回0,失败返回 -1

1.1.6 注册设备配置信息变化(可选)

int vda_sdk_register_config_changed_callback(const char *module_name, cb)

函数功能:注册驱动配置变化回调(可选),可以通过这个函数修改注册设备配置变化回调函数。
函数描述:

int (cb)(const char module_name, const char *config)
module_name可以不是当前驱动的名字。但与module_name相关的驱动配置推送到边缘网关时,回调函数cb将被调用。
函数返回值:成功返回0,失败返回 其他

1.2 设备创建与管理

1.2.1 设备注册

int vda_sdk_device_register(const char *productKey, const char *deviceName,vda_sdk_cbs_t *cbs , void *ctx)

函数功能:设备注册,并设定设备对应功能的回调函数。调用此接口完成子设备注册并上线。
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param deviceName 设备的设备名称,即dn

  • @param cbs 要设置的回调函数, 回调函数的集合,用于处理下行的数据

  • @param ctx 传递给回调函数的参数

函数返回值:成功返回0,失败返回 -1

typedef struct {
    int (get_property)(const char in, char out, int out_len, void ctx);
    int (set_property)(const char in, void *ctx);
    int (call_service)(const char identifier, const char in, char out, int out_len, void *ctx);
    ssize_t (down_rawdata)(const void in, int in_len, void out, int out_len, void ctx);
} vda_sdk_cbs_t

注意: 如果在云端创建的产品是ICA协议的,上述的结构体只需要设置get_property,set_property和call_service三个函数指针;如果创建的产品是透传的,上述结构体只需要设置down_rawdata这个函数指针。目前不支持四个函数指针都设置。

1.2.2 设备上线

int vda_sdk_device_online(const char *productKey, const char *name)

函数功能:设置设备为上线状态
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param name 设备的设备名称,即dn

函数返回值:成功返回0,失败返回 -1

1.2.3 设备下线

int vda_sdk_device_offline(const char *productKey, const char *name)

函数功能:设置设备为下线状态
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param name 设备的设备名称,即dn

函数返回值:成功返回0,失败返回 -1

1.2.4 上报设备属性

int vda_sdk_post_properties(const char *productKey, const char *name, const char *properties)

函数功能:将设备的属性变更发布到云端
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param name 设备的设备名称,即dn

  • @param properties 属性数据,json格式

函数返回值:成功返回0,失败返回 -1

1.2.5 上报设备事件

int vda_sdk_trigger_event(const char *productKey, const char *name, const char *identifier, const char *events)

函数功能:将设备的事件发布到云端
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param name 设备的设备名称,即dn

  • @param identifier 事件的标识符,有关事件标识符的详细信息,请参见TSL

  • @param properties 属性数据,json格式

函数返回值:成功返回0,失败返回 -1

1.2.6 上报设备的原始数据

int vda_sdk_post_rawdata(const char *productKey, const char *name, const char *data, int len)

函数功能:将设备的原始数据发布到云端。
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param name 设备的设备名称,即dn

  • @param data 发布的原始数据。

  • @param len 发布数据的长度。

函数返回值:成功返回0,失败返回 -1

1.2.7 获取网关子设备列表大小

int vda_sdk_get_devicelist_size()

函数功能:从设备管理模块获取子设备列表的大小
函数返回值:返回设备列表大小,大于0即为成功

1.2.8 获取网关子设备列表

int vda_sdk_get_devicelist(char *buff, int size)

函数功能:从设备管理模块获取子设备列表
函数描述:

  • @param buff 设备列表的缓冲区

  • @param size 缓冲区的大小,通过vda_sdk_get_devicelist_size函数获取

函数返回值: 成功返回 0,-1 internal error,-2 size of buffer too samll

1.2.9 重置网关或子设备数据

int vda_sdk_device_reset(const char *productKey, const char *deviceName)

函数功能:重置网关,解除包括网关与全部子设备的拓扑关系,网关与用户的关联关系;重置网关子设备,解除包括子设备与网关的拓扑关系,子设备与用户的关联关系。
函数描述:

  • @param productKey 设备的产品ID,即pk

  • @param deviceName 设备的设备名称,即dn

函数返回值:成功返回0,失败返回 -1

2 使用流程

2.1 接口初始化

SDK的初始化包括以下步骤
1、获取默认参数
调用系统接口vda_sdk_get_default_params获得默认的系统参数,获得的默认参数不需要释放。

sample:
vda_sdk_params_t *params;
...
params = vda_sdk_get_default_params();

2、修改默认参数
调用vda_sdk_set_option接口,对SDK的默认参数进行修改。

sample:
int opt_val;
...
...
opt_val = 8192;
if (vda_sdk_set_option(params, VDA_OPT_MAX_MSG_SIZE, &opt_val, sizeof(opt_val)) < 0) {
        log_e(TAG`, "set VDA_OPT_MAX_MSG_SIZE failed!\n");
        return -1;
}//设置最大消息队列大小为8192

opt_val = 0;
if (vda_sdk_set_option(params, VDA_OPT_LOG_TO_FILE, &opt_val, sizeof(opt_val)) < 0) {
        log_e(TAG, "set VDA_OPT_LOG_LEVEL failed!\n");
        return -1;
}//设置系统输出路径为标准输出

3、设置事件回调
SDK通过注册事件回调来通知用户SDK的内部状态变化,通过下面的接口设置SDK的回调函数。 vda_sdk_set_event_callback(params, event_cb, NULL)
回调函数的示例代码

static int event_cb(vda_sdk_event_t ev, void ctx)
{
log_i(DRIVER_NAME, "event %d", ev->event_type);
switch (ev->event_type) {
    case VDA_EVENT_CLOUD_CONNECTED:
        /*在此处处理成功连接云连接的消息*/
        break;

    case VDA_EVENT_CLOUD_DISCONNECTED:
        /*在此处处理断开云连接的消息,消息通知存在几分钟延时*/
        break;

    case VDA_EVENT_DEVICE_DELETED:
        /*处理删除子设备,此时使用的是event_data的dev_deleted成员结构体*/
        devmgr_destroy_device(ev->event_data.dev_deleted.productKey, ev->event_data.dev_deleted.deviceName);
        break;

    case VDA_EVENT_DEVICE_PERMITED:
        /*云端下发添加网关子设备的消息通知*/
        break;
    }
return 0;
}

注意: vda_sdk_set_event_callback需要在调用vda_sdk_init前设置好回调函数,否则回调无法生效。

4、初始化VDA接口
调用vda_sdk_init对SDK进行初始化。
在设置好初始化参数以后,可以将初始化参数作为vda_sdk_init的输入参数,对SDK进行初始化。

vda_sdk_init (DRIVER_NAME, params);

5、注册驱动配置变化回调(可选)
通过vda_sdk_register_config_changed_callback这个函数注册驱动配置变化回调。

2.2 功能调用

2.2.1 设备的创建和管理

VDA初始化时设定好相应的系统事件回调处理函数后,在事件VDA_EVENT_DEVICE_PERMITED消息中获取待绑定的子设备的pk信息,再调用设备注册函数将获取到子设备进行注册上线。

sample:
vda_sdk_device_register("productKey", "deviceName", cbs, Interface);
//cbs为子设备操作回调函数,Interface为传递给回调函数的参数

2.2.2 设备属性和事件上报

ICA设备属性和事件上报
事件上报:
事件的构成有2部分:
(1)用于标识事件类型的identifier
(2)事件对应的数据

SDK事件上报的接口和调用示例如下:
int vda_sdk_trigger_event(const char productKey, const char name, const char identifier, const char events);

sample:
vda_sdk_trigger_event("productKey", "deviceName", "ErrorCode", "{"ErrorCode": 0}")

属性上报:
当设备的属性发生了变化,可以调用如下的接口上报变更的属性
int vda_sdk_post_properties(const char productKey, const char name, const char *properties);

例如子设备为单键开关类型,子设备属性上报示例如下:

sample:
vda_sdk_post_properties("productKey", "deviceName", ""PowerSwitch_1":0")

透传设备属性与事件上报
设备的原始数据可以通过以下接口上报给云端,需要在云端添加数据解析脚本,来转换原始数据格式到ICA Alink格式。

int vda_sdk_post_rawdata(const char productKey, const char name, const char *data, int len);

sample:
memset(hex_buffer, 0, sizeof(hex_buffer));
rawdata_len = str_to_hex(arg_properties, strlen(arg_properties), hex_buffer, sizeof(hex_buffer));
if (vda_sdk_post_rawdata(productKey, deviceName, hex_buffer, rawdata_len) < 0) {
printf("post rawdata failed!\n");
continue;
}

二 HAL接口

HAL接口需要设备厂商实现,接口定义在linkedge/include/hal.h里面,用来提供设备上云需要的网关设备证书信息(ProductKey\DeviceName\DeviceSecret),用于网关系统整体升级的网关固件版本信息和固件升级相关的接口。
厂商实现HAL的功能函数后,编译生成libhal.so文件,替换掉linkedge/lib/libhal.so文件,重启linkedge即可生效。

1.1 函数定义

HAL_GetProductKey 获取网关的ProductKey
HAL_GetDeviceName 获取网关的DeviceName
HAL_GetDeviceSecret 获取网关的DeviceSecret
HAL_GetFirmwareVersion 获取网关系统版本号
HAL_UpdateFirmware 由厂商接收固件文件并进行升级
HAL_RebootSystem 网关系统重启

int HAL_GetProductKey(char productKey[PRODUCT_KEY_MAXLEN]);

int HAL_GetDeviceName(char device_name[DEVICE_NAME_MAXLEN]);

int HAL_GetDeviceSecret(char device_secret[DEVICE_SECRET_MAXLEN]);

int HAL_GetFirmwareVersion(char version[FIRMWARE_VERSION_MAXLEN]);

int HAL_UpdateFirmware(const char *filename);

int HAL_RebootSystem(void);

1.2 示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include "hal.h"

#ifndef TAG
#define TAG "HAL"
#endif

static int get_project_root(char *dir)
{
    static char abs_proj_root[FILENAME_MAX + 1] = "../";
    char rel_proj_root[FILENAME_MAX + 1];
    int len = readlink("/proc/self/exe", rel_proj_root, FILENAME_MAX);
    if (len <= 0) {
        return 1;
    }
    rel_proj_root[len] = '\0';
    char *path_end = strrchr(rel_proj_root, '/');
    if (path_end) {
        *path_end = '\0';
    }
    strcat(rel_proj_root, "/../");
    char *real_path = realpath(rel_proj_root, abs_proj_root);
    if (NULL == real_path) {
        strcpy(dir, rel_proj_root);
        return 1;
    }
    strcpy(dir, abs_proj_root);

    return 0;
}

static int get_file_content(char *file_path, char *content, int size)
{
    FILE *fp = NULL;
    fp = fopen(file_path, "r");
    if (fp != NULL)
    {
        char *line = NULL;
        if (size > 0) line = malloc(size);
        if (line && fgets(line, size, fp) != NULL)
        {
            char *find = strchr(line, '\n');
            if(find) *find = '\0';
            strncpy(content, line, size - 1);
        }
        fclose(fp);
        fp = NULL;
        free(line);
        line = NULL;
    }
    return 0;
}

int HAL_GetProductKey(char productKey[PRODUCT_KEY_MAXLEN])
{
    char file_path[FILENAME_MAX + 1] = { 0 };
    get_project_root(file_path);
    strcat(file_path, "/config/gateway_pk");
    printf("gateway product key file path is %s\n", file_path);

    memset(productKey, 0, PRODUCT_KEY_MAXLEN);
    get_file_content(file_path, productKey, PRODUCT_KEY_MAXLEN);
    return strlen(productKey);
}

int HAL_GetDeviceName(char deviceName[DEVICE_NAME_MAXLEN])
{
    char file_path[FILENAME_MAX + 1] = { 0 };
    get_project_root(file_path);
    strcat(file_path, "/config/gateway_dn");
    printf("gateway product key file path is %s\n", file_path);

    memset(deviceName, 0, DEVICE_NAME_MAXLEN);
    get_file_content(file_path, deviceName, DEVICE_NAME_MAXLEN);
    return strlen(deviceName);
}

int HAL_GetDeviceSecret(char deviceSecret[DEVICE_SECRET_MAXLEN])
{
    char file_path[FILENAME_MAX + 1] = { 0 };
    get_project_root(file_path);
    strcat(file_path, "/config/gateway_ds");
    printf("gateway product key file path is %s\n", file_path);

    memset(deviceSecret, 0, DEVICE_SECRET_MAXLEN);
    get_file_content(file_path, deviceSecret, DEVICE_SECRET_MAXLEN);
    return strlen(deviceSecret);
}

int HAL_GetFirmwareVersion(char version[FIRMWARE_VERSION_MAXLEN])
{
    strncpy(version, "1.0", FIRMWARE_VERSION_MAXLEN - 1);
    return strlen(version);
}

int HAL_UpdateFirmware(const char *filename)
{
    int fd = open(filename, O_RDONLY);

    if (fd < 0) {
        printf("Open firmware file %s failed %s\n", filename, strerror(errno));
        return -1;
    }

    printf("Updating firmware...\n");
    sleep(3);

    close(fd);

    printf("Upgrade firmware success\n");
    return 0;
}

int HAL_RebootSystem(void)
{
    printf("Rebooting system...\n");

    return 0;
}

1.3 编译命令参考

gcc -fPIC -shared hal.c -o libhal.so

三 日志接口

全屋边缘网关的日志采用集中式管理,日志接口定义在linkedge/include/logger.h里面,例如log_d接口用来打印debug级别的日志,log_e接口用来打印错误级别的日志。厂商可选用此方式来输出driver程序日志信息。日志存储在linkedge/run/logger目录下,以程序模块名称分类。默认日志大小为10M,写满后自动循环滚动。

results matching ""

    No results matching ""