概念介绍

涂鸦配网协议是标准 Bluetooth LE 协议的应用层规范,定义了一整套低功耗蓝牙设备和智能手机 App 之间的配网协议。通过涂鸦专属服务进行多层加密数据交互,结合涂鸦物模型实现安全可靠、点对点的物联网蓝牙数据传输协议。涂鸦配网协议是应用层协议,可兼容蓝牙 4.x/5.x 所有版本的标准蓝牙协议。

涂鸦配网协议除标准的 Primary Service 外,还引入了涂鸦专属服务(UUID:0xFD50),该服务定义了可读可写可通知的特征值,充分利用蓝牙特性,通过规范低功耗蓝牙底层的技术参数(广播周期/间隔,连接间隔/方式,数据交互方式),最大程度地发挥蓝牙芯片的性能。

功能描述

android 获取自己设备的蓝牙mac地址 手机获取蓝牙设备mac地址_固件

角色

配网过程中,涉及到主机(Central)和从机(Peripheral)两个参与角色。日常交流中,主机多称为 App,从机多称为设备:

  • 主机:智能生活 App(手机)、蓝牙网关。
  • 从机:智能蓝牙设备,例如门锁、灯、防丢器,体脂称、手环等。

不同角色的交互流程如下所述:

  1. 主机通过 蓝牙广播 识别从机。
  2. 主机对已授权的从机发起配对请求,完成配对的主从机处于 绑定状态
  3. 处于绑定状态的主从机之间存在一条符合蓝牙规范的安全通道,所有的业务类通信(包括 DP 数据)都在该安全通道中进行。

配网流程

安全通道的建立过程(配网)可以简述如下:

  • 配网:
    未绑定
    连接
    配对
    绑定
    安全通信
    断开
  • 重连:
    重连
    绑定
    安全通信
    ……
    解配对
    未绑定

配网过程中的关键环节的解释如下:

  • 连接:表示蓝牙设备链路层的状态为连接状态。
  • 配对:视为一种过程,一系列的密钥交换过程。
  • 绑定:视为一种状态,配对完成的状态称之为 绑定状态,处于绑定状态的两个设备可以进行安全通信。
  • 重连:视为一种过程,依然是一系列的密钥交换过程,可以认为是简化的 配对。该过程的前提是,设备此前已经进入过一次绑定状态。
  • 解配对:视为一种过程,秘钥删除和绑定状态等信息的清除,也称作 移除解绑 等。

解绑流程

  • 解绑
  • 触发条件:App 面板上单击 解除绑定 按钮
  • 触发事件:TUYA_BLE_CB_EVT_UNBOUND
  • 解绑并清除数据
  • 触发条件:App 面板上单击 解绑并清除数据 按钮
  • 触发事件:TUYA_BLE_CB_EVT_DEVICE_RESET

数据结构

tuya_ble_addr_type_t

typedef enum {
    TUYA_BLE_ADDRESS_TYPE_PUBLIC, // public address
    TUYA_BLE_ADDRESS_TYPE_RANDOM, // random address
} tuya_ble_addr_type_t;
  • TUYA_BLE_ADDRESS_TYPE_PUBLIC:公共地址类型。
  • TUYA_BLE_ADDRESS_TYPE_RANDOM:随机地址类型。

tuya_ble_gap_addr_t

typedef struct {
    tuya_ble_addr_type_t addr_type;
    UINT8_T addr[6];
} tuya_ble_gap_addr_t;
  • addr_type:详见 tuya_ble_addr_type_t
  • addr:6 字节 Mac 地址。

tuya_ble_product_id_type_t

typedef enum {
    TUYA_BLE_PRODUCT_ID_TYPE_PID,
    TUYA_BLE_PRODUCT_ID_TYPE_PRODUCT_KEY,
} tuya_ble_product_id_type_t;
  • TUYA_BLE_PRODUCT_ID_TYPE_PID:product ID 类型。
  • TUYA_BLE_PRODUCT_ID_TYPE_PRODUCT_KEY:product key 类型。

tuya_ble_device_param_t

