本地管理

更新时间:2023-09-06 10:40:14下载pdf

TuyaOS 提供简单的本地访问功能,您可以获取设备列表和设备上报的数据,能够调用接口本地下发指令,主要用于实现网关本地化业务。

数据类型

设备信息结构体

/**
 * @brief 子设备信息结构体。
 */
typedef struct {
    CHAR_T id[DEV_ID_LEN+1]; ///< 设备的唯一标识
    CHAR_T sw_ver[SW_VER_LEN+1]; ///< 设备固件版本号
    CHAR_T schema_id[SCHEMA_ID_LEN+1]; ///< 设备的物模型 ID
    CHAR_T product_key[PRODUCT_KEY_LEN+1]; ///< 设备的产品 ID
    CHAR_T firmware_key[PRODUCT_KEY_LEN+1]; ///< 设备的固件 KEY
    BOOL_T is_oem; ///< 是否是 OEM 设备
    #if defined(ENABLE_SIGMESH) && (ENABLE_SIGMESH==1)
    CHAR_T sigmesh_dev_key[SIGMESH_DEV_KEY_LEN+1]; ///< MESH 子设备 login key
    CHAR_T sigmesh_mac[SIGMESH_DEV_MAC_LEN+1]; ///< MESH 子设备 MAC 地址
    #endif
    CHAR_T virt_id[DEV_ID_LEN+1]; ///< 设备的虚拟 ID
    USER_DEV_DTL_DEF_T uddd; ///< 设备描述 1
    USER_DEV_DTL_DEF_T uddd2; ///< 设备描述 2
    DEV_TYPE_T tp; ///< 设备的类型。1:蓝牙设备;2:Zigbee 设备。
    DEV_SUB_TYPE_T sub_tp; ///< 设备的子类型,目前只有蓝牙设备使用。0:MESH;1:BLE;2:beacon。
    CHAR_T uuid[DEV_UUID_LEN+1]; ///< UUID
    INT_T abi; ///< 设备的能力值
    BOOL_T bind; ///< 设备的绑定状态。TRUE:已绑定;FALSE:未绑定。
    BOOL_T sync; ///< 设备绑定和解绑是否与云端同步。TRUE:已同步;FALSE:未同步。
    #if defined(ENABLE_SIGMESH) && (ENABLE_SIGMESH==1)
    BOOL_T sigmesh_sync; ///< MESH 子设备绑定和解绑是否与云端同步。TRUE:已同步;FALSE:未同步。
    BOOL_T ble_mesh_bind_rept_sync; ///< 忽略该字段
    #endif
    BOOL_T bind_status; ///< 忽略该字段
    BYTE_T attr_num; ///< 设备的属性数组长度
    GW_ATTACH_ATTR_T attr[GW_ATTACH_ATTR_LMT]; ///< 设备的属性数组
    BOOL_T reset_flag; ///< 设备的恢复出厂设置标志位
    #if defined(TUYA_OPERATOR_TYPE) && (TUYA_OPERATOR_TYPE != 0)
    CH_CODE_ST ch_dminfo; ///< 忽略该字段
    #endif
	CHAR_T subList_flag; ///< 忽略该字段
    #if ((!defined(DISABLE_ZIGBEE_LQI)) || (defined(DISABLE_ZIGBEE_LQI) && (DISABLE_ZIGBEE_LQI == 0)))
    DEV_QOS_ST dev_qos; ///< 忽略该字段
    #endif
    CHAR_T schema_flag; ///< 忽略该字段
    CHAR_T schema_sync; ///< 忽略该字段
    CHAR_T schema_ver[SCHEMA_VER_LEN+1]; ///< 忽略该字段
    UINT_T dev_attr; ///< 忽略该字段
    #if defined(ENABLE_SIGMESH) && (ENABLE_SIGMESH==1)
    TY_SUBDEV_BIND_OPTIONS options; ///< 忽略该字段
    #endif
} DEV_DESC_IF_S;

DP 数据结构体

/**
 * @brief DP 数据结构体。
 */
typedef struct {
    BYTE_T dpid;             ///< DP ID
    DP_PROP_TP_E type;       ///< DP 类型
    TY_OBJ_DP_VALUE_U value; ///< DP 值
    UINT_T time_stamp;       ///< 时间戳
} TY_OBJ_DP_S;

/**
 * @brief DP 值联合体。
 */
