蓝牙配件

更新时间:2025-06-24 09:16:57下载pdf

概念介绍

将非智能设备以配件的形式,基于智能电池包实现对非智能工具的智能控制与管理。该能力具备以下三个特点:

  • 针对非智能工具,推出一套标准的涂鸦对接通用方案。

  • 基于智能电池包实现对非智能工具的智能控制、OTA,同时可在 App 端展示非智能工具 RN 页面。

  • 针对智能电池包和非智能工具输出微应用管理后台,用于品牌方维护电池包和工具关系。

UART
Bluetooth LE
配件
电池包
App
云端
配件蓝牙子设备App设备注册握手请求(周期上报直到蓝牙子设备回复)握手请求回复发送配件信息上报设备信息注册设备并下发 short id告知注册状态数据上报通过 UART 上报数据通过 Bluetooth LE 上报至 App数据下发通过 Bluetooth LE 下发数据通过 UART 透传至配件配件蓝牙子设备App

数据结构

基线部分均以一个 UINT8_T 的指针传递数据,具体的数据处理在应用层,处理详情在 Demo:tuyaos_demo_ble_accessory 中展示。

typedef struct {
    UINT8_T channle;
    UINT32_T soft_version;
    UINT32_T hard_version;
} accessory_fw_info_t;

typedef struct {
    UINT8_T                    *p_accessory_fw_info;
    UINT8_T                     device_id[DEVICE_ID_LEN];
    UINT8_T                     common_pid[TUYA_BLE_PRODUCT_ID_MAX_LEN];
    tuya_ble_product_id_type_t  pid_type;
    UINT8_T                     pid_len;
    UINT8_T                     accessory_fw_info_len;
    UINT8_T                     device_id_len;
    UINT8_T                     connect_status; //1-connect 0-disconnect
    UINT8_T                     port_id;
    UINT8_T                     active_status; //1-active 0-no active
    UINT16_T                    short_id;
} tuya_ble_accessory_connection_info_t;

/**@brief    Structure about the accessory active information. */
typedef struct {
    UINT32_T info_crc;
    UINT16_T info_len;
    UINT16_T short_id;
    UINT8_T device_id[DEVICE_ID_LEN];
} tuya_ble_accessory_active_info_t;

/**@brief    Structure about the accessory ID information. */
typedef struct {
    UINT8_T id_type;
    UINT8_T id_len;
    UINT16_T short_id;
} tuya_ble_accessory_id_info_t; 

API 说明

以下所有的事件处理均在 tuya_ble_protocol_callback 这个回调中调用。

App 与子设备上下行透传接口

配件与 App、App 与配件的数据交互(包括 OTA 数据)通过蓝牙子设备作为媒介,子设备通过数据透传命令实现配件与 App 的数据上下行:

TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_DATA_RECEIVED

带数据源的 DP 数据接收,收到的数据需要透传给配件。

case TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_DATA_RECEIVED: {
    /* 判定数据来源*/
    if (event->dp_data_with_src_type_received_data.src_type != DATA_SOURCE_TYPE_ACCESSORY_EQUIPMENT) {
        break;
    }
    /* 判定设备信息是否符合要求*/
    p_id_info = (tuya_ble_accessory_id_info_t*)event->dp_data_with_src_type_received_data.p_add_info;
    if ((p_id_info->id_type != 0) || (p_id_info->id_len != 2)) {
        TAL_PR_ERR("TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_DATA_RECEIVED id info error.");
        break;
    }

    /*通过 short id 判定是否是匹配的配件*/
    if (tuya_ble_accessory_connection_info_find_by_short_id(p_id_info->short_id, &info_index) == TRUE) {
        /* 透传数据至配件*/
        tuya_ble_accessory_uart_cmd_dp_data_send_to_accessory(accessory_info[info_index].port_id, event->dp_data_with_src_type_received_data.sn, event->dp_data_with_src_type_received_data.p_data, event->dp_data_with_src_type_received_data.data_len);
        /* 上报 App */
        tuya_ble_dp_data_with_src_type_send(event->dp_data_with_src_type_received_data.sn, DATA_SOURCE_TYPE_ACCESSORY_EQUIPMENT, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITHOUT_RESPONSE, \
            event->dp_data_with_src_type_received_data.add_info_len, event->dp_data_with_src_type_received_data.p_add_info, \
            event->dp_data_with_src_type_received_data.p_data, event->dp_data_with_src_type_received_data.data_len);
    } else {
        TAL_PR_ERR("unknown device: %d", p_id_info->short_id);
    }
} break;

TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_QUERY

带数据源的 DP 数据 Query。

case TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_QUERY: {
            /* 判定数据来源*/
    if (event->dp_query_data_with_src_type.src_type != DATA_SOURCE_TYPE_ACCESSORY_EQUIPMENT) {
        break;
    }
            /* 判定设备信息是否符合要求*/
    p_id_info = (tuya_ble_accessory_id_info_t*)event->dp_query_data_with_src_type.p_add_info;
    if ((p_id_info->id_type != 0) || (p_id_info->id_len != 2)) {
        TAL_PR_ERR("TUYA_BLE_CB_EVT_WITH_SRC_TYPE_DP_QUERY id info error.");
        break;
    }
            /*通过 short id 判定是否是匹配的配件*/
    if (tuya_ble_accessory_connection_info_find_by_short_id(p_id_info->short_id, &info_index) == TRUE) {
        TAL_PR_HEXDUMP_DEBUG("DP Query - accessory:", event->dp_query_data_with_src_type.p_data, event->dp_query_data_with_src_type.data_len);

        /*send work status*/
        tuya_ble_accessory_uart_cmd_send_work_mode(accessory_info[info_index].port_id);

        /*send dp query*/
        tuya_ble_accessory_uart_cmd_dp_query(accessory_info[info_index].port_id, event->dp_query_data_with_src_type.p_data, event->dp_query_data_with_src_type.data_len);
    } else {
        TAL_PR_DEBUG("unknown device: %d", p_id_info->short_id);
    }
} break;

TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_SEND_RESPONSE

带数据源的 DP 数据上报 Response。

case TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_SEND_RESPONSE: {
    /* 判定数据来源*/
    if (event->dp_with_src_type_send_response_data.src_type != DATA_SOURCE_TYPE_ACCESSORY_EQUIPMENT) {
        break;
    }
    /*判定设备信息是否符合要求*/
    p_id_info = (tuya_ble_accessory_id_info_t*)event->dp_with_src_type_send_response_data.p_add_info;
    if ((p_id_info->id_type != 0) || (p_id_info->id_len != 2)) {
        TAL_PR_ERR("TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_SEND_RESPONSE id info error.");
        break;
    }
    /*通过 short id 判定是否是匹配的配件*/
    if (tuya_ble_accessory_connection_info_find_by_short_id(p_id_info->short_id, &info_index) == TRUE) {
        TAL_PR_DEBUG("DP Send Respondse - accessory:sn:0x%08X,type:%d,mode:%d,ack:%d,status:%d", event->dp_with_src_type_send_response_data.sn,\
        event->dp_with_src_type_send_response_data.type, event->dp_with_src_type_send_response_data.mode, event->dp_with_src_type_send_response_data.ack, event->dp_with_src_type_send_response_data.status);
    } else {
        TAL_PR_ERR("unknown device: %d", p_id_info->short_id);
    }
} break;

TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_AND_TIME_SEND_RESPONSE

带数据源、带时间戳的 DP 数据上报 Response。

case TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_AND_TIME_SEND_RESPONSE: {
    /* 判定数据来源*/ 
    if (event->dp_with_src_type_and_time_send_response_data.src_type != DATA_SOURCE_TYPE_ACCESSORY_EQUIPMENT) {
        break;
    }
            /*判定设备信息是否符合要求*/
    p_id_info = (tuya_ble_accessory_id_info_t*)event->dp_with_src_type_and_time_send_response_data.p_add_info;
    if ((p_id_info->id_type != 0) || (p_id_info->id_len != 2)) {
        TAL_PR_ERR("TUYA_BLE_CB_EVT_DP_DATA_WITH_SRC_TYPE_AND_TIME_SEND_RESPONSE id info error.");
        break;
    }
            /*通过 short id 判定是否是匹配的配件*/
    if (tuya_ble_accessory_connection_info_find_by_short_id(p_id_info->short_id, &info_index) == TRUE) {
        TAL_PR_DEBUG("DP Send Respondse - accessory:sn:0x%08X,type:%d,mode:%d,ack:%d,status:%d", event->dp_with_src_type_and_time_send_response_data.sn,\
        event->dp_with_src_type_and_time_send_response_data.type, event->dp_with_src_type_and_time_send_response_data.mode, event->dp_with_src_type_and_time_send_response_data.ack, event->dp_with_src_type_and_time_send_response_data.status);
    } else {
        TAL_PR_ERR("unknown device,%d", p_id_info->short_id);
    }
} break;

子设备与配件上下行接口

配件与子设备通过 UART 交互,协议中走用户命令字,对于应用层来说,只需要在应用层实现。

VOID_T tuya_ble_custom_app_uart_common_process(UINT8_T *p_in_data, UINT16_T in_len);

此接口函数 (该函数在底层被 weak 修饰,应用层实现后编译器优先链接应用层对该函数的实现)底层已经将数据解析上抛,传入的数据全部都是配件上报的数据,所以只需要将接到的数据传入接口中进行处理即可。

VOID_T tuya_ble_accessory_uart_protocol_process(UINT8_T port_id, UINT8_T *p_in_data, UINT16_T in_len);

接口中处理了所有与配件交互的命令:

  • TUYA_BLE_ACCESSORY_UART_CMD_OTA_REQUEST

  • TUYA_BLE_ACCESSORY_UART_CMD_OTA_FILE_INFO

  • TUYA_BLE_ACCESSORY_UART_CMD_OTA_FILE_OFFSET

  • TUYA_BLE_ACCESSORY_UART_CMD_OTA_DATA

  • TUYA_BLE_ACCESSORY_UART_CMD_OTA_END

  • TUYA_BLE_ACCESSORY_UART_CMD_HANDUP

  • TUYA_BLE_ACCESSORY_UART_CMD_DEVICE_INFO_REPORT

  • TUYA_BLE_ACCESSORY_UART_CMD_DP_DATA_REPORT

  • TUYA_BLE_ACCESSORY_UART_CMD_QUERY_MODULE_MAC

  • TUYA_BLE_ACCESSORY_UART_CMD_FATORY_CMD

具体详情,请参考 Demo:tuyaos_demo_ble_accessory

FAQ

开启该能力需要关注哪些宏?


// 该能力非默认支持,需要通过宏定义额外开启
#define TUYA_BLE_ACCESSORY_MOUNT_SUPPORTED 1 
// 基线需要支持多源头数据透传
#define TUYA_BLE_MUTI_DATA_SOURCE_SUPPORTED 1
// 以及通用对接串口能力
#define TUYA_BLE_FEATURE_UART_COMMON_ENABLE 1


串口的配置参数是怎么样的?

非智能配件与电池包通过 UART 通信,通信规格:

  • 波特率:9600

  • 数据长度:8 位

  • 停止位:1 位

  • 流控:无

配件在离线如何判定?

电池包的 RX 口设置一个弱下拉,配件的 TX 口设置一个上拉电阻。电池包周期检测 RX 口的电平状态,如果持续下拉则认为配件拔出,即处于离线状态;如果触发高电平,则发起握手命令;如果握手成功,则认为在线。

通信正常但是看不到设备注册,面板无法显示设备

蓝牙配件能力属于高级能力,需要 PID 额外开启,如果需要请联系涂鸦相关商务。

支持与帮助

在开发过程遇到问题,您可以登录 TuyaOS 开发者论坛 TuyaOS > 蓝牙设备开发 版块进行沟通咨询。

咨询前建议首先查阅 官方资料 或参考已有帖子,并认真阅读 发帖规范