TuyaOS
DP 模型

DP 点是涂鸦 IoT 平台对功能点的定义。开发者可以在涂鸦 IoT 平台创建产品,并根据开发者的需求,定义产品功能和功能点的特征,每一个功能点,就是一个 DP 点。产品的 DP 点的集合,是产品的业务模型,也被称为产品的 Schema。当设备在涂鸦 IoT 平台激活的时候,通过激活时候所携带的产品创建所得的 PID 信息,可以获得产品的 Schema 信息。TuyaOS 会根据 Schema 信息创建设备的能力列表,并在后续的日常运行过程中根据设备的能力,处理 DP 的上报和下发。

DP 点支持布尔型(bool)、数值型(value)、字符串型(string)、枚举型(enum)、故障型(bitmap),RAW 型数据,像定义 C 变量一样简单。其中布尔型(bool)、数值型(value)、字符串型(string)、枚举型(enum)、故障型(bitmap)又被称为 obj 型。使用 DP 点的时候应注意:

  • 目前建议每个产品最多创建 35 个 dp,复杂功能请用 RAW 型数据实现;
  • objDP 上报的时候,会对上报的数值进行过滤,相同则不予上报;
  • 如果想上报相同的 objDP,可以通过带 force 的接口上报,或者将 DP 点定义为统计类型(stat)

DP通道

DP下发和上报支持蓝牙、局域网和涂鸦MQTT三个通道,三个通道同时处理会造成DP处理逻辑复杂化,并造成流量、功耗的增加,因此DP处理的通道存在一定的逻辑策略。

通道 策略
MQTT 上报:当MQTT通道在线的时候,永远会通过MQTT上报
下发:当MQTT通道在线,且LAN不在线,会通过MQTT通道下发;LAN在线,不会通过MQTT通道下发
LAN 上报:当LAN通道在线的时候,永远会通过LAN上报
下发:当LAN通道在线,只会通过LAN通道下发
BLE 上报:仅当MQTTLAN都不在线的情况,会通过BLE上报
下发:仅当MQTTLAN都不在线的情况,会通过BLE下发

DP下发

初始化DP回调

TuyaOS 在初始化的时候,会需要开发者提供 TY_IOT_CBS_S,其中包括三个回调函数,用于处理 TuyaOS 里接受到的DP相关的命令,具体用途如下。开发者根据自己的实际功能需要,实现相应的回调,并在设备初始化的时候注册到 TuyaOS

回调名称 功能描述
dev_obj_dp_cb 结构化DP接受处理回调,结构化DP即DP有明确的类型定义
dev_raw_dp_cb raw型DP接受处理回调,raw型DP即二进制数据流
dev_dp_query_cb DP查询回调,用于查询设备实际的DP的值

DP下发处理流程

通过向设备下发 DP 点可以对设备进行控制, TuyaOS 可以支持从蓝牙、局域网、涂鸦云 MQTT 三条通道来的 DP 信息,在 TuyaOS 里对收到的 DP 校验处理,然后调用相应的回调接口,告知应用层收到相应的DP命令,交于应用层对DP命令进行处理,处理流程如下图所示。

DP下发.png

DP上报

设备产生的状态、数据,以及 DP 下发操作执行结果可以上报,通过 TuyaOS 提供的 DP 上报接口,并在 TuyaOS 内部对上报的 DP 进行校验和流控,然后通过对应通道进行上报。

DP上报.png

接口描述

上报DP

上报 DP 点,针对不同类型的DP点,行为不同:

  • T_OBJ_REPT:该接口会对需要上报的 DP 进行重复性校验,即如果 DP 点的值和上次上报的值一样,不会进行上报。该接口会对上报的数据进行缓存。此接口上报是异步上报,即上报发起即返回,不关心上报的结果。
  • T_RAW_REPT:该接口不会对需要上报的 DP 进行重复性校验,即如果 DP 点的值和上次上报的值一样,也依然会进行上报。该接口不会对上报的数据进行缓存,因为数据量一般会比较大。此接口上报是同步上报,即上报成功或者超时时间到了之后才会进行返回。
  • T_STAT_REPT:该接口不会对需要上报的 DP 进行重复性校验,即如果 DP 点的值和上次上报的值一样,也依然会进行上报。该接口会对上报的数据进行缓存,但仅缓存最后一次上报的结果,因此在实现统计类型的DP上报的时候,需要考虑上报失败的时候缓存数据。此接口上报是同步上报,即上报成功或者超时时间到了之后才会进行返回。

如果是查询上报,即通过dev_dp_query_cb产生的上报行为,需要将is_query设置为TRUE。

OPERATE_RET ty_dp_report(IN CONST DP_REPT_TYPE_E dp_rept_type, IN VOID_T* dp_rept, IN CONST BOOL_T is_query);
OPERATE_RET ty_dp_report(IN CONST DP_REPT_TYPE_E dp_rept_type, IN VOID_T *dp_rept)
Report dp data

使用示例