typedef union {
    INT_T dp_value;   ///< DP 类型为 PROP_VALUE,该字段有效
    UINT_T dp_enum;   ///< DP 类型为 PROP_ENUM,该字段有效
    CHAR_T *dp_str;   ///< DP 类型为 PROP_STR,该字段有效
    BOOL_T dp_bool;   ///< DP 类型为 PROP_BOOL,该字段有效
    UINT_T dp_bitmap; ///< DP 类型为 PROP_BITMAP,该字段有效
} TY_OBJ_DP_VALUE_U;

控制指令结构体

/**
 * @brief OBJ 类型控制指令结构体。
 * @note OBJ 类型指令可以包含多个 DP 数据。
 */
typedef struct {
    DP_CMD_TYPE_E cmd_tp;   ///< 消息源。0:局域网;1:云端;2:定时;3:联动;4:重传。本地控制填充 0 即可。
    DP_TRANS_TYPE_T dtt_tp; ///< 消息类型。0:单播;1:广播;2:组播;3:联动。
    CHAR_T *cid;            ///< 设备唯一标识符,对应 DEV_DESC_IF_S->id。
    CHAR_T *mb_id;          ///< dtt_tp 为组播时,该字段有效,表示组 ID。
    UINT_T dps_cnt;         ///< DP 数据的长度。
    TY_OBJ_DP_S dps[0];     ///< DP 数据。
} TY_RECV_OBJ_DP_S;

/**
 * @brief RAW 类型控制指令结构体。
 * @note RAW 类型指令只能包含单个 DP 数据。
 */
typedef struct {
    DP_CMD_TYPE_E cmd_tp;   ///< 消息源。0:局域网;1:云端;2:定时;3:联动;4:重传。本地控制填充 0 即可。
    DP_TRANS_TYPE_T dtt_tp; ///< 消息类型。0:单播;1:广播;2:组播;3:联动。
    CHAR_T *cid;            ///< 设备唯一标识符,对应 DEV_DESC_IF_S->id。
    BYTE_T dpid;            ///< DP ID。
    CHAR_T *mb_id;          ///< dtt_tp 为组播时,该字段有效,表示组 ID。
    UINT_T len;             ///< RAW 数据长度。
    BYTE_T data[0];         ///< RAW 数据。
}TY_RECV_RAW_DP_S;

接口描述

允许子设备入网

/**
 * @brief 允许子设备入网接口。
 * @note 使用该接口可以让涂鸦网关模组处于开启配网或者关闭配网状态。
 *
 * @param[in] tp 子设备类型,一般不用区分,填入 255 即可。
 * @param[in] permit 是否开启配网。TRUE:开启,FALSE:关闭。
 * @param[in] timeout 配网超时时间,只有当 permit = TRUE 时有效。
 */
OPERATE_RET tuya_iot_dev_join_permit(GW_PERMIT_DEV_TP_T tp, BOOL_T permit, UINT_T timeout);

获取子设备信息

/**
 * @brief 获取单个子设备的设备信息接口。
 *
 * @param[in] dev_id 子设备唯一标识,可以从遍历设备列表接口获取。
 *
 * @return (DEV_DESC_IF_S *):子设备信息,NULL:找不到子设备。
 */
DEV_DESC_IF_S *tuya_iot_get_dev_if(IN CONST CHAR_T *dev_id);

遍历子设备列表

/**
 * @brief 遍历子设备列表接口。
 * @note 使用该接口可以获取网关下的所有子设备的设备信息。
 *
 * @param[out] iterator 迭代器。
 *
 * @return (DEV_DESC_IF_S *):子设备信息,NULL:遍历结束。
 */
DEV_DESC_IF_S *tuya_iot_dev_traversal(INOUT VOID **iterator);

获取上报数据

/**
 * @brief 数据上报回调结构体。
 */
typedef struct {
    VOID (*obj_dp_rept_cb)(CONST CHAR_T *dev_id, CONST TY_OBJ_DP_S *dps, CONST UINT_T dp_cnt); ///< obj 类型 DP
    VOID (*raw_dp_rept_cb)(CONST CHAR_T *dev_id, BYTE_T dpid, CONST BYTE_T *data, UINT_T len); ///< raw 类型 DP
} TY_DP_REPORT_CBS_S;

/**
 * @brief 注册数据上报回调接口。
 * @note 获取子设备的上报数据是通过回调方式实现,子设备上报数据会触发回调函数。数据为涂鸦标准 DP 模型。
 *
 * @param[in] cbs 回调接口。
 */
OPERATE_RET tuya_iot_reg_dp_report_cb(TY_DP_REPORT_CBS_S *cbs);

下发控制指令

/**
 * @brief 下发 OBJ 类型控制指令接口。
 * @note 指令为涂鸦标准 DP 模型。
 *
 * @param[in] cmd OBJ 类型指令。
 */
OPERATE_RET tuya_iot_dev_obj_cmd_send(CONST TY_RECV_OBJ_DP_S *cmd);

/**
 * @brief 下发 RAW 类型控制指令接口。
 * @note 指令为涂鸦标准 DP 模型。
 *
 * @param[in] cmd RAW 类型指令。
 */
OPERATE_RET tuya_iot_dev_raw_cmd_send(CONST TY_RECV_RAW_DP_S *cmd);

使用示例

获取子设备信息

VOID test_subdev_info(VOID)
{
	DEV_DESC_IF_S *dev_if = NULL;

	dev_if = tuya_iot_get_dev_if("112233aabbcc");
	if (dev_if == NULL) {
		PR_ERR("dev is not found");
		return;
	}
	PR_DEBUG("id: %s, type: %d, pid: %s, version: %s", dev_if->id, dev_if->tp, \
	                                                   dev_if->product_key, dev_if->sw_ver);
}

遍历子设备列表

VOID test_subdev_list(VOID)
{
    DEV_DESC_IF_S *dev_if = NULL;
    VOID *iterator = NULL;

    do {
        dev_if = tuya_iot_dev_traversal(&iterator);
        if (dev_if) {
            PR_DEBUG("id: %s, type: %d", dev_if->id, dev_if->tp);
        }
    } while(dev_if);
}

获取上报数据

STATIC VOID __obj_dp_rept_cb(CONST CHAR_T *dev_id, CONST TY_OBJ_DP_S *dps, CONST UINT_T dp_cnt)
{
    PR_DEBUG("report data, dev_id: %s", dev_id);

    for (INT_T i = 0; i < dp_cnt; i++) {
        PR_DEBUG("dpid: %d", dps[i].dpid);
        switch (dps[i].type) {
        case PROP_BOOL:
            PR_DEBUG("dp_bool value: %d", dps[i].value.dp_bool);
            break;
        case PROP_VALUE:
            PR_DEBUG("dp_value value: %d", dps[i].value.dp_value);
            break;
        case PROP_ENUM:
            PR_DEBUG("dp_enum value: %d", dps[i].value.dp_enum);
            break;
        case PROP_STR:
            PR_DEBUG("dp_str value: %s", dps[i].value.dp_str);
            break;
        }
    }
}

VOID test_subdev_report(VOID)
{
    OPERATE_RET op_ret = OPRT_OK;

    TY_DP_REPORT_CBS_S __dp_report_cbs = {
        .obj_dp_rept_cb = __obj_dp_rept_cb,
    };

    op_ret = tuya_iot_reg_dp_report_cb(&__dp_report_cbs);
    if (op_ret != OPRT_OK) {
        PR_ERR("tuya_iot_reg_dp_report_cb err: %d", op_ret);
        return;
    }
}

下发控制指令

VOID test_subdev_cmd(VOID)
{
    UINT_T dp_cnt = 3;
    TY_RECV_OBJ_DP_S *obj_cmd = NULL;

    obj_cmd = Malloc(SIZEOF(TY_RECV_OBJ_DP_S) + dp_cnt * SIZEOF(TY_OBJ_DP_S));
    if (obj_cmd == NULL) {
        PR_ERR("Malloc error");
        return;
    }

    obj_cmd->cid = "112233aabbcc";
    obj_cmd->cmd_tp = DP_CMD_LAN;
    obj_cmd->dtt_tp = DTT_SCT_UNC;
    obj_cmd->dps_cnt = dp_cnt;

    for (INT_T i = 0; i < dp_cnt; i++) {
        obj_cmd->dps[i].dpid = (i + 1);
        obj_cmd->dps[i].type = PROP_BOOL;
        obj_cmd->dps[i].value.dp_bool = TRUE;
    }

    tuya_iot_dev_obj_cmd_send(obj_cmd);

    Free(obj_cmd);
}