typedef struct {
    UINT8_T use_ext_license_key; //If use the license key stored by the SDK,initialized to 0, Otherwise 1.
    UINT8_T device_id_len;       //if ==20,Compressed into 16
    UINT8_T device_id[DEVICE_ID_LEN_MAX];
    UINT8_T auth_key[AUTH_KEY_LEN];
    tuya_ble_gap_addr_t mac_addr;
    UINT8_T mac_addr_string[MAC_STRING_LEN];

    tuya_ble_product_id_type_t p_type;
    UINT8_T product_id_len;
    UINT8_T product_id[TUYA_BLE_PRODUCT_ID_MAX_LEN];
    UINT8_T adv_local_name_len;
    UINT8_T adv_local_name[TUYA_BLE_ADV_LOCAL_NAME_MAX_SPACE_LEN]; //Only supported when TUYA_BLE_PROTOCOL_VERSION_HIGN >= 4.
    UINT32_T firmware_version; //0x00010102 : v1.1.2
    UINT32_T hardware_version;

    UINT8_T device_vid[DEVICE_VIRTUAL_ID_LEN];
    UINT8_T login_key[LOGIN_KEY_LEN];
    UINT8_T beacon_key[BEACON_KEY_LEN];
    UINT8_T bound_flag;

    UINT8_T reserve_1;
    UINT8_T reserve_2;
} tuya_ble_device_param_t;
  • use_ext_license_key:是否使用调试的授权信息,0:不使用,1:使用。
  • device_id_len:设备 ID 长度。
  • device_id:设备 ID。
  • auth_key:32 字节授权秘钥。
  • mac_addr:详见 tuya_ble_gap_addr_t
  • mac_addr_string:12 字节 Mac 地址字符串。
  • p_type:详见 tuya_ble_product_id_type_t
  • product_id_len:PID 长度。
  • product_id:产品 ID。
  • adv_local_name_len:蓝牙广播名称长度。
  • adv_local_name:蓝牙广播名称(通过 nRF Connect 看到的名字)。
  • firmware_version:固件版本,例如 1.1.0。
  • hardware_version:硬件版本,例如 1.0.0。
  • device_vid:22 字节设备虚拟 ID。
  • login_key:6 字节注册秘钥。
  • beacon_key:16 字节 Beacon 秘钥。
  • bound_flag:绑定标识。

实际使用方式详见 tal_ble_protocol_callback.c 中的示例程序。

tuya_ble_connect_status_t

typedef enum {
    UNBONDING_UNCONN = 0,
    UNBONDING_CONN,
    BONDING_UNCONN,
    BONDING_CONN,
    BONDING_UNAUTH_CONN,
    UNBONDING_UNAUTH_CONN,
    UNKNOW_STATUS
} tuya_ble_connect_status_t;
  • UNBONDING_UNCONN:未绑定未连接。
  • UNBONDING_CONN:未绑定已连接。
  • BONDING_UNCONN:已绑定未连接。
  • BONDING_CONN:已绑定已连接。
  • BONDING_UNAUTH_CONN:已绑定已连接未认证。
  • UNBONDING_UNAUTH_CONN:未绑定未授权已连接。
  • UNKNOW_STATUS:未知状态。

各状态之间的转换关系见下图:

android 获取自己设备的蓝牙mac地址 手机获取蓝牙设备mac地址_物联网_02

接口说明

配网初始化

该接口是涂鸦蓝牙设备和 App 通信的主要接口,涵盖了配网相关的各种参数和事件处理。

VOID_T tuya_ble_protocol_init(VOID_T)
{
    tuya_ble_protocol_param.firmware_version = tal_common_info.firmware_version,
    tuya_ble_protocol_param.hardware_version = tal_common_info.hardware_version,
    memcpy(tuya_ble_protocol_param.device_id,       device_id_test, DEVICE_ID_LEN);
    memcpy(tuya_ble_protocol_param.auth_key,        auth_key_test, AUTH_KEY_LEN);
    memcpy(tuya_ble_protocol_param.mac_addr_string, TY_DEVICE_MAC, MAC_STRING_LEN);
    memcpy(tuya_ble_protocol_param.product_id,      TY_DEVICE_PID, tuya_ble_protocol_param.product_id_len);
    memcpy(tuya_ble_protocol_param.adv_local_name, TY_DEVICE_NAME, tuya_ble_protocol_param.adv_local_name_len);
    tuya_ble_sdk_init(&tuya_ble_protocol_param);

    tuya_ble_callback_queue_register(tuya_ble_protocol_callback);

    ……
}
  • tuya_ble_sdk_init():用于参数初始化,包括固件版本、三元组(Mac、Device id、Auth key)、PID、广播名称等参数。
  • tuya_ble_callback_queue_register():用于注册回调函数,处理包括配网状态、时间戳、DP 数据、解绑等各种配网相关的逻辑。

