TUYA BLE SDK User Guide

The tuya ble sdk encapsulates the communication protocol with Tuya Smart mobile App and implements event scheduling abilities. The device using tuya ble sdk does not need to care about the specific communication protocol implementation details. It can be interconnected with Tuya Smart App by calling the API and callback provided by the tuya ble sdk.

This topic gives details of the components, porting instruction, SDK configuration, API description, and usage of tuya ble sdk.

Project address

https://github.com/TuyaInc/tuya_ble_sdk.git

Overview of tuya ble sdk

Framework

The following figure shows the Application framework based on tuya ble sdk:

  • platform: the chip platform. The chip and protocol stack are maintained by the chip company.

  • Port: the abstract interfaces needed by the tuya ble sdk. You must implement them according to the chip-specific platform.

  • tuya ble sdk: encapsulates the communication protocol of Tuya BLE and provides the service interface to develop Tuya BLE devices.

  • Application: your application, built by using tuya ble sdk.

  • Tuya sdk API: implements BLE related management, communication, and so forth. The calls of API are based on asynchronous messages, and the result of API will be notified to the Application of device by message or call back.

  • sdk config: by setting the macro in the configuration file, you can configure tuya ble sdk to different modes, for example, the general network configuration mode applicable to multi-protocol devices, Bluetooth singlepoint devices mode, ECDH key based encryption method, whether to use OS, and so forth.

  • Main process function: the engine of tuya ble sdk, to which the Application will call all the time. If the platform architecture has an OS, The tuya ble sdk will automatically create a task to run the main process based on the OS related interface provided by the port layer. If the platform does not have an OS, the device Application needs to be called circularly.

  • Message or Call back: SDK sends the data of status, data, and others to device Application through call back function registered by device Application or messages.

OS compatibility

The tuya ble sdk can run on OS based chip platform besides Linux. If an OS is used, the API requests are based on asynchronous messages. When tuya ble sdk is initialized, the SDK automatically creates a task based on 'tuya_ble_config.h file to process the message events of the SDK, and creates a message queue to receive the responses of the Application API. The results of the API are notified to the Application of the device in the form of message, so your Application needs to create a message queue and call tuya_ble_callback_queue_register() after calling tuya_ble_sdk_init() or tuya_ble_sdk_init_async() to register the message queue to the SDK.

In the chip platform that has an OS, you can also configure the tuya ble sdk to process messages using the task provided by Application instead of tasks within the tuya ble sdk. By doing so, the Application must implement the outbound message interface at the port layer.

Event queue

The earlier event takes precedence to leave (FIFO). Event queue caches the messages sent by the Application and platform layer, the event can be API calls, data response from BLE devices, and so forth. The main process function module circularly queries the message queue and takes it out for processing.

Directories

The concepts of tuya ble service

The tuya ble sdk does not provide the interfaces for initializing service. Your Application needs to implement the service characteristics defined in the following table before you initializing the SDK. Other than the services required by the tuya ble sdk, you can also define other services if needed. The initial format of broadcast data must be implemented according to the following table, otherwise the tuya ble sdk cannot work.

The MTU

For a better compatibility, the ATT MTU used by tuya ble sdk is 23, and the GATT MTU (ATT DATA MAX) is 20.

Broadcast data format

The following picture illustrates the broadcast packet format of BLE.

The following table describes what are contained in the broadcast packet.

Example of 8 byte PID: 02 01 05 03 02 01 A2 0C 16 01 A2 00 00 00 00 00 00 00 00 00

The following table describes what are contained in the scan response data.

Example of an unassociated devices: 03 09 54 59 19 FF D0 07 00 0300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

How to port and configure tuya ble sdk

As the following picture shows, the interfaces defined in the file tuya_ble_port.h and tuya_ble_port_peripheral.h must be ported and implemented according to the chip-specific platform. Note that if the platform used in the Application does not have an OS, the OS related interfaces do not need to be implemented. The tuya_ble_port.c and tuya_ble_port_peripheral.c are the weak implementation of the interfaces defined for the tuya_ble_port.h and tuya_ble_port_peripheral.h.

You cannot implement platform-specific interfaces in the preceding .c files, please create a new one, for example tuya_ble_port_nrf52832.c. If the file name contains the keyword tuya, it is the platform implementation file that Tuya Smart has adapted and transplanted, you can refer to it if needed.

Reference of porting APIs

TUYA_BLE_LOG

TUYA_BLE_HEXDUMP

tuya_ble_gap_advertising_adv_data_update

tuya_ble_gap_advertising_scan_rsp_data_update

tuya_ble_gap_disconnect

tuya_ble_gatt_send_data

tuya_ble_timer_create

tuya_ble_timer_delete

tuya_ble_timer_start

tuya_ble_timer_restart

tuya_ble_timer_stop

tuya_ble_device_delay_ms

tuya_ble_device_delay_us

tuya_ble_device_reset

tuya_ble_gap_addr_get

The following sample illustrates how to use the tuya_ble_gap_addr_get method.

typedef enum

{

TUYA_BLE_ADDRESS_TYPE_PUBLIC, // The public address

TUYA_BLE_ADDRESS_TYPE_RANDOM, // The random address

} tuya_ble_addr_type_t;

typedef struct

{

tuya_ble_addr_type_t addr_type;

uint8_t addr[6];

}tuya_ble_gap_addr_t;

tuya_ble_gap_addr_set

tuya_ble_device_enter_critical

tuya_ble_device_exit_critical

tuya_ble_rand_generator

tuya_ble_rtc_get_timestamp

tuya_ble_rtc_set_timestamp

tuya_ble_nv_init

tuya_ble_nv_erase

tuya_ble_nv_write

tuya_ble_nv_read

tuya_ble_nv_erase_async

tuya_ble_nv_write_async

tuya_ble_nv_read_async

tuya_ble_common_uart_init

tuya_ble_common_uart_send_data

tuya_ble_os_task_create

tuya_ble_os_task_delete

tuya_ble_os_task_suspend

tuya_ble_os_task_resume

tuya_ble_os_msg_queue_create

tuya_ble_os_msg_queue_delete

tuya_ble_os_msg_queue_peek

tuya_ble_os_msg_queue_send

tuya_ble_os_msg_queue_recv

tuya_ble_event_queue_send_port

tuya_ble_aes128_ecb_encrypt

tuya_ble_aes128_ecb_decrypt

tuya_ble_aes128_cbc_encrypt

tuya_ble_aes128_cbc_decrypt

tuya_ble_md5_crypt

tuya_ble_hmac_sha1_crypt

tuya_ble_hmac_sha256_crypt

tuya_ble_port_malloc

tuya_ble_port_free

Reference of configuration APIs

The items in the tuya_ble_config.h file are used to configure the tuya ble sdk for different use cases, for example, network configuration for multi-protocol devices, whether running an OS on the platform or not, device communication, whether self-manage the authorization, and so forth.

CUSTOMIZED_TUYA_BLE_CONFIG_FILE

CUSTOMIZED_TUYA_BLE_APP_PRODUCT_TEST_HEADER_FILE

CUSTOMIZED_TUYA_BLE_APP_UART_COMMON_HEADER_FILE

TUYA_BLE_USE_OS

TUYA_BLE_SELF_BUILT_TASK

TUYA_BLE_TASK_PRIORITY

TUYA_BLE_TASK_STACK_SIZE

TUYA_BLE_DEVICE_COMMUNICATION_ABILITY

TUYA_BLE_DEVICE_SHARED

TUYA_BLE_DEVICE_UNBIND_MODE

TUYA_BLE_WIFI_DEVICE_REGISTER_MODE

TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT

TUYA_BLE_SECURE_CONNECTION_TYPE

TUYA_BLE_DEVICE_MAC_UPDATE

TUYA_BLE_DEVICE_MAC_UPDATE_RESET

TUYA_BLE_USE_PLATFORM_MEMORY_HEAP

TUYA_BLE_GATT_SEND_DATA_QUEUE_SIZE

TUYA_BLE_DATA_MTU_MAX

TUYA_BLE_LOG_ENABLE

TUYA_BLE_LOG_COLORS_ENABLE

TUYA_BLE_LOG_LEVEL

TUYA_APP_LOG_ENABLE

TUYA_APP_LOG_COLORS_ENABLE

TUYA_APP_LOG_LEVEL

TUYA_BLE_ADVANCED_ENCRYPTION_DEVICE

TUYA_NV_ERASE_MIN_SIZE

TUYA_NV_WRITE_GRAN

TUYA_NV_START_ADDR

TUYA_NV_AREA_SIZE

TUYA_BLE_APP_VERSION_STRING

TUYA_BLE_APP_BUILD_FIRMNAME_STRING

API reference

The tuya ble sdk provides packaged API for Application to achieve BLE related management, communication, and so forth. The APIs are defined in the tuya_ble_api.c and tuya_ble_api.h files, you can read the source code to understand how the APIs are implemented. The following tables describes the details of each API.

tuya_ble_main_tasks_exec

Example: the calling location under nrf52832 platform is as follows:

/**@brief Function for handling the idle state (main loop).
 *
 * @details If there is no pending log operation, then sleep until next the next event occurs.
 */
static void idle_state_handle(void)
{
    tuya_ble_main_tasks_exec();

    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }

}

tuya_ble_gatt_receive_data

Example (nrf52832 example demo):

/**@brief Function for handling the data from the Nordic UART Service.
 *
 * @details This function will process the data received from the Nordic UART BLE Service and send
 *          it to the UART module.
 *
 * @param[in] p_evt       Nordic UART Service event.
 */
/**@snippet [Handling the data received over BLE] */
static void nus_commdata_handler(ble_nus_evt_t * p_evt)
{

    if (p_evt->type == BLE_NUS_EVT_RX_DATA)
    {
        tuya_ble_gatt_receive_data((uint8_t*)(p_evt->params.rx_data.p_data),p_evt->params.rx_data.length);
        TUYA_BLE_HEXDUMP("nus_commdata_handler :",20,(uint8_t*)(p_evt->params.rx_data.p_data),p_evt->params.rx_data.length);
    }

}

tuya_ble_common_uart_receive_data

tuya_ble_common_uart_send_full_instruction_received

Explanation:

  • The tuya ble sdk integrates the production testing authorization function module. The production testing authorization module communicates through the UART and PC production testing authorization tools. UART communication has a complete set of command formats. For details, refer to the Bluetooth General Production Test Authorization Agreement.

  • The tuya ble sdk includes the UART communication instruction parsing function. The Application only needs to call the tuya_ble_common_uart_receive_data() function where UART data is received. The Application can also parse out the complete UART communication instruction, and then call tuya_ble_common_uart_send_full_instruction_received() function to send a complete command to tuya ble sdk.

tuya_ble_device_update_product_id

tuya_ble_device_update_login_key

tuya_ble_device_update_bound_state

tuya_ble_device_update_mcu_version

tuya_ble_sdk_init

Parameter explanation:

The structure of tuya_ble_device_param_t is as follows:

typedef struct{
    uint8_t device_id_len;   //if ==20,Compressed into 16
	uint8_t device_id[DEVICE_ID_LEN_MAX];
    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 device_vid[DEVICE_VIRTUAL_ID_LEN];
	uint8_t auth_key[AUTH_KEY_LEN];
	uint8_t login_key[LOGIN_KEY_LEN];
    uint8_t bound_flag;
    uint32_t firmware_version; //0x00010102: v1.1.2
    uint32_t hardware_version;
    uint8_t reserve_1;
    uint8_t reserve_2;
}tuya_ble_device_param_t;

The following items describe the variables in the preceding snippet.

  • device_id and auth_key: the device_uuid and the auth_key are unique identifier pairs assigned to the BLE devices by the Tuya IoT platform. They are required when you perform the production testing authorization via Tuya testing tool. After a BLE device is authorized by production testing, the tuya ble sdk takes control of and manages them automatically. Therefore, you can set the device_uuid ad the auth_key to 0 when the tuya ble sdk is initialized. If they are not 0, the tuya ble sdk uses the pre-defined device_id and auth_key. For a Wi-Fi/BLE dual-mode device, itsdevice_id and auth_key are managed by the Wi-Fi layer, therefore, the actual device_id and auth_key are needed when the tuya ble sdk is initialized.

  • product_id: pid for short. It is automatically generated when a new product is created on the IoT platform. In your Application, the PID needs to be saved in the form of a constant. It is required when initializing the tuya ble sdk.

  • device_vid: the virtual ID of a BLE device, which is generated by Tuya IoT platform after the binding of the notice volume. It can be used to find the data record of the cloud to the BLE device when the BLE device is added or removed. For BLE devices that need the authorization information of the tuya ble sdk management, the value is 0. For Wi-Fi/BLE dual mode devices, or BLE devices of which the authorization is managed by your Application, the actual device_vid is needed.

  • login_key and bound_flag: if the authorization of BLE devices are managed by the tuya ble sdk, set the values to 0. For Wi-Fi/BLE dual mode devices, or BLE devices of which the authorization is managed by your Application, the actual values are needed.

  • firmware_version and hardware_version: indicates the firmware version number and the hardware (PCBA) version number of BLE devices. They are required when initializing the tuya ble sdk. Currently, BLE devices only support two digit version numbers, for example 0x0100 represents v1.0.

The following snippet is the initialization example of tuya ble sdk for nrf52832 platform.

static const char auth_key_test[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
static const char device_id_test[] = "yyyyyyyyyyyyyyyy";

#define APP_PRODUCT_ID  "vvvvvvvv"

void tuya_ble_app_init(void)
{
	tuya_ble_device_param_t device_param = {0};
    device_param.device_id_len = 16;
    memcpy(device_param.auth_key,(void *)auth_key_test,AUTH_KEY_LEN);
    memcpy(device_param.device_id,(void *)device_id_test,DEVICE_ID_LEN);
    device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
    device_param.product_id_len = 8;
    memcpy(device_param.product_id,APP_PRODUCT_ID,8);
    device_param.firmware_version = TY_APP_VER_NUM;
    device_param.hardware_version = TY_HARD_VER_NUM;

    tuya_ble_sdk_init(&device_param);
    tuya_ble_callback_queue_register(tuya_cb_handler);

    tuya_ota_init();
}

/*nrf52832 example*/
int main(void)
{
    bool erase_bonds;

    // Initialize.
    uart_init();
    app_log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();
    tuya_ble_app_init();
    advertising_start();

    NRF_LOG_INFO("App version: %s\r\n",TY_APP_VER_STR);

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}

tuya_ble_sdk_init_async

Example of tuya ble sdk asynchronous initialization:

static const char auth_key_test[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
static const char device_id_test[] = "yyyyyyyyyyyyyyyy";

#define APP_PRODUCT_ID  "vvvvvvvv"

static void tuya_ble_sdk_init_async_completed(void *p_param,tuya_ble_status_t result)
{
    if(result==TUYA_BLE_SUCCESS)
    {
        tuya_ble_callback_queue_register(tuya_cb_handler);

        tuya_ota_init();

        TUYA_APP_LOG_INFO("tuya sdk init succeed.");
        TUYA_APP_LOG_INFO("App version: "TY_APP_VER_STR);
        TUYA_APP_LOG_DEBUG("current free heap size = %d",xTuyaPortGetFreeHeapSize());
        //tuya_ble_device_factory_reset();
    }
    else
    {
        TUYA_APP_LOG_INFO("tuya sdk init failed.");
    }
}

void tuya_ble_app_init(void)
{
    tuya_ble_nv_init_custom();
    memset(&device_param,0,sizeof(tuya_ble_device_param_t));
    device_param.device_id_len = 16;
    memcpy(device_param.auth_key,(void *)auth_key_test,AUTH_KEY_LEN);
    memcpy(device_param.device_id,(void *)device_id_test,DEVICE_ID_LEN);

    device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
    device_param.product_id_len = 8;
    memcpy(device_param.product_id,APP_PRODUCT_ID,8);
    device_param.firmware_version = TY_APP_VER_NUM;
    device_param.hardware_version = TY_HARD_VER_NUM;

    tuya_ble_sdk_init_async(&device_param,tuya_ble_sdk_init_async_completed);


}

/*nrf52832 example*/
int main(void)
{
    bool erase_bonds;

    // Initialize.
    uart_init();
    app_log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();
    tuya_ble_app_init();
    advertising_start();

    NRF_LOG_INFO("App version: %s\r\n",TY_APP_VER_STR);

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}

tuya_ble_dp_data_report

parameter description:

  • Tuya IoT platform manages data in the form of dp points. The data generated by any device needs to be abstracted in the form of dp points. A complete dp point data consists of four parts (refer to the relevant introduction on the IoT platform for details):

    Dp_id: 1 byte, dp_id serial number registered in the development platform.

    Dp_type: 1 byte, dp point type.

#define DT_RAW 0 //raw type

#define DT_BOOL 1 //Boolean type

#define DT_VALUE 2 //Value type

#define DT_STRING 3 //String type

#define DT_ENUM 4 //Enumeration type

#define DT_BITMAP 5 // Bitmap type

Dp_len: Bluetooth currently supports only one byte, that is, the longest data of a single dp point is 255 bytes.

Dp_data: Data, dp_len bytes.

  • The dp point reporting function, the data pointed to by parameter p_data must be assembled and reported in the form of a table:

  • When calling this function, the maximum length of parameter len is TUYA_BLE_REPORT_MAX_DP_DATA_LEN (currently 255+3).

tuya_ble_dp_data_with_time_report

tuya_ble_dp_data_with_time_ms_string_report

tuya_ble_dp_data_with_flag_report

parameter description:

mode:

REPORT_FOR_CLOUD_PANEL: report to the panel and the cloud at the same time.

REPORT_FOR_CLOUD: only report to the cloud.

REPORT_FOR_PANEL: only report to the panel.

REPORT_FOR_NONE: neither reported to the panel nor to the cloud.

tuya_ble_dp_data_with_flag_and_time_report

tuya_ble_dp_data_with_flag_and_time_ms_string_report

tuya_ble_connected_handler

tuya_ble_disconnected_handler

Example of calling tuya_ble_connected_handler and tuya_ble_disconnected_handler on nrf52832 platform:

/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    uint32_t err_code;

    switch (p_ble_evt->header.evt_id)
    {
    case BLE_GAP_EVT_CONNECTED:

        NRF_LOG_INFO("Connected");

        tuya_ble_connected_handler();

        err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
        APP_ERROR_CHECK(err_code);
        m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
        err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
        APP_ERROR_CHECK(err_code);

        break;

    case BLE_GAP_EVT_DISCONNECTED:

        NRF_LOG_INFO("Disconnected");

        tuya_ble_disconnected_handler();

        tuya_ota_init_disconnect();
        // LED indication will be changed when advertising starts.
        m_conn_handle = BLE_CONN_HANDLE_INVALID;
        break;

    case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
    {
        NRF_LOG_DEBUG("PHY update request.");
        ble_gap_phys_t const phys =
        {
            .rx_phys = BLE_GAP_PHY_AUTO,
            .tx_phys = BLE_GAP_PHY_AUTO,
        };
        err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
        APP_ERROR_CHECK(err_code);
    }
    break;

    case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
        // Pairing not supported
        err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
        APP_ERROR_CHECK(err_code);
        break;

    case BLE_GATTS_EVT_SYS_ATTR_MISSING:
        // No system attributes have been stored.
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
        APP_ERROR_CHECK(err_code);
        break;

    case BLE_GATTC_EVT_TIMEOUT:
        // Disconnect on GATT Client timeout event.
        err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                         BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        break;

    case BLE_GATTS_EVT_TIMEOUT:
        // Disconnect on GATT Server timeout event.
        err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                         BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        break;

    default:
        // No implementation needed.
        break;
    }
}

tuya_ble_adv_data_connecting_request_set

tuya_ble_data_passthrough

tuya_ble_production_test_asynchronous_response

tuya_ble_net_config_response

tuya_ble_ubound_response

tuya_ble_anomaly_ubound_response

tuya_ble_device_reset_response

tuya_ble_connect_status_get

Responses description:

typedef enum{
    UNBONDING_UNCONN = 0,
    UNBONDING_CONN,
    BONDING_UNCONN,
    BONDING_CONN,
    BONDING_UNAUTH_CONN,
    UNBONDING_UNAUTH_CONN,
    UNKNOW_STATUS
}tuya_ble_connect_status_t;

tuya_ble_device_factory_reset

tuya_ble_time_req

tuya_ble_ota_response

tuya_ble_custom_event_send

Description: This function is mainly used when the Application wants to use the internal message scheduler of tuya ble sdk to process the Application's message events. tuya_ble_custom_event_send Application examples:

#define APP_CUSTOM_EVENT_1  1
#define APP_CUSTOM_EVENT_2  2
#define APP_CUSTOM_EVENT_3  3
#define APP_CUSTOM_EVENT_4  4
#define APP_CUSTOM_EVENT_5  5

typedef struct {
    uint8_t data[50];
} custom_data_type_t;

void custom_data_process(int32_t evt_id,void *data)
{
    custom_data_type_t *event_1_data;
    TUYA_BLE_LOG_DEBUG("custom event id = %d",evt_id);
    switch (evt_id)
    {
        case APP_CUSTOM_EVENT_1:
            event_1_data = (custom_data_type_t *)data;
            TUYA_BLE_LOG_HEXDUMP_DEBUG("received APP_CUSTOM_EVENT_1 data:",event_1_data->data,50);
            break;
        case APP_CUSTOM_EVENT_2:
            break;
        case APP_CUSTOM_EVENT_3:
            break;
        case APP_CUSTOM_EVENT_4:
            break;
        case APP_CUSTOM_EVENT_5:
            break;
        default:
            break;

    }
}

custom_data_type_t custom_data;

void custom_evt_1_send_test(uint8_t data)
{
    tuya_ble_custom_evt_t event;

    for(uint8_t i=0; i<50; i++)
    {
        custom_data.data[i] = data;
    }
    event.evt_id = APP_CUSTOM_EVENT_1;
    event.custom_event_handler = (void *)custom_data_process;
    event.data = &custom_data;
    tuya_ble_custom_event_send(event);
}

tuya_ble_callback_queue_register

Application examples for OS platform:

void *tuya_custom_queue_handle;

os_msg_queue_create(&tuya_custom_queue_handle, MAX_NUMBER_OF_TUYA_CUSTOM_MESSAGE, sizeof(tuya_ble_cb_evt_param_t));

tuya_ble_callback_queue_register(tuya_custom_queue_handle);

Application example without OS platform:

void tuya_cb_handler(tuya_ble_cb_evt_param_t* event).

tuya_ble_callback_queue_register(tuya_cb_handler);

tuya_ble_event_response

Application examples:

 /*Application task to process ble sdk messages*/
void app_custom_task(void *p_param)
{
    tuya_ble_cb_evt_param_t event;

    while (true)
    {
        if (os_msg_recv(tuya_custom_queue_handle, &event, 0xFFFFFFFF) == true)
        {
            switch (event.evt)
            {
            case TUYA_BLE_CB_EVT_CONNECTE_STATUS:
                break;
            case TUYA_BLE_CB_EVT_DP_WRITE:
                break;
            case TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE:
                break;
            case TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE:
                break;
            case TUYA_BLE_CB_EVT_UNBOUND:
                break;
            case TUYA_BLE_CB_EVT_ANOMALY_UNBOUND:
                break;
            case TUYA_BLE_CB_EVT_DEVICE_RESET:
                break;
            case TUYA_BLE_CB_EVT_DP_QUERY:
                break;
            case TUYA_BLE_CB_EVT_OTA_DATA:
                break;
            case TUYA_BLE_CB_EVT_NETWORK_INFO:
                break;
            case TUYA_BLE_CB_EVT_WIFI_SSID:
                break;
            case TUYA_BLE_CB_EVT_TIME_STAMP:
                break;
            case TUYA_BLE_CB_EVT_TIME_NORMAL:
                break;
            case TUYA_BLE_CB_EVT_DATA_PASSTHROUGH:
                break;
            default:
                break;
            }

            tuya_ble_event_response(&event);
        }
    }

}

tuya_ble_scheduler_queue_size_get

tuya_ble_scheduler_queue_space_get

tuya_ble_scheduler_queue_events_get

The callback event of tuya ble sdk

The tuya ble sdk sends message of status, data, and other information to Application through message (for OS architecture platform) or callback function registered by Application (for non-OS architecture platform). According to the previous section, the example of tuya_ble_event_response describes how the Application in the OS architecture platform handle the messages sent by tuya ble sdk. The chip platform without an OS can use the similar code to process messages, however it is not necessary to call the tuya_ble_event_response() to respond to tuya ble sdk after the messages is handled by the callback function. As the following snippet shows an example for callback registration in the platform without an OS.

    /*Call back function for processing ble sdk messages*/
	static void tuya_cb_handler(tuya_ble_cb_evt_param_t* event)
	{
            switch (event->evt)
            {
            case TUYA_BLE_CB_EVT_CONNECTE_STATUS:
                break;
            case TUYA_BLE_CB_EVT_DP_WRITE:
                break;
            case TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE:
                break;
            case TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE:
                break;
            case TUYA_BLE_CB_EVT_UNBOUND:
                break;
            case TUYA_BLE_CB_EVT_ANOMALY_UNBOUND:
                break;
            case TUYA_BLE_CB_EVT_DEVICE_RESET:
                break;
            case TUYA_BLE_CB_EVT_DP_QUERY:
                break;
            case TUYA_BLE_CB_EVT_OTA_DATA:
                break;
            case TUYA_BLE_CB_EVT_NETWORK_INFO:
                break;
            case TUYA_BLE_CB_EVT_WIFI_SSID:
                break;
            case TUYA_BLE_CB_EVT_TIME_STAMP:
                break;
            case TUYA_BLE_CB_EVT_TIME_NORMAL:
                break;
            case TUYA_BLE_CB_EVT_DATA_PASSTHROUGH:
                break;
            default:
                break;
            }

    }

    void tuya_ble_app_init(void)
	{
		device_param.device_id_len = 16;
		memcpy(device_param.auth_key,(void *)auth_key_test,AUTH_KEY_LEN);
		memcpy(device_param.device_id,(void *)device_id_test,DEVICE_ID_LEN);
		device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
		device_param.product_id_len = 8;
		memcpy(device_param.product_id,APP_PRODUCT_ID,8);
		device_param.firmware_version = TY_APP_VER_NUM;
		device_param.hardware_version = TY_HARD_VER_NUM;

		tuya_ble_sdk_init(&device_param);
		tuya_ble_callback_queue_register(tuya_cb_handler);

		tuya_ota_init();
	}

TUYA_BLE_CB_EVT_CONNECTE_STATUS

Corresponding data structure:

typedef enum{
    UNBONDING_UNCONN = 0,
    UNBONDING_CONN,
    BONDING_UNCONN,
    BONDING_CONN,
    BONDING_UNAUTH_CONN,
    UNBONDING_UNAUTH_CONN,
    UNKNOW_STATUS
}tuya_ble_connect_status_t;

TUYA_BLE_CB_EVT_DP_WRITE

Corresponding data structure:

/*
 * dp data  buffer:  (Dp_id,Dp_type,Dp_len,Dp_data),(Dp_id,Dp_type,Dp_len,Dp_data),....
 * */
typedef struct{
	uint8_t *p_data;
	uint16_t data_len;
}tuya_ble_dp_write_data_t;

TUYA_BLE_CB_EVT_DP_QUERY

Corresponding data structure:

/*
 * query dp point data,if data_len is 0,means query all dp point data,otherwise query the dp point in p_data buffer.
 * */
typedef struct{
	uint8_t *p_data;
	uint16_t data_len;
}tuya_ble_dp_query_data_t;

TUYA_BLE_CB_EVT_OTA_DATA

Corresponding data structure:

typedef struct{
	tuya_ble_ota_data_type_t type;
	uint16_t data_len;
	uint8_t *p_data;
}tuya_ble_ota_data_t;

TUYA_BLE_CB_EVT_NETWORK_INFO

Corresponding data structure:

/*
 * network data,unformatted json data,for example " {"wifi_ssid":"tuya","password":"12345678","token":"xxxxxxxxxx"} "
 * */
typedef struct{
	uint16_t data_len;//include '\0'
	uint8_t *p_data;
}tuya_ble_network_data_t;

TUYA_BLE_CB_EVT_WIFI_SSID

Corresponding data structure:

/*
 * wifi ssid data,unformatted json data,for example " {"wifi_ssid":"tuya","password":"12345678"} "
 * */
typedef struct{
	uint16_t data_len;//include '\0'
	uint8_t *p_data;
}tuya_ble_wifi_ssid_data_t;

TUYA_BLE_CB_EVT_TIME_STAMP

Corresponding data structure:

/*
 * Unix timestamp
 * */
typedef struct{
	uint8_t timestamp_string[14];
	int16_t  time_zone;   //actual time zone Multiply by 100.
}tuya_ble_timestamp_data_t;

TUYA_BLE_CB_EVT_TIME_NORMAL

Corresponding data structure:

/*
 * normal time formatted
 * */
typedef struct{
	uint16_t nYear;
    uint8_t nMonth;
    uint8_t nDay;
    uint8_t nHour;
    uint8_t nMin;
    uint8_t nSec;
    uint8_t DayIndex; /* 0 = Sunday */
	int16_t time_zone;   //actual time zone Multiply by 100.
}tuya_ble_time_noraml_data_t;

TUYA_BLE_CB_EVT_DATA_PASSTHROUGH

Corresponding data structure:

typedef struct{
	uint16_t data_len;
	uint8_t *p_data;
}tuya_ble_passthrough_data_t;

TUYA_BLE_CB_EVT_DP_DATA_REPORT_RESPONSE

Corresponding data structure:

typedef struct{
	uint8_t status;
}tuya_ble_dp_data_report_response_t;

TUYA_BLE_CB_EVT_DP_DATA_WTTH_TIME_REPORT_RESPONSE

Corresponding data structure:

typedef struct{
	uint8_t status;
}tuya_ble_dp_data_with_time_report_response_t;

TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_REPORT_RESPONSE

Corresponding data structure:

typedef struct{
    uint16_t sn;
    tuya_ble_report_mode_t mode;
	uint8_t status;
}tuya_ble_dp_data_with_flag_report_response_t;

TUYA_BLE_CB_EVT_DP_DATA_WITH_FLAG_AND_TIME_REPORT_RESPONSE

Corresponding data structure:

typedef struct{
    uint16_t sn;
    tuya_ble_report_mode_t mode;
	uint8_t status;
}tuya_ble_dp_data_with_flag_and_time_report_response_t;

TUYA_BLE_CB_EVT_UNBOUND

Corresponding data structure:

typedef struct{
	uint8_t data;
}tuya_ble_unbound_data_t;

TUYA_BLE_CB_EVT_ANOMALY_UNBOUND

Corresponding data structure:

typedef struct{
	uint8_t data;
}tuya_ble_anomaly_unbound_data_t;

TUYA_BLE_CB_EVT_DEVICE_RESET

Corresponding data structure:

typedef struct{
	uint8_t data;
}tuya_ble_device_reset_data_t;

TUYA_BLE_CB_EVT_UPDATE_LOGIN_KEY_VID

Corresponding data structure:

typedef struct{
    uint8_t login_key_len;
    uint8_t vid_len;
	uint8_t login_key[LOGIN_KEY_LEN];
	uint8_t vid[DEVICE_VIRTUAL_ID_LEN];
}tuya_ble_login_key_vid_data_t;

Example of SDK port in nrf52832

This section takes nrf52832 as an example to describe the porting steps for the OS-free architecture platforms. You can contact your account manager in Tuya for the detailed procedure of nrf52832 and the demo of other platforms.

  1. Download the original SDK of nrf52832 chip, for example, nRF5_SDK_15.2.0_9412b96, and prepare a nrf52832 development board.

  2. Unzip the SDK to a custom directory, as shown in the following picture.

  3. Open the examples > ble_peripheral directories. In this directory, you can see tutorials of ble peripheral.

  4. Create a project with ble_app_uart as the template, and copy the ble_app_uart folder and rename it (for example, tuya_ble_standard_nordic).

  5. Enter the PCA10040 > S123 directories, open the project and compile it. You must confirm that it can be compiled and run correctly on the development board.

  6. Create a file with the ble_nus.c in the nRF_BLE_Services directory as the template and tuya_ble_service.c as the name, modify your code to cater for the tuya ble service, modify the code in the main.c file and broadcast the changes according the broadcasting content specified in the previous introduction.

  7. Compile and download to your development board and run, use Bluetooth scanning tool in your mobile phone (for example, LightBlue for iOS) to scan devices. Make sure that your scanning result meet the requirement of broadcasting and service.

  8. Download the tuya ble sdk to the directory of a new project, add the source files to the project and compile for once.

  9. Your project must have the same directories as the following pictures. Note that select correct library files.

  10. Create a custom_tuya_ble_config.h file, and save to the directories of your project, for example, tuya_ble_app.

    You must configure the items in the custom_tuya_ble_config.h according to your actual demand and environment. The tuya ble sdk provides references for some chip platforms. The reference configuration files are stored in each platform directory under the port directory in the tuya ble sdk folder.

  11. Assign the name of custom_tuya_ble_config.h to the CUSTOMIZED_TUYA_BLE_CONFIG_FILE file, and add to the macro of your project.

  12. Create port files, and the name can be tuya_ble_port_nrf52832.h and tuya_ble_port_nrf52832.c, or replace the nrf52832 with other platforms.

    In the port file, implement the interfaces listed in the tuya_ble_port.h file according to your configurations. Not all of the listed interfaces need to be implemented, for example, this porting tutorial does not involve OS, therefore, the OS-specific APIs are not needed. This tutorial is configured to use the internal memory management module of tuya ble sdk, therefore the memory allocation and release APIs are not needed. Under the port file of the tuya ble sdk, every platform is provided with porting reference file with the platform as the file name.

  13. After the port file is completed, define the port file in the custom_tuya_ble_config.h.

  14. Compile. If the compiling fails, examine your code first.

  15. In this tutorial, a specific file is created to handle the initialization of the tuya ble sdk, call back function registration, and callback message handling. As the following picture shows.

  16. Register the product in the Tuya IoT console and copy the product ID to your project code. The macro name APP_PRODUCT_ID, APP_BUILD_FIRMNAME, TY_APP_VER_NUM, TY_APP_VER_STR, TY_HARD_VER_NUM, and TY_HARD_VER_STR cannot be changed. Replace the xxxxxxxx as the product ID. If you use the test and production tooling authorization, contact your Tuya account manager to create a project for you, and replace the tuya_ble_sdk_app_demo_nrf52832 as the project name.

  17. Call the tuya_ble_app_init(), tuya_ble_main_tasks_exec(), tuya_ble_gatt_receive_data(), tuya_ble_common_uart_receive_data(), tuya_ble_disconnected_handler(), and tuya_ble_connected_handler() respectively in your code, as the following picture shows.

  18. During the development and debug stage, contact your Tuya account manager to obtain the auth_key_test and device_id_test.

  19. Compile your code, download the code to the development board, download Tuya Smart App, and scan to add devices.

OTA protocol

The firmware upgrade and the chip platform architecture are related, therefore the tuya ble sdk only provides a firmware upgrade interface, and your Application only needs to be implemented according to the OTA protocol described below through the OTA communication interface provided by tuya ble sdk.

The Application receives OTA data through the registered callback function (if the chip platform does not have OS) or registered queue (if the chip platform has an OS), the EVENT ID is TUYA_BLE_CB_EVT_OTA_DATA.

For the data format, see the upgrade protocol section. And the OTA response data is sent through the tuya_ble_ota_response(tuya_ble_ota_response_t *p_data) function.

OTA upgrade process

The following picture illustrates the process of OTA upgrade.

OTA upgrade protocol

OTA data types

typedef enum 

{

​ TUYA_BLE_OTA_REQ, // OTA Upgrade request command

​ TUYA_BLE_OTA_FILE_INFO, // OTA Upgrade file information command

​ TUYA_BLE_OTA_FILE_OFFSET_REQ, // OTA Upgrade file offset command

​ TUYA_BLE_OTA_DATA, // OTA Upgrade data command

​ TUYA_BLE_OTA_END, // End of OTA upgrade command

​ TUYA_BLE_OTA_UNKONWN,

}tuya_ble_ota_data_type_t;

typedef struct{

​ tuya_ble_ota_data_type_t type; 

​ uint16_t data_len;

​ uint8_t *p_data;

}tuya_ble_ota_data_t; //The mobile app sends the data struct corresponding to the OTA upgrade EVENT (TUYA_BLE_CB_EVT_OTA_DATA)..

typedef struct{

​ tuya_ble_ota_data_type_t type; 

​ uint16_t data_len;

​ uint8_t *p_data;

}tuya_ble_ota_response_t;  //Data struct corresponding to OTA response data sending function tuya_ble_ota_response(tuya_ble_ota_response_t *p_data)

OTA upgrade request (TUYA_BLE_OTA_REQ)

From App to BLE devices

From BLE devices to App

  • Flag: 0x00 indicates upgrade confirmation, 0x01 indicates upgrade denial.

  • OTA_Version: OTA Protocol version, for example 0x03 indicates the protocol version of 3.X.

  • Version: the current firmware version number in the big-endian format. For example, 0x00 01 00 02 indicates the version number is V1.0.2.

  • Maximum packet length: the maximum length of a single packet allowed by the device, unit: byte. The current version cannot exceed 512 bytes.

OTA upgrade file information (TUYA_BLE_OTA_FILE_INFO)

From App to BLE devices

  • product id: the PID.

  • file version: for example, 0x00010002 indicates the version is V1.0.2.

From BLE devices to App

  • STATE:

    0x00: upgrade success

    0x01: PID different

    0x02: the file version is lower than or equal to the current version

    0x03: file size is out of range.

  • Other: a reserved field.

  • File information has been saved: to support the resuming of the breakpoint, the file information that are stored in the device will be returned. After receiving the infomration, the App first calculates the CRC32 of the corresponding length of the new file according to the length of the stored file returned by the device, and then compares it with the CRC32 returned by the device. If the both are consistent, then in the following file start transmission request, the start transmission offset is changed to the length value. Otherwise, the file start transmission offset is changed to 0, indicating that the transmission starts from the beginning.

OTA upgrade file offset (TUYA_BLE_OTA_FILE_OFFSET_REQ)

From App to BLE devices

offset: upgrade file offset.

From BLE devices to App

offset: the starting file offset required by the device. The offset address of the actual file transfer should be based on the device requirements, and the address required by the device will be less or equal to the offset given by the App.

OTA Upgrade data (TUYA_BLE_OTA_DATA)

From App to BLE devices

The packet number starts from 0, and the high byte is at the beginning of the packet.

From BLE devices to App

STATE:

  • 0x00: success

  • 0x01: the package number is abnormal

  • 0x02: the length is inconsistent

  • 0x03: CRC check fails

  • 0x04: others

OTA upgrade is over (TUYA_BLE_OTA_END)

From App to BLE devices

From BLE devices to App

STATE:

  • 0x00: success

  • 0x01: the total data length is wrong

  • 0x02: the total CRC of data check fails

  • 0x03: others

    If you need to restart after verifying the success of the ble device OTA file, you can call the API tuya_ble_ota_response(tuya_ble_ota_response_t *p_data) to respond to the App result at least no delay and restart after 2 seconds.

OTA upgrade APIs

The Application receives OTA data through the registered callback function (without RTOS environment) or registered queue (in the RTOS environment), the EVENT ID is TUYA_BLE_CB_EVT_OTA_DATA. And the OTA response data is sent through tuya_ble_ota_response(tuya_ble_ota_response_t *p_data) function.

As the following picture shows, the Application calls the custom OTA processing function.

An example of OTA processing function:

void tuya_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
{
TUYA_BLE_LOG_DEBUG("ota cmd: 0x%04x , recv_len: %d",cmd,recv_len);
switch(cmd)
{
case TUYA_BLE_OTA_REQ:
tuya_ota_start_req(recv_data,recv_len);
break;
case TUYA_BLE_OTA_FILE_INFO:
tuya_ota_file_info_req(recv_data,recv_len);
break;
case TUYA_BLE_OTA_FILE_OFFSET_REQ:
tuya_ota_offset_req(recv_data,recv_len);
break;
case TUYA_BLE_OTA_DATA:
tuya_ota_data_req(recv_data,recv_len);
break;
case TUYA_BLE_OTA_END:
tuya_ota_end_req(recv_data,recv_len);
break;
default:
break;
}

}

Reference of production testing APIs

Before BLE devices are connected to Tuya IoT development platform, they must be burned with license information (one set of licenses for one device), which is usually burned in factory production. You can also use Tuya production testing tools to burn license and test. Alternatively, you can purchase licenses in batches, and use custom protocol and interface to manage them.

If you use custom protocol, you must set the auth_key and device_id when you initialize the tuya ble sdk. As the following sample shows.

tuya_ble_device_param_t device_param ;

void tuya_ble_app_init(void)
{
memset(&device_param,0,sizeof(tuya_ble_device_param_t));
device_param.device_id_len = 16;
memcpy(device_param.auth_key,(void *)auth_key_test,AUTH_KEY_LEN);
memcpy(device_param.device_id,(void *)device_id_test,DEVICE_ID_LEN);
device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
device_param.product_id_len = 8;
memcpy(device_param.product_id,APP_PRODUCT_ID,8);
device_param.firmware_version = TY_APP_VER_NUM;
device_param.hardware_version = TY_HARD_VER_NUM;

tuya_ble_sdk_init(&device_param);
tuya_ble_callback_queue_register(tuya_cb_handler);

tuya_ota_init();

TUYA_APP_LOG_INFO("app version: "TY_APP_VER_STR);
}

If you use the authorization tool of Tuya production testing to burn the license and you use the tuya ble sdk to manage authorization, then the auth_key and device_id are not needed when you initialize the tuya ble sdk. As the following sample shows.

tuya_ble_device_param_t device_param ;

void tuya_ble_app_init(void)
{
memset(&device_param,0,sizeof(tuya_ble_device_param_t));
device_param.device_id_len = 0;
device_param.p_type = TUYA_BLE_PRODUCT_ID_TYPE_PID;
device_param.product_id_len = 8;
memcpy(device_param.product_id,APP_PRODUCT_ID,8);
device_param.firmware_version = TY_APP_VER_NUM;
device_param.hardware_version = TY_HARD_VER_NUM;

tuya_ble_sdk_init(&device_param);
tuya_ble_callback_queue_register(tuya_cb_handler);

tuya_ota_init();

TUYA_APP_LOG_INFO("app version: "TY_APP_VER_STR);
}

If you use the authorization tool of Tuya production testing to burn the license, make sure that the TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT is enabled by setting #define TUYA_BLE_DEVICE_AUTH_SELF_MANAGEMENT 1.

The production testing consists of the general authorization testing and the general device testing, and the general machine testing is subordinate to the general authorization testing. The general authorization testing includes authorization burning, GPIO testing and RSSI testing. The general device testing provides additional testing for tailored products, you can see the Bluetooth General Authorization Protocol of Production Testing or Bluetooth General Device Testing Protocol of Production Testing for more information.

The tuya ble sdk has achieved the protocol of general authorization testing, however, testing such as RSSI testing, GPIO testing and additional testing for tailored products provided by general device testing must be implemented according to the product configuration. The source file tuya_ble_app_production_test.c in the tuya ble sdk has prepared APIs for the preceding testings, and they are defined in the form of __TUYA_BLE_WEAK weak implement. Your Application can redefine those APIs in other source files, for example, creating a custom_app_product_test.c file, and referring to it in your custom configuration file. As the following pictures show.

Last updated