// 上报 OBJ 型 DP
OPERATE_RET dev_report_dp_json_async(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
{
TY_OBJ_DP_REPT_S obj_dp = {{(CHAR_T *)dev_id, (TY_OBJ_DP_S *)dp_data, cnt}, FALSE};
return ty_dp_report(T_OBJ_REPT, (VOID_T*)&obj_dp, FALSE);
}
// 强制上报 OBJ 型 DP
OPERATE_RET dev_report_dp_json_async_force(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
{
TY_OBJ_DP_REPT_S obj_dp = {{(CHAR_T *)dev_id, (TY_OBJ_DP_S *)dp_data, cnt}, TRUE};
return ty_dp_report(T_OBJ_REPT, (VOID_T*)&obj_dp, FALSE);
}
// OBJ 类型的 DP 上报
OPERATE_RET sample_objdp_test()
{
OPERATE_RET rt = OPRT_OK;
INT_T dp_idx = 0;
TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(2*SIZEOF(TY_OBJ_DP_S));
if(NULL == dp_arr) {
PR_ERR("malloc failed");
return OPRT_MALLOC_FAILED;
}
memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));
dp_arr[dp_idx].dpid = 1;
dp_arr[dp_idx].type = PROP_BOOL;
dp_arr[dp_idx].time_stamp = 0;
dp_arr[dp_idx].value.dp_bool = TRUE;
dp_idx ++;
dp_arr[dp_idx].dpid = get_channel_cddpid(ch_idx);
dp_arr[dp_idx].type = PROP_VALUE;
dp_arr[dp_idx].time_stamp = 0;
dp_arr[dp_idx].value.dp_value = 0;
dp_idx ++;
// 一次上报两个DP
TUYA_CALL_ERR_LOG(dev_report_dp_json_async(get_gw_cntl()->gw_if.id, dp_arr, 2));
// 再次上报(上报不成功,因为没有变化)
TUYA_CALL_ERR_LOG(dev_report_dp_json_async(get_gw_cntl()->gw_if.id, dp_arr, 2));
// 强制上报(可以上报成功)
TUYA_CALL_ERR_LOG(dev_report_dp_json_async_force(get_gw_cntl()->gw_if.id, dp_arr, 2));
Free(dp_arr);
dp_arr = NULL;
return rt;
}
// 上报 RAW 型 DP
OPERATE_RET dev_report_dp_raw_sync(IN CONST CHAR_T *dev_id, IN CONST BYTE_T dpid,
IN CONST BYTE_T *data, IN CONST UINT_T len,
IN CONST UINT_T timeout)
{
TY_RAW_DP_REPT_S obj_dp = {(CHAR_T *)dev_id, dpid, (BYTE_T *)data, len, NULL, timeout};
return ty_dp_report(T_RAW_REPT, (VOID_T*)&obj_dp, FALSE);
}
// RAW 类型的 DP 上报
void sample_rawdp_test(void)
{
OPERATE_RET rt = OPRT_OK;
CHAR_T tmp_buf[1024] = {0x0};
// 上报成功
TUYA_CALL_ERR_LOG(dev_report_dp_raw_sync(NULL, 1, tmp_buf, BUFFER_LEN, 3));
// 上报成功,不会检测重复,总是上报
TUYA_CALL_ERR_LOG(dev_report_dp_raw_sync(NULL, 1, tmp_buf, BUFFER_LEN, 3));
return rt;
}
// 上报 STAT 型 DP
OPERATE_RET dev_report_dp_stat_sync(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt, IN CONST UINT_T timeout)
{
TY_STAT_DP_REPT_S obj_dp = {{(CHAR_T *)dev_id, (TY_OBJ_DP_S *)dp_data, cnt}, timeout};
return ty_dp_report(T_STAT_REPT, (VOID_T*)&obj_dp, FALSE);
}
// STAT 类型的 DP 上报
void sample_statdp_test(void)
{
OPERATE_RET rt = OPRT_OK;
INT_T dp_idx = 0;
TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(2*SIZEOF(TY_OBJ_DP_S));
if(NULL == dp_arr) {
PR_ERR("malloc failed");
return OPRT_MALLOC_FAILED;
}
memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));
dp_arr[dp_idx].dpid = 1;
dp_arr[dp_idx].type = PROP_BOOL;
dp_arr[dp_idx].time_stamp = 0;
dp_arr[dp_idx].value.dp_bool = TRUE;
dp_idx ++;
dp_arr[dp_idx].dpid = 2;
dp_arr[dp_idx].type = PROP_VALUE;
dp_arr[dp_idx].time_stamp = 0;
dp_arr[dp_idx].value.dp_value = 0;
dp_idx ++;
// 一次上报两个DP
TUYA_CALL_ERR_LOG(dev_report_dp_stat_sync(get_gw_cntl()->gw_if.id, dp_arr, 2, 3, NULL));
// 上报成功,不会检测重复,总是上报
TUYA_CALL_ERR_LOG(dev_report_dp_stat_sync(get_gw_cntl()->gw_if.id, dp_arr, 2, 3, NULL));
return rt;
}
// 接收 OBJ DP 处理回调 dev_obj_dp_cb
VOID test_DEV_OBJ_DP_CMD_CB(IN CONST TY_RECV_OBJ_DP_S *dp)
{
PR_DEBUG("SOC Rev DP Obj Cmd t1:%d t2:%d CNT:%u", dp->cmd_tp, dp->dtt_tp, dp->dps_cnt);
// TBD...
// 开发者可以在这里实现真实的 DP 对应功能的操作
// 默认实现是简单的把收到的DP上报上去,认为处理全部成功
OPERATE_RET rt = OPRT_OK;
TUYA_CALL_ERR_LOG(dev_report_dp_json_async(dp->cid,dp->dps,dp->dps_cnt));
return;
}
// 接收 RAW DP 处理回调 dev_raw_dp_cb
VOID test_DEV_RAW_DP_CMD_CB(IN CONST TY_RECV_RAW_DP_S *dp)
{
PR_DEBUG("SOC Rev DP Raw Cmd t1:%d t2:%d dpid:%d len:%u", dp->cmd_tp, dp->dtt_tp, dp->dpid, dp->len);
if(dp->cid != NULL) PR_ERR("soc not have cid.%s", dp->cid);
// TBD...
// 开发者可以在这里实现真实的 DP 对应功能的操作
// 默认实现是简单的把收到的DP上报上去,认为处理全部成功
OPERATE_RET rt = OPRT_OK;
TUYA_CALL_ERR_LOG(dev_report_dp_raw_sync(dp->cid,dp->dpid,dp->data,dp->len,0));
return;
}
// DP 查询上报,查询上报会附带一个"query"字段,云端会根据此字段进行过滤处理,避免影响真实上报逻辑
OPERATE_RET dev_query_dp_json_async(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
{
TY_OBJ_DP_REPT_S obj_dp = {{(CHAR_T *)dev_id, (TY_OBJ_DP_S *)dp_data, cnt}, FALSE};
return ty_dp_report(T_OBJ_REPT, (VOID_T*)&obj_dp, TRUE);
}
// 接收 DP 查询回调 dev_dp_query_cb
VOID test_DEV_DP_QUERY_CMD_CB(IN CONST TY_DP_QUERY_S *dp_qry)
{
PR_DEBUG("SOC Rev Query DP Cmd cnt:%d", dp_qry->cnt);
if(dp->cid != NULL) {
PR_ERR("soc not have cid.%s", dp_qry->cid);
}
// TBD...
// 如果cnt==0, 查询所有DP,每个产品的DP数量不一样,按照实际实现
OPERATE_RET rt = OPRT_OK;
if(dp_qry->cnt == 0) {
PR_DEBUG("soc rev all dp query");
UINT32_T cnt = 0;
TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(2*SIZEOF(TY_OBJ_DP_S));
if(NULL == dp_arr) {
PR_ERR("malloc failed");
return OPRT_MALLOC_FAILED;
}
memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));
// 获取所有的DP,组装DP数组
// TBD...
TUYA_CALL_ERR_LOG(dev_query_dp_json_async(dp_query->cid,dp_arr, cnt));
}else {
// 否则查询dp_query->dpid列表里的dp
TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(dp_qry->cnt*SIZEOF(TY_OBJ_DP_S));
if(NULL == dp_arr) {
PR_ERR("malloc failed");
return OPRT_MALLOC_FAILED;
}
memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));
UINT_T index = 0;
for(index = 0; index < dp_qry->cnt; index++) {
PR_DEBUG("rev dp query:%d", dp_qry->dpid[index]);
// 获取对应的DP,组装DP数组
// TBD...
}
TUYA_CALL_ERR_LOG(dev_query_dp_json_async(dp_query->cid,dp_arr, dp_qry->cnt));
}
return rt;
}
GW_CNTL_S * get_gw_cntl(VOID)
Get gateway cntl
Definition of DP query
Definition: tuya_cloud_com_defs.h:564
dp data report information for object type
Definition: smart_frame.h:249
Definition of structured dp
Definition: tuya_cloud_com_defs.h:448
DP_PROP_TP_E type
Definition: tuya_cloud_com_defs.h:452
BYTE_T dpid
Definition: tuya_cloud_com_defs.h:450
UINT_T time_stamp
Definition: tuya_cloud_com_defs.h:456
TY_OBJ_DP_VALUE_U value
Definition: tuya_cloud_com_defs.h:454
dp data report information for raw type
Definition: smart_frame.h:273
Definition of recved structured dp
Definition: tuya_cloud_com_defs.h:494
Definition of recved raw dp
Definition: tuya_cloud_com_defs.h:512
dp data report information for statistic type
Definition: smart_frame.h:261
OPERATE_RET dev_report_dp_json_async(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
dev_report_dp_json_async @desc report dp info a-synced.
OPERATE_RET dev_query_dp_json_async(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
dev_query_dp_json_async @desc report dp info a-synced.
OPERATE_RET dev_report_dp_json_async_force(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt)
dev_report_dp_json_async_force @desc report dp info a-synced.