配网回调函数

用于设备配网完成的回调接口。

STATIC VOID_T tuya_ble_protocol_callback(tuya_ble_cb_evt_param_t* event)

用于处理配网以及通信过程中发生的各种事件如下所示:

typedef enum {
    TUYA_BLE_CB_EVT_CONNECTE_STATUS = TUYA_BLE_CB_EVT_BASE,
    TUYA_BLE_CB_EVT_DP_WRITE,          // old version
    TUYA_BLE_CB_EVT_DP_QUERY,
    TUYA_BLE_CB_EVT_DP_DATA_RECEIVED, // new version
    TUYA_BLE_CB_EVT_OTA_DATA,
    TUYA_BLE_CB_EVT_BULK_DATA,
    TUYA_BLE_CB_EVT_NETWORK_INFO,
    TUYA_BLE_CB_EVT_WIFI_SSID,
    TUYA_BLE_CB_EVT_TIME_STAMP,
    TUYA_BLE_CB_EVT_TIME_NORMAL,
    TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL,
    TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST,
    TUYA_BLE_CB_EVT_DATA_PASSTHROUGH,
    TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE,
    TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE,
    TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_REPORT_RESPONSE,
    TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORT_RESPONSE,
    TUYA_BLE_CB_EVT_DP_DATA_SEND_RESPONSE,               // new version
    TUYA_BLE_CB_EVT_DP_DATA_WITH_TIME_SEND_RESPONSE,     // new version
    TUYA_BLE_CB_EVT_UNBOUND,
    TUYA_BLE_CB_EVT_ANOMALY_UNBOUND,
    TUYA_BLE_CB_EVT_DEVICE_RESET,
    TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID,
    TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE,               // Notify the application of the result of the local reset
    TUYA_BLE_CB_EVT_WEATHER_DATA_REQ_RESPONSE,             // received request weather data app response
    TUYA_BLE_CB_EVT_WEATHER_DATA_RECEIVED,                  // received app sync weather data
    TUYA_BLE_CB_EVT_REMOTER_PROXY_AUTH_RESP,
    TUYA_BLE_CB_EVT_REMOTER_GROUP_SET,
    TUYA_BLE_CB_EVT_REMOTER_GROUP_DELETE,
    TUYA_BLE_CB_EVT_REMOTER_GROUP_GET,
} tuya_ble_cb_evt_t;

查询网络状态

tuya_ble_connect_status_t tuya_ble_connect_status_get(VOID_T);

tuya_ble_connect_status_t:详见 tuya_ble_connect_status_t。

使用方法

通信流程

android 获取自己设备的蓝牙mac地址 手机获取蓝牙设备mac地址_蓝牙_03

代码开发

详见 tal_ble_protocol_callback.c 中的示例程序:

STATIC tuya_ble_device_param_t tuya_ble_protocol_param = {
#if (TUYA_SDK_DEBUG_MODE)
    .use_ext_license_key = 1, //1-info in tuya_ble_protocol_callback.h, 0-auth info
    .device_id_len       = DEVICE_ID_LEN,
#else
    .use_ext_license_key = 0,
    .device_id_len       = 0,
#endif
    .p_type              = TUYA_BLE_PRODUCT_ID_TYPE_PID,
#if (TUYA_BLE_PROD_SUPPORT_OEM_TYPE == TUYA_BLE_PROD_OEM_TYPE_NONE)
    .product_id_len      = 8,
#else
    .product_id_len      = 0,
#endif
    .adv_local_name_len  = 4,
};

STATIC VOID_T tuya_ble_protocol_callback(tuya_ble_cb_evt_param_t* event)
{
    switch (event->evt) {
        case TUYA_BLE_CB_EVT_CONNECTE_STATUS: {
            if (event->connect_status == BONDING_CONN) {
                TAL_PR_INFO("bonding and connecting");

                tuya_ble_update_conn_param_timer_start();
            }
        } break;

        case TUYA_BLE_CB_EVT_DP_DATA_RECEIVED: {
            app_dp_parser(event->dp_received_data.p_data, event->dp_received_data.data_len);
        } break;

        …………

        case TUYA_BLE_CB_EVT_UNBOUND: {
            TAL_PR_INFO("TUYA_BLE_CB_EVT_UNBOUND");
        } break;

        case TUYA_BLE_CB_EVT_ANOMALY_UNBOUND: {
            TAL_PR_INFO("TUYA_BLE_CB_EVT_ANOMALY_UNBOUND");
        } break;

        case TUYA_BLE_CB_EVT_DEVICE_RESET: {
            TAL_PR_INFO("TUYA_BLE_CB_EVT_DEVICE_RESET");
        } break;

        case TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE: {
            TAL_PR_INFO("TUYA_BLE_CB_EVT_UNBIND_RESET_RESPONSE");
        } break;

        …………

        default: {
            TAL_PR_INFO("tuya_ble_protocol_callback Unprocessed event type 0x%04x", event->evt);
        } break;
    }
    …………
}

VOID_T tuya_ble_protocol_init(VOID_T)
{
    tuya_ble_protocol_param.firmware_version = tal_common_info.firmware_version,
    tuya_ble_protocol_param.hardware_version = tal_common_info.hardware_version,
    memcpy(tuya_ble_protocol_param.device_id,       TY_DEVICE_DID, DEVICE_ID_LEN);
    memcpy(tuya_ble_protocol_param.auth_key,        TY_DEVICE_AUTH_KEY,  AUTH_KEY_LEN);
    memcpy(tuya_ble_protocol_param.mac_addr_string, TY_DEVICE_MAC,  MAC_STRING_LEN);
    memcpy(tuya_ble_protocol_param.product_id,      TY_DEVICE_PID,  tuya_ble_protocol_param.product_id_len);
    memcpy(tuya_ble_protocol_param.adv_local_name,  TY_DEVICE_NAME, tuya_ble_protocol_param.adv_local_name_len);
    tuya_ble_sdk_init(&tuya_ble_protocol_param);

    tuya_ble_callback_queue_register(tuya_ble_protocol_callback);

    …………
}

功能测试

前置条件

蓝牙设备进行配网前,需要进行固件烧录和授权。

  • 烧录固件跟芯片平台完全相关,请参考 TuyaOS 快速入门 中相应平台相关的资料。
  • 授权一般用于设备批量生产,请参考 TuyaOS 快速入门 中 TuyaOS 开发蓝牙产品之授权产测

若暂无生产需要,也可通过以下方式进行临时授权(仅用于调试,生产时请改回原状):

  1. 找到如下代码片段:
  2. 临时修改为如下设置:
STATIC tuya_ble_device_param_t tuya_ble_protocol_param = {
    .use_ext_license_key = 1, //1-info in tuya_ble_sdk_demo.h, 0-auth info
    .device_id_len       = DEVICE_ID_LEN, //DEVICE_ID_LEN,
    .p_type              = TUYA_BLE_PRODUCT_ID_TYPE_PID,
    .product_id_len      = 8,
    .adv_local_name_len = 4,
};

操作步骤

授权结束后,即成功激活涂鸦低功耗蓝牙设备。

此时,您可以在手机上下载 智能生活 App,登录后在 App 首页单击右上角 + > 添加设备。上位机展示的信息为更新配网状态、更新 MTU、更新时间戳、更新连接参数,整个过程如下图所示:

android 获取自己设备的蓝牙mac地址 手机获取蓝牙设备mac地址_蓝牙_04

上位机使用的相关问题,请访问 Logic 上位机使用指南