Last Updated on : 2024-11-20 02:14:53download
This topic describes how to develop a temperature and humidity sensor by using Tuya’s Bluetooth module and the Bluetooth SDK.
Create a temperature and humidity sensor on the Tuya Developer Platform. For more information, see Create Products.
You will need the following to proceed:
If you use the BTU module or module built with the same chip platform, have the above items ready before development. The microcontroller board and function board are optional. If you use Tuya’s Bluetooth module of a different chip platform, see Set up Development Environment and documentation from the chip vendor for environment setup.
See Flash Firmware and Authorize Module to flash the initial firmware to the module and authorize it to connect to the cloud by using the Cloud Module Burning Authorization Platform. Then, pair the device with the Smart Life app to verify cloud connectivity. Then, you can use Telink BDT to flash firmware to the module when you debug the code.
Walk through the following steps to try out the demo.
app_demo
from GitHub repository tuya-ble-sdk-development-course-demo.tuya_ble_sdk_demo.h
in the app_demo
directory to your project. Make sure to replace the value of the PID and firmware version with your own. Then, set up the include path.use_ext_license_key
and device_id_len
according to the authorization solution you use.If you use Tuya’s Bluetooth module of a different chip platform, there is no need to copy the board directory under app_demo
to your project, but make sure to check if the API functions in the board
directory are implemented. You should use the flashing tool provided by the chip vendor to flash firmware to your board.
Use the SDK for TLSR825x
as an example to describe the SDK directory.
├── ble_sdk_multimode
| ├── telink_sdk /* SDK from the chip vendor */
| ├── tuya_ble_sdk_demo /* Tuya Bluetooth SDK and the demo, which are adapted to the TLSR825x platform. */
| | ├── app /* The application code with demos included. You can develop on top of it. */
| | ├── board /* The chip platform specific code, including the peripheral hardware abstraction and the `tuya_ble_sdk`-specific port API and application configuration file. */
| | ├── components /* The component code, including generic components. Your custom components can be put here. */
| | ├── doc /* Documentation */
| | ├── tools /* Toolkit */
| | └── tuya_ble_sdk /* Tuya Bluetooth SDK. It implements the communication between smart devices and Smart Life app as well as task scheduler. */
| |
| └── .cproject and others /* The project file. */
|
├── CHANGELOG.md /* The changelog. */
├── README.md /* README in English */
└── README_zh-CN /* README in Chinese */
tuya_ble_sdk_demo
tuya_ble_sdk_demo.c
: Implements tuya_ble_sdk
initialization and includes the event scheduler APIs of the application layer.tuya_ble_sdk_test.c
: Includes serial commands for testing tuya_ble_sdk
. It is used for testing only and irrelevant to the application.tuya_ble_bulk_data_demo.c
: Includes the routine for bulk transfer.tuya_ble_product_test_demo.c
: Includes the routine for end product test.component
external\easylogger
: The logger to print debug messages.board
TLSR825X\ty_board_tlsr825x
: Peripheral hardware abstraction.TLSR825X\tuya_ble_port
: Includes the tuya_ble_sdk
-specific port API and application configuration file.TLSR825X\ota
: OTA update implementation for different chip platforms. They use the same serial transmission protocols, but different flash operations.tuya_ble_sdk_demo_init
: The Bluetooth SDKs for different chip platforms come with demos, allowing you to directly develop on top of tuya_ble_sdk_demo.c
. tuya_ble_sdk_demo_init
is used to initialize the demo. Add your application initialization code at the end of this function.
void tuya_ble_sdk_demo_init(void)
{
/* Whether to use the license in `tuya_ble_sdk_demo.h` to configure the related parameters. */
if (tuya_ble_device_param.use_ext_license_key) {
memcpy(tuya_ble_device_param.device_id, device_id_test, DEVICE_ID_LEN);
memcpy(tuya_ble_device_param.auth_key, auth_key_test, AUTH_KEY_LEN);
memcpy(tuya_ble_device_param.mac_addr_string, TY_DEVICE_MAC, MAC_STRING_LEN);
}
/* Configure PID and device name */
memcpy(tuya_ble_device_param.product_id, TY_DEVICE_PID, tuya_ble_device_param.product_id_len);
memcpy(tuya_ble_device_param.adv_local_name, TY_DEVICE_NAME, tuya_ble_device_param.adv_local_name_len);
/* Initialize tuya_ble_sdk. */
tuya_ble_sdk_init(&tuya_ble_device_param);
/* Register tuya_ble_sdk callback */
tuya_ble_callback_queue_register(tuya_ble_sdk_callback);
/* Initialize OTA and timer */
tuya_ble_ota_init();
tuya_ble_disconnect_and_reset_timer_init();
tuya_ble_update_conn_param_timer_init();
/* Initialize applications of the smart product */
tuya_ble_app_init();
}
tuya_ble_main_tasks_exec
: If you do not use the RTOS, this function is used as the event scheduler of the Bluetooth SDK for cyclic execution. It is located in tuya_ble_main.c
. You can put tasks in this function to cycle them. Alternatively, we recommend you create a timer to schedule task execution. For more information, see Software timer.
void tuya_ble_main_tasks_exec(void)
{
/* The main loop of applications of the smart product */
tuya_ble_app_loop();
/* The main scheduler */
tuya_sched_execute();
}
API list
Function name | Description |
---|---|
TUYA_APP_LOG_ERROR | Print error messages. |
TUYA_APP_LOG_WARNING | Print warning messages. |
TUYA_APP_LOG_INFO | Print information messages. |
TUYA_APP_LOG_DEBUG | Print debugging messages. |
API description
API file: tuya_ble_log.h
/* Enable/disable logger */
#define TUYA_APP_LOG_ENABLE 1 /* 0: Disable. 1: Enable. (custom_tuya_ble_config.h) */
#define TY_LOG_ENABLE 1 /* 0: Disable. 1: Enable. (board.h) */
158: /* Set logging levels */
#defien TUYA_APP_LOG_LEVEL TUYA_APP_LOG_LEVEL_DEBUG
/**
* @brief Print logs. You can replace xxxx with ERROR, WARNING, INFO, or DEBUG.
* @param[in] format: Format control
* @param[in] …: Variable parameter
* @return None
*/
void TUYA_APP_LOG_xxxx(const char *format, …)
Sample application
TUYA_APP_LOG_xxxx("tuya_ble_sdk_init succeeded.");
TUYA_APP_LOG_xxxx("tuya_ble_sdk_init failed, error code: %d.", res);
TUYA_APP_LOG_xxxx("receive data: %x.", data);
API list
Function name | Description |
---|---|
tuya_ble_timer_create | Create a timer. |
tuya_ble_timer_start | Start a specified timer. |
tuya_ble_timer_stop | Stop a specified timer. |
tuya_ble_timer_restart | Restart a specified timer. |
tuya_ble_timer_delete | Delete a specified timer. |
API description
API file: tuya_ble_port.h
/**
* @brief Create a timer
* @param[in] p_timer_id: Timer ID
* @param[in] timeout_value_ms: Timeout period in milliseconds
* @param[in] mode: Working mode
* @param[in] timeout_handler: Timeout handler
* @return The operation result
*/
tuya_ble_status_t tuya_ble_timer_create(void** p_timer_id,
uint32_t timeout_value_ms,
tuya_ble_timer_mode mode,
tuya_ble_timer_handler_t timeout_handler);
/**
* @brief Start the specified timer
* @param[in] timer_id: Timer ID
* @return The operation result
*/
tuya_ble_status_t tuya_ble_timer_start(void* timer_id);
/**
* @brief Stop the specified timer
* @param[in] timer_id: Timer ID
* @return The operation result
*/
tuya_ble_status_t tuya_ble_timer_stop(void* timer_id);
/**
* @brief Restart the specified timer
* @param[in] timer_id: Timer ID
* @return The operation result
*/
tuya_ble_status_t tuya_ble_timer_restart(void* timer_id, uint32_t timeout_value_ms);
/**
* @brief Delete the specified timer
* @param[in] timer_id: Timer ID
* @return The operation result
*/
tuya_ble_status_t tuya_ble_timer_delete(void* timer_id);
Data type
/* Timer working mode */
typedef enum {
TUYA_BLE_TIMER_SINGLE_SHOT, /* One-time task. The timer stops counting when it expires. */
TUYA_BLE_TIMER_REPEATED, /* Recurring task. The timer begins counting again when it expires. */
} tuya_ble_timer_mode;
/* The type of timer callback */
typedef void (*tuya_ble_timer_handler_t)(void*);
Sample application
After power-on, the indicator comes on for two seconds and then goes off. When the button is pressed, the indicator comes on for five seconds and then goes off.
#include "tuya_ble_port.h"
#include "ty_pin.h"
/* Pin */
#define KEY_PIN GPIO_PA0 /* KEY */
#define LED_PIN GPIO_PD7 /* LED */
/* The timer period */
#define KEY_SCAN_TIME_MS 10 /* 10ms */
#define LED_TURN_TIME_MS_1 2000 /* 2s */
#define LED_TURN_TIME_MS_2 5000 /* 5s */
/* The deletion flag of a timer */
uint8_t delete_flag = 0;
/* Timer ID */
tuya_ble_timer_t key_timer;
tuya_ble_timer_t led_timer;
/**
* @brief key_timer Timeout handler
* @param None
* @return None
*/
void key_timer_cb(void)
{
/* Read the voltage level on the button pin */
ty_pin_level_t pin_level;
ty_pin_get(KEY_PIN, &pin_level);
if (TY_PIN_LOW == pin_level) {
/* Turn on the LED and restart the led_timer that expires after 5s. */
ty_pin_set(LED_PIN, TY_PIN_HIGH);
tuya_ble_timer_restart(led_timer, LED_TURN_TIME_MS_2);
/* Stop the key_timer and set the key_timer to be deletable. */
tuya_ble_timer_stop(key_timer);
delete_flag = 1;
}
}
/**
* @brief led_timer Timeout handler
* @param None
* @return None
*/
void led_timer_cb(void)
{
/* Turn off the LED */
ty_pin_set(LED_PIN, TY_PIN_LOW);
if (delete_flag) {
/* Delete the key_timer */
tuya_ble_timer_delete(key_timer);
} else {
/* Start the key_timer */
tuya_ble_timer_start(key_timer);
}
}
/**
* @brief Initialize functions
* @param None
* @return None
*/
void app_init(void)
{
/* Initialize the button and LED pin and turn on the LED. */
ty_pin_init(KEY_PIN, TY_PIN_MODE_IN_PU);
ty_pin_init(LED_PIN, TY_PIN_MODE_OUT_PP_LOW);
ty_pin_set(LED_PIN, TY_PIN_HIGH);
/* Create a recurring key_timer that expires after 10 ms. Register the timeout handler key_timer_cb. */
tuya_ble_timer_create(&key_timer, KEY_SCAN_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)key_timer_cb);
/* Create and start a one-time led_timer that expires after 2s. Register the timeout handler led_timer_cb. */
tuya_ble_timer_create(&led_timer, LED_TURN_TIME_MS_1, TUYA_BLE_TIMER_SINGLE_SHOT, (tuya_ble_timer_handler_t)led_timer_cb);
tuya_ble_timer_start(led_timer);
}
API list
Function name | Description |
---|---|
tuya_ble_dp_data_send | Send data point (DP) data to the cloud. |
API description
API file: tuya_ble_api.h
/**
* @brief Send DP data.
* @param[in] sn: The sequence number of DP data transmission, which is defined and managed by the application and incremented by 1 with each operation.
* @param[in] type: The transmission type.
* @param[in] mode: The transmission mode.
* @param[in] ack: The acknowledgement flag.
* @param[in] p_dp_data: DP data.
* @param[in] dp_data_len: The total length of data, which cannot exceed TUYA_BLE_SEND_MAX_DATA_LEN-7.
* @return The operation result
*/
tuya_ble_status_t tuya_ble_dp_data_send(uint32_t sn,
tuya_ble_dp_data_send_type_t type,
tuya_ble_dp_data_send_mode_t mode,
tuya_ble_dp_data_send_ack_t ack,
uint8_t *p_dp_data,
uint32_t dp_data_len);
Data type
/* The transmission type */
typedef enum {
DP_SEND_TYPE_ACTIVE = 0, /* The device proactively sends DP data. */
DP_SEND_TYPE_PASSIVE, /* The device responds to DP data queries from the app. */
} tuya_ble_dp_data_send_type_t;
/* The transmission mode */
typedef enum {
DP_SEND_FOR_CLOUD_PANEL = 0, /* The app sends the received data to the cloud and the control panel for data updating. */
DP_SEND_FOR_CLOUD, /* The app sends the received data to the cloud only. */
DP_SEND_FOR_PANEL, /* The app sends the received data to the control panel for data updating only. */
DP_SEND_FOR_NONE, /* The app sends data neither to the cloud nor to the control panel. */
} tuya_ble_dp_data_send_mode_t;
/* The response mode */
typedef enum {
DP_SEND_WITH_RESPONSE = 0, /* A response from the app is required. */
DP_SEND_WITHOUT_RESPONSE, /* A response from the app is not required. */
} tuya_ble_dp_data_send_ack_t;
Description
The DP is used to represent device functions defined on the Tuya Developer Platform. The DP model abstracts away the data that a device generates. It consists of DP ID, DP data type, DP data length, and DP data. For more information, see Custom Functions.
The Bluetooth SDK respects the following DP data format.
Field | Length (byte) | Description |
---|---|---|
dp_id | 1 | The ID of a DP. |
dp_type | 1 | The data type of a DP. |
dp_len | 2 | The data length of a DP. |
dp_data | dp_len | The DP data. |
The data type and length respect the following rules.
dp_type | Identifier | Value | dp_len |
---|---|---|---|
Raw | DT_RAW | 0 | 1 to 255 |
Boolean | DT_BOOL | 1 | 1 |
Value | DT_VALUE | 2 | 4 |
String | DT_STRING | 3 | 0 to 255 |
Enum | DT_ENUM | 4 | 1 |
The maximum length of a DP is specified when you define a DP on the Tuya Developer Platform. If dp_type
is 0 or 3, dp_len
can be customized but must not exceed the maximum length defined on the Tuya Developer Platform.
The data that p_dp_data
of tuya_ble_dp_data_send
points to must be concatenated in the following format.
Data point (DP) | Data of the first DP | Data of the second DP | … | ||||||
---|---|---|---|---|---|---|---|---|---|
Byte | 0 | 1 | 2 to 3 | 4 to n-1 | n | n+1 | n+2 to n+3 | n+4 to m-1 | … |
Field | dp1_id | dp1_type | dp1_len | dp1_data | dp2_id | dp2_type | dp2_len | dp2_data | … |
n-1
= (4 + dp1_len
) − 1. m-1
= n + (4 + dp2_len
) – 1.
You can send the data of multiple DPs at a time. Make sure the total length does not exceed TUYA_BLE_SEND_MAX_DATA_LEN-7
. The parameter TUYA_BLE_SEND_MAX_DATA_LEN
is configurable.
Sample application
When the temperature is updated, the device reports the temperature data. If Bluetooth is connected, it reports data of all DPs.
/* DP ID */
#define DP_ID_TEMP_CURRENT 1 /* Temperature */
#define DP_ID_TEMP_ALARM 14 /* Temperature alert */
/* DP data type. You can use the definition in the `tuya_ble_mutli_tsf_protocol.h` file. */
#define DT_RAW 0 /* Raw */
#define DT_BOOL 1 /* Boolean */
#define DT_VALUE 2 /* Value */
#define DT_STRING 3 /* String */
#define DT_ENUM 4 /* Enum */
/* The field offset of DP model */
#define DP_DATA_INDEX_OFFSET_ID 0 /* dp_id */
#define DP_DATA_INDEX_OFFSET_TYPE 1 /* dp_type */
#define DP_DATA_INDEX_OFFSET_LEN_H 2 /* dp_len */
#define DP_DATA_INDEX_OFFSET_LEN_L 3 /* dp_len */
#define DP_DATA_INDEX_OFFSET_DATA 4 /* dp_data */
/* DP data variable */
static int32_t sg_cur_temp = 0, sg_prv_temp = 0;
static uint8_t sg_temp_alarm = 0;
/* The DP array assembled for reporting */
static uint8_t sg_repo_array[255+4];
/* The sequence number of data transmission */
static uint32_t sg_sn = 0;
/**
* @brief Report data of a DP.
* @param[in] dp_id: DP ID
* @param[in] dp_type: DP data type.
* @param[in] dp_len: DP data length.
* @param[in] dp_data: DP data
* @return None
*/
static void __report_one_dp_data(const uint8_t dp_id, const uint8_t dp_type, const uint16_t dp_len, const uint8_t *dp_data)
{
uint16_t i;
/* Save DP data to an array. */
sg_repo_array[DP_DATA_INDEX_OFFSET_ID] = dp_id;
sg_repo_array[DP_DATA_INDEX_OFFSET_TYPE] = dp_type;
sg_repo_array[DP_DATA_INDEX_OFFSET_LEN_H] = (uint8_t)(dp_len >> 8);
sg_repo_array[DP_DATA_INDEX_OFFSET_LEN_L] = (uint8_t)dp_len;
for (i = 0; i < dp_len; i++) {
sg_repo_array[DP_DATA_INDEX_OFFSET_DATA + i] = *(dp_data + (dp_len-i-1));
}
/* Call an API to send DP data. */
tuya_ble_dp_data_send(sg_sn++, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITHOUT_RESPONSE, sg_repo_array, dp_len + DP_DATA_INDEX_OFFSET_DATA);
}
/**
* @brief Report temperature data.
* @param None
* @return None
*/
void app_repo_dp_temp(void)
{
if (sg_cur_temp != sg_prv_temp)) {
__report_one_dp_data(DP_ID_TEMP_CURRENT, DT_VALUE, 4, (uint8_t *)&sg_cur_temp);
sg_prv_temp = sg_cur_temp;
}
}
/**
* @brief Add DP data.
* @param[in] dp_id: DP ID
* @param[in] dp_type: DP data type.
* @param[in] dp_len: DP data length.
* @param[in] dp_data: DP data
* @param[in] addr: The start address of DP data storage.
* @return The total length of stored data.
*/
static uint8_t __add_one_dp_data(const uint8_t dp_id, const uint8_t dp_type, const uint16_t dp_len, const uint8_t *dp_data, uint8_t *addr)
{
uint16_t i;
*(addr + DP_DATA_INDEX_OFFSET_ID) = dp_id;
*(addr + DP_DATA_INDEX_OFFSET_TYPE) = dp_type;
*(addr + DP_DATA_INDEX_OFFSET_LEN_H) = (UCHAR_T)(dp_len >> 8);
*(addr + DP_DATA_INDEX_OFFSET_LEN_L) = (UCHAR_T)dp_len;
for (i = 0; i < dp_len; i++) {
*(addr + DP_DATA_INDEX_OFFSET_DATA + i) = *(dp_data + (dp_len-i-1));
}
return (dp_len + DP_DATA_INDEX_OFFSET_DATA);
}
/**
* @brief Report all DP data.
* @param None
* @return None
*/
void app_repo_dp_all(void)
{
uint32_t total_len = 0;
/* Add all data to DP array assembled for reporting. */
total_len += __add_one_dp_data(DP_ID_TEMP_CURRENT, DT_VALUE, 4, &sg_cur_temp, sg_repo_array);
total_len += __add_one_dp_data(DP_ID_TEMP_ALARM, DT_ENUM, 1, &sg_temp_alarm, sg_repo_array+total_len);
/* Call an API to send DP data. */
tuya_ble_dp_data_send(sg_sn++, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITHOUT_RESPONSE, sg_repo_array, total_len);
}
API list
Function name | Description |
---|---|
tuya_ble_connect_status_get | Query Bluetooth connection status. |
tuya_ble_device_unbind | Unbind a device locally, without clearing the virtual device ID. |
tuya_ble_device_factory_reset | Reset a device and clear the virtual device ID. |
The virtual device ID manages the historical data in the cloud.
API description
API file: tuya_ble_api.h
/**
* @brief Query Bluetooth connection status.
* @param None
* @return Bluetooth connection status.
*/
tuya_ble_connect_status_t tuya_ble_connect_status_get(void);
/**
* @brief Unbind a device locally.
* @param None
* @return The operation result
*/
tuya_ble_status_t tuya_ble_device_unbind(void);
/**
* @brief Reset a device.
* @param None
* @return The operation result
*/
tuya_ble_status_t tuya_ble_device_factory_reset(void);
Data type
/* Bluetooth connection status */
typedef enum {
UNBONDING_UNCONN = 0, /* The device is unbound and not connected. */
UNBONDING_CONN, /* The device is unbound and connected. */
BONDING_UNCONN, /* The device is bound and not connected. */
BONDING_CONN, /* The device is bound and connected. */
BONDING_UNAUTH_CONN, /* The device is bound, connected, and unauthenticated. */
UNBONDING_UNAUTH_CONN, /* The device is unbound, connected, and unauthenticated. */
UNKNOW_STATUS /* Unknown status */
} tuya_ble_connect_status_t;
The following table lists the possible Bluetooth connection status.
Bluetooth connection status | Description |
---|---|
Unbound and not connected | A device is neither registered with the cloud nor connected over Bluetooth. If the device is advertising, it is ready for pairing. |
Unbound and connected | An unbound device is being connected over Bluetooth. |
Bound and not connected | A Bluetooth device is offline. The device is bound with but not connected to the app. |
Bound and connected | A Bluetooth device is online. The device establishes a secure connection with the app through the Tuya-specific Bluetooth protocol. |
Bound, connected, and unauthenticated | This status occurs when a device is being paired or reconnected, indicating a Bluetooth connection is just made. |
Unbound, connected, and unauthenticated | A device is connected over Bluetooth, but is not discoverable currently. |
Sample application
When the application requests to pair again, it queries Bluetooth connection status first. If the device has been bound, the application calls the API to request unbinding. When the application requests to reset the device, it calls the API for a reset.
/**
* @brief Unbind a device.
* @param None
* @return None
*/
void app_unbind(void)
{
tuya_ble_connect_status_t ble_conn_sta = tuya_ble_connect_status_get();
if ((ble_conn_sta == BONDING_UNCONN) ||
(ble_conn_sta == BONDING_CONN) ||
(ble_conn_sta == BONDING_UNAUTH_CONN)) {
tuya_ble_device_unbind();
}
}
/**
* @brief Reset a device.
* @param None
* @return None
*/
void app_reset(void)
{
tuya_ble_device_factory_reset();
}
tuya_ble_sdk_callback
is in tuya_ble_sdk_demo.c
. This is a message callback registered on initialization, which the Bluetooth SDK uses to send messages such as status and data to the device application. Add the code to process under the corresponding case
statement.
The following table lists the common events. For more information, see API Reference.
Event | Description |
---|---|
TUYA_BLE_CB_EVT_CONNECTE_STATUS | The Bluetooth SDK sends this event to the device application on changes in Bluetooth status. |
TUYA_BLE_CB_EVT_DP_DATA_RECEIVED | The Bluetooth SDK receives DP data from the mobile app. |
TUYA_BLE_CB_EVT_DP_QUERY | The Bluetooth SDK receives an array of queried DP IDs from the mobile app. |
TUYA_BLE_CB_EVT_OTA_DATA | The Bluetooth SDK receives OTA firmware updates from the mobile app. |
TUYA_BLE_CB_EVT_TIME_STAMP | The Bluetooth SDK receives the timestamp in string format from the mobile app. |
TUYA_BLE_CB_EVT_TIME_NORMAL | The Bluetooth SDK receives time data in general format from the mobile app. |
TUYA_BLE_CB_EVT_UNBOUND | The Bluetooth SDK receives an unbinding command from the mobile app. |
TUYA_BLE_CB_EVT_ANOMALY_UNBOUND | The Bluetooth SDK receives an offline removing command from the mobile app. |
This demo implements the following features:
Feature | Description |
---|---|
Data acquisition | The sensor collects the temperature and humidity data every second. When the temperature and humidity change, the sensor reports the current data to the mobile app for updating the control panel display. |
Threshold alerts | Set upper and lower limits on temperature and humidity by using the app. If one of the metrics goes above or below that limit, the sensor will send a notification to the mobile app. |
Pairing indication | - The indicator blinks when the device is not bound. - The indicator comes off when the device is bound. - The indicator blinks when the device is unbound. |
Add the standard functions shown in the following figure to your product to implement the above-listed features.
Note that if you modify the definition of a DP or an error occurs on the control panel display, unbinding and binding the device again is recommended.
The Bluetooth SDK comes with a basic file structure. The application code is stored in tuya_ble_sdk_demo\app
. The component code is stored in tuya_ble_sdk_demo\components
.
The demo directory is shown below.
tuya_ble_sdk_demo
├── app /* Application */
| ├── include /* Header directory, having the same file name as the src directory */
| └── src /* Source directory */
| ├── tuya_ble_bulk_data_demo.h /* The routine for bulk transfer */
| ├── tuya_ble_product_test_demo.h /* The routine for end product test */
| ├── tuya_ble_sdk_demo.h /* Implements tuya_ble_sdk initialization. The entry point to application. */
| ├── tuya_ble_sdk_test.h /* Implements the serial commands for tuya_ble_sdk testing */
| └── tuya_ble_sensor_rht_demo.h /* The sample of temperature and humidity sensor application */
├── board
├── components /* Component */
| ├── external
| ├── ty_oled
| └── ty_sht3x /* SHT3x driver component */
| ├── ty_sht3x.c
| └── ty_sht3x.h
├── doc
├── tools
└── tuya_ble_sdk
Create src
and include
folders in app
. Copy the sample file tuya_ble_sdk_demo.c
to the folder by kind. Create tuya_ble_sensor_rht_demo.c
and tuya_ble_sensor_rht_demo.h
in src
and include
to write the sample code of the temperature and humidity sensor application. Create ty_sht3x
folder in components
and then create ty_sht3x.c
and ty_sht3x.h
files to write SHT3x driver code.
Configure project
Since we add some include directories in the above step, we need to add their path in the project property. Otherwise, the compilation will fail. Add the directory path as instructed below and verify the compilation.
No. | Symbol | I/O type | Usage | Notes |
---|---|---|---|---|
1 | D3 | I/O | - | - |
2 | D7 | I/O | LED control | LED indicator on the microcontroller board. It comes on at high level. |
3 | C0 | I/O | I2C bus – SDA line | Corresponds to SDA on the temperature and humidity board. |
4 | SWS | I/O | SWS | Used to flash firmware using Telink programmer. |
5 | B6 | I | - | - |
6 | A0 | I/O | - | - |
7 | A1 | I/O | - | - |
8 | C2 | I/O | - | - |
9 | C3 | I/O | Log printing | Used to debug serial communication. |
10 | D2 | I/O | - | - |
11 | B4 | I/O | - | - |
12 | B5 | I/O | - | - |
13 | GND | P | GND | The ground pin. |
14 | VCC | P | VCC | 3.3V |
15 | B1 | I/O | TX pin for serial communication. | Used to flash firmware over the serial port. |
16 | B7 | I/O | TX pin for serial communication. | Used to flash firmware over the serial port. |
17 | C4 | I/O | - | - |
18 | RST | I/O | RST | Reset button on the microcontroller board. |
19 | C1 | I/O | I2C bus – SCL line | Corresponds to SCL on the temperature and humidity board. |
20 | D4 | I/O | - | - |
21 | NC | I/O | - | - |
The following code snippet shows where to modify these pins. You can find the configuration function by macro name and edit the pin function.
/* tuya_ble_sensor_rht_demo.c */
#define LED_PIN GPIO_PD7
/* ty_i2c_tlsr825x.c */
#define I2C_PIN_SDA GPIO_PC0
#define I2C_PIN_SCL GPIO_PC1
/* ty_uart_tlsr825x.c */
#define TLSR_UART_GPIO_TX UART_TX_PB1
#define TLSR_UART_GPIO_RX UART_RX_PB7
/* telink_sdk\vendor\8258_module\app_config.h */
#define DEBUG_INFO_TX_PIN GPIO_PC3
#define PC3_FUNC AS_GPIO
#define PC3_INPUT_ENABLE 0
#define PC3_OUTPUT_ENABLE 1
#define PC3_DATA_OUT 1
This demo uses the Tuya Sandwich temperature and humidity board to collect data. This board has a Sensirion’s SHT30-DIS temperature and humidity sensor, using the I2C protocol. Its peripheral is controlled by ADDR pin (Pin2). When ADDR
is connected to GND, the device address is 0x44
. When ADDR
is connected to VDD
, the device address is 0x45
.
Download official materials:
tuya_ble_sdk_demo_init
Located in tuya_ble_sdk_demo.c
Add tuya_ble_sensor_rht_init
at the end of tuya_ble_sdk_demo_init
to initialize the temperature and humidity sensor.
/**
* @brief The entry point to application initialization.
* @param None
* @return None
*/
void tuya_ble_sdk_demo_init(void)
{
/* ... */
/* Initialize the temperature and humidity sensor sample application */
tuya_ble_sensor_rht_init();
}
tuya_ble_sensor_rht_init
Located in tuya_ble_sensor_rht_demo.c
/* The data scale. 1 represents 10 to the 1 power. */
#define TEMP_SCALE 1 /* Temperature data: 10 times the original data */
#define HUMI_SCALE 1 /* Humidity data: 10 times the original data */
/* Data collection cycle */
#define SHT3X_PERI_TIME_MS 1000 /* 1s / 1Hz */
/* The type of temperature and humidity data */
typedef struct {
int32_t temp; /* The temperature value. */
int32_t humi; /* The humidity value. */
uint8_t temp_alarm; /* Temperature threshold to trigger alerts. */
uint8_t humi_alarm; /* Humidity threshold to trigger alerts. */
} RHT_DP_DATA_T;
/* Temperature and humidity data */
static RHT_DP_DATA_T sg_rht_data = {
.temp = 0, /* Temperature. Initial value: 0 */
.humi = 0, /* Humidity. Initial value: 0 */
.temp_alarm = ALARM_CANCEL, /* Temperature alert. Initial value: Alert canceled. */
.humi_alarm = ALARM_CANCEL /* Humidity alert. Initial value: Alert canceled. */
};
/* Timer for temperature and humidify collection */
static tuya_ble_timer_t sg_rht_daq_timer;
/**
* @brief Initialize temperature and humidity sensor application
* @param None
* @return None
*/
void tuya_ble_sensor_rht_init(void)
{
/* Print notification: Start the temperature and humidity sensor sample application */
TUYA_APP_LOG_INFO("Sensor RH-T demo start.");
/* Initialize networking */
__net_proc_init();
/* Initialize the SHT3x driver. The ADDR pin is connected to ground. */
ty_sht3x_init(false);
/* Measure data once and save the reading to sg_rht_data, with data multiplied by 10 times. */
if (ty_sht3x_measure_single_shot(&sg_rht_data.temp, &sg_rht_data.humi, TEMP_SCALE, HUMI_SCALE)) {
/* Print debugging message: Output the temperature and humidity data in integer. */
TUYA_APP_LOG_DEBUG("Temperature: %d, Humidity: %d", sg_rht_data.temp, sg_rht_data.humi);
} else {
/* Print error message: Failed to execute ty_sht3x_measure_single_shot. */
TUYA_APP_LOG_ERROR("ty_sht3x_measure_single_shot failed.");
}
/* Start scheduled measurement of high repetition, with a sampling frequency of 1 Hz. */
ty_sht3x_start_periodic_measure(REPEATAB_HIGH, FREQ_1HZ);
/* Create and start a recurring sg_rht_daq_timer that expires after 1s. Register the handler __rht_daq_timer_handler. */
tuya_ble_timer_create(&sg_rht_daq_timer, SHT3X_PERI_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__rht_daq_timer_handler);
tuya_ble_timer_start(sg_rht_daq_timer);
}
__net_proc_init
Located in tuya_ble_sensor_rht_demo.c
/* Pin definition */
#define LED_PIN GPIO_PD7 /* LED pin */
/* Blinking interval */
#define LED_TIMER_VAL_MS 300 /* 300ms */
/* Timer for LED blinking control */
static tuya_ble_timer_t sg_led_flash_timer;
/* The flag of LED status */
static uint8_t sg_led_status = 0;
/**
* @brief Initialize networking.
* @param None
* @return None
*/
static void __net_proc_init(void)
{
/* Initialize LED pin (PD7). Push-pull output and low level in the initial stage. */
ty_pin_init(LED_PIN, TY_PIN_MODE_OUT_PP_LOW);
/* Create a recurring sg_led_flash_timer that expires after 300 ms. Register the timeout handler __led_flash_timer_cb. */
tuya_ble_timer_create(&sg_led_flash_timer, LED_TIMER_VAL_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__led_flash_timer_cb);
/* Get and print Bluetooth connection status */
tuya_ble_connect_status_t ble_conn_sta = tuya_ble_connect_status_get();
TUYA_APP_LOG_DEBUG("BLE connect status: %d.", ble_conn_sta);
/* Control the LED behavior according to the Bluetooth connection status. */
if ((ble_conn_sta == BONDING_UNCONN) ||
(ble_conn_sta == BONDING_CONN) ||
(ble_conn_sta == BONDING_UNAUTH_CONN)) {
/* If the Bluetooth is bound, the LED comes off. */
TUYA_APP_LOG_INFO("LED keep off."); /* Print message: LED steady off */
} else {
/* If the Bluetooth is unbound, the LED starts blinking. */
sg_led_status = 1; /* Update the flag of LED status. */
ty_pin_set(LED_PIN, TY_PIN_HIGH); /* The LED pin outputs high. */
tuya_ble_timer_start(sg_led_flash_timer); /* Start sg_led_flash_timer. */
TUYA_APP_LOG_INFO("LED start falshing."); /* Print message: LED starts blinking */
}
}
ty_pin_init
The GPIO driver for TLSR825x platform, located in ty_pin_tlsr825x.c
.
You can port the code in this demo to your project or directly call the API from the chip vendor to drive pins.
/**
* @brief Initialize pins
* @param[in] pin: The pin number, which can be modified according to the chip platform.
* @param[in] mode: The pin mode.
* @return none
*/
uint32_t ty_pin_init(uint16_t pin, ty_pin_mode_t mode)
{
/* Set the pin function. */
gpio_set_func(pin, AS_GPIO);
/* Set the pin output direction. */
if ((mode & TY_PIN_INOUT_MASK) <= TY_PIN_IN_IRQ) {
gpio_set_input_en(pin, 1);
gpio_set_output_en(pin, 0);
} else {
gpio_set_input_en(pin, 0);
gpio_set_output_en(pin, 1);
}
/* Set the pin mode and initial level. */
switch (mode) {
case TY_PIN_MODE_IN_PU:
gpio_setup_up_down_resistor(pin, PM_PIN_PULLUP_10K);
break;
case TY_PIN_MODE_IN_PD:
gpio_setup_up_down_resistor(pin, PM_PIN_PULLDOWN_100K);
break;
case TY_PIN_MODE_IN_FL:
gpio_setup_up_down_resistor(pin, PM_PIN_UP_DOWN_FLOAT);
break;
case TY_PIN_MODE_OUT_PP_LOW:
gpio_write(pin, 0);
break;
case TY_PIN_MODE_OUT_PP_HIGH:
gpio_write(pin, 1);
break;
default:
break;
}
/* Set the wake-up pin. */
#if (GPIO_WAKEUP_MODULE_POLARITY == 1)
cpu_set_gpio_wakeup (WAKEUP_MODULE_GPIO, Level_High, 1);
GPIO_WAKEUP_MODULE_LOW;
#else
cpu_set_gpio_wakeup (WAKEUP_MODULE_GPIO, Level_Low, 1);
GPIO_WAKEUP_MODULE_HIGH;
#endif
return 0;
}
ty_sht3x_init
Located in ty_sht3x.c
/* The address of the I2C device. */
#define SHT3X_DEV_ADDR_A 0x44 /* The ADDR pin (pin2) is connected to logic low. */
#define SHT3X_DEV_ADDR_B 0x45 /* The ADDR pin (pin2) is connected to logic high. */
/* The address of the I2C device. The ADDR pin is connected to ground by default. */
uint8_t g_dev_addr = SHT3X_DEV_ADDR_A;
/**
* @brief Initialize the SHT3x driver.
* @param[in] addr_pin_high: Specify whether the ADDR pin is connected high.
* @return None
*/
void ty_sht3x_init(bool addr_pin_high)
{
/* Initialize I2C */
ty_i2c_init();
/* Set the address of the peripheral device. */
if (addr_pin_high) {
g_dev_addr = SHT3X_DEV_ADDR_B;
}
}
ty_i2c_init
The I2C driver for TLSR825x platform, located in ty_i2c_tlsr825x.c
.
To use the I2C driver, change the value of USE_SOFT_I2C
in ty_i2c.h
to 1
.
/* I2C pin definition. You can modify the pin number according to your hardware design. */
#define I2C_PIN_SDA GPIO_PC0
#define I2C_PIN_SCL GPIO_PC1
/**
* @brief Initialize the I2C pin.
* @param None
* @return None
*/
void i2c_soft_gpio_init(void)
{
gpio_set_func(I2C_PIN_SDA, AS_GPIO);
gpio_set_func(I2C_PIN_SCL, AS_GPIO);
gpio_set_output_en(I2C_PIN_SDA, 1);
gpio_set_input_en(I2C_PIN_SDA, 0);
gpio_set_output_en(I2C_PIN_SCL, 1);
gpio_set_input_en(I2C_PIN_SCL, 0);
}
/**
* @brief Initialize I2C.
* @param None
* @return The operation result
*/
uint32_t ty_i2c_init(void)
{
#if (USE_SOFT_I2C == 0)
/* ... */
#else
/* Initialize the I2C pin. */
i2c_soft_gpio_init();
#endif
return 0;
}
__led_flash_timer_cb
Located in tuya_ble_sensor_rht_demo.c
/**
* @brief The timeout handler for LED on/off control.
* @param None
* @return None
*/
static void __led_flash_timer_cb(void)
{
/* LED on/off control */
sg_led_status = !sg_led_status;
/* Control the pin output level according to LED status */
if (sg_led_status) {
ty_pin_set(LED_PIN, TY_PIN_HIGH);
} else {
ty_pin_set(LED_PIN, TY_PIN_LOW);
}
}
__rht_daq_timer_handler
Located in tuya_ble_sensor_rht_demo.c
/* Alert code */
#define ALARM_LOWER 0 /* Trigger an alert when the lower limit is reached. */
#define ALARM_UPPER 1 /* Trigger an alert when the upper limit is reached. */
#define ALARM_CANCEL 2 /* Alert is canceled. */
/* The data type of the threshold value */
typedef struct {
int32_t temp_max; /* The upper limit of temperature */
int32_t temp_min; /* The lower limit of temperature */
int32_t humi_max; /* The upper limit of humidity */
int32_t humi_min; /* The lower limit of humidity */
} ALARM_THR_T;
/* Alert threshold */
static ALARM_THR_T sg_alarm_thr = {
.temp_max = 400, /* The upper limit of temperature. Initial value: 40°C */
.temp_min = 0, /* The lower limit of temperature. Initial value: 0°C */
.humi_max = 700, /* The upper limit of humidity. Initial value: 70% */
.humi_min = 300 /* The lower limit of humidity. Initial value: 30% */
};
/**
* @brief Check if the temperature exceeds the alert threshold.
* @param[in] cur_temp: The current temperature.
* @return Alert code.
*/
static uint8_t __check_temp_val(int32_t cur_temp)
{
uint8_t res;
if (cur_temp < sg_alarm_thr.temp_min) {
res = ALARM_LOWER;
} else if (cur_temp > sg_alarm_thr.temp_max) {
res = ALARM_UPPER;
} else {
res = ALARM_CANCEL;
}
return res;
}
/**
* @brief Check if the humidity exceeds the alert threshold.
* @param[in] cur_humi: The current humidity.
* @return Alert code.
*/
static uint8_t __check_humi_val(int32_t cur_humi)
{
uint8_t res;
if (cur_humi < sg_alarm_thr.humi_min) {
res = ALARM_LOWER;
} else if (cur_humi > sg_alarm_thr.humi_max) {
res = ALARM_UPPER;
} else {
res = ALARM_CANCEL;
}
return res;
}
/**
* @brief The timeout handler for temperature and humidity collection.
* @param None
* @return None
*/
static void __rht_daq_timer_handler(void)
{
int32_t temp, humi;
/* Read the temperature and humidity and save the reading to temp and humi, with data multiplied by 10 times. */
if (ty_sht3x_read_data(&temp, &humi, TEMP_SCALE, HUMI_SCALE)) {
/* Print when data is read. */
TUYA_APP_LOG_DEBUG("Temperature: %d, Humidity: %d", temp, humi);
/* Archive data to sg_rht_data */
sg_rht_data.temp = temp;
sg_rht_data.humi = humi;
/* Check if data exceeds the alert threshold. */
sg_rht_data.temp_alarm = __check_temp_val(temp);
sg_rht_data.humi_alarm = __check_humi_val(humi);
/* If Bluetooth is connected, the device reports data. */
if (BONDING_CONN == tuya_ble_connect_status_get()) {
__repo_dp_data_all();
}
} else {
/* Print error message: Failed to execute ty_sht3x_read_data. */
TUYA_APP_LOG_ERROR("ty_sht3x_read_data failed.");
}
}
__repo_dp_data_all
Located in tuya_ble_sensor_rht_demo.c
/* DP ID (The ID of a DP defined on the Tuya Developer Platform) */
#define DP_ID_TEMP_CURRENT 1
#define DP_ID_HUMIDITY_VALUE 2
#define DP_ID_TEMP_ALARM 14
#define DP_ID_HUM_ALARM 15
/**
* @brief Report all DP data that is updated.
* @param None
* @return None
*/
static void __repo_dp_data_all(void)
{
/* Before definition, return the datastore variables. */
static RHT_DP_DATA_T s_prv_val = {
.temp = 0,
.humi = 0,
.temp_alarm = ALARM_CANCEL,
.humi_alarm = ALARM_CANCEL
};
/* Report temperature data. */
if (sg_rht_data.temp != s_prv_val.temp) {
__report_one_dp_data(DP_ID_TEMP_CURRENT, DT_VALUE, 4, (uint8_t *)&sg_rht_data.temp);
s_prv_val.temp = sg_rht_data.temp;
}
/* Report humidity data. */
if (sg_rht_data.humi != s_prv_val.humi) {
__report_one_dp_data(DP_ID_HUMIDITY_VALUE, DT_VALUE, 4, (uint8_t *)&sg_rht_data.humi);
s_prv_val.humi = sg_rht_data.humi;
}
/* Report temperature alerts. */
if (sg_rht_data.temp_alarm != s_prv_val.temp_alarm) {
__report_one_dp_data(DP_ID_TEMP_ALARM, DT_ENUM, 1, (uint8_t *)&sg_rht_data.temp_alarm);
s_prv_val.temp_alarm = sg_rht_data.temp_alarm;
}
/* Report humidity alerts. */
if (sg_rht_data.humi_alarm != s_prv_val.humi_alarm) {
__report_one_dp_data(DP_ID_HUM_ALARM, DT_ENUM, 1, (uint8_t *)&sg_rht_data.humi_alarm);
s_prv_val.humi_alarm = sg_rht_data.humi_alarm;
}
}
__report_one_dp_data
Located in tuya_ble_sensor_rht_demo.c
/* The field offset of DP model */
#define DP_DATA_INDEX_OFFSET_ID 0 /* dp_id */
#define DP_DATA_INDEX_OFFSET_TYPE 1 /* dp_type */
#define DP_DATA_INDEX_OFFSET_LEN_H 2 /* dp_len high byte */
#define DP_DATA_INDEX_OFFSET_LEN_L 3 /* dp_len low byte */
#define DP_DATA_INDEX_OFFSET_DATA 4 /* dp_data */
/* Report the size of the array. */
#define REPO_ARRAY_SIZE 8
/* Report the datastore array. */
static uint8_t sg_repo_array[REPO_ARRAY_SIZE];
/* The sequence number of data transmission. Initial value: 0 */
static uint32_t sg_sn = 0;
/**
* @brief Report data of a DP.
* @param[in] dp_id: DP ID
* @param[in] dp_type: DP data type.
* @param[in] dp_len: DP data length.
* @param[in] dp_data: DP data.
* @return None
*/
static void __report_one_dp_data(const uint8_t dp_id, const uint8_t dp_type, const uint16_t dp_len, const uint8_t *dp_data)
{
uint16_t i;
/* Save DP data to an array. */
sg_repo_array[DP_DATA_INDEX_OFFSET_ID] = dp_id;
sg_repo_array[DP_DATA_INDEX_OFFSET_TYPE] = dp_type;
sg_repo_array[DP_DATA_INDEX_OFFSET_LEN_H] = (uint8_t)(dp_len >> 8);
sg_repo_array[DP_DATA_INDEX_OFFSET_LEN_L] = (uint8_t)dp_len;
for (i = 0; i < dp_len; i++) {
sg_repo_array[DP_DATA_INDEX_OFFSET_DATA + i] = *(dp_data + (dp_len-i-1));
}
/* Call an API to send DP data. */
tuya_ble_dp_data_send(sg_sn++, DP_SEND_TYPE_ACTIVE, DP_SEND_FOR_CLOUD_PANEL, DP_SEND_WITHOUT_RESPONSE, sg_repo_array, dp_len + DP_DATA_INDEX_OFFSET_DATA);
}
tuya_ble_sdk_callback
Located in tuya_ble_sdk_demo.c
This demo uses the following events.
/**
* @brief tuya_ble_sdk callback
* @param[in] event: Event (Message)
* @return None
*/
static void tuya_ble_sdk_callback(tuya_ble_cb_evt_param_t* event)
{
switch (event->evt) {
/* Bluetooth connection status changes */
case TUYA_BLE_CB_EVT_CONNECTE_STATUS: {
/* When Bluetooth connection status changes to bound and connected */
if (event->connect_status == BONDING_CONN) {
TUYA_APP_LOG_INFO("bonding and connecting");
tuya_ble_update_conn_param_timer_start();
/* Bluetooth connection processing */
tuya_net_proc_ble_conn();
}
} break;
/* Receive DP data from the mobile app. */
case TUYA_BLE_CB_EVT_DP_DATA_RECEIVED: {
/* Pass in the DP data and the total length of the DP data. */
tuya_net_proc_dp_recv(event->dp_received_data.p_data, event->dp_received_data.data_len);
} break;
/* Receive an unbinding command from the mobile app. */
case TUYA_BLE_CB_EVT_UNBOUND: {
/* Unbind Bluetooth connection. */
tuya_net_proc_ble_unbound();
TUYA_APP_LOG_INFO("TUYA_BLE_CB_EVT_UNBOUND");
} break;
/* Receive an offline unbinding command from the mobile app. */
case TUYA_BLE_CB_EVT_ANOMALY_UNBOUND: {
/* Unbind Bluetooth connection. */
tuya_net_proc_ble_unbound();
TUYA_APP_LOG_INFO("TUYA_BLE_CB_EVT_ANOMALY_UNBOUND");
} break;
/* Default */
default: {
TUYA_APP_LOG_INFO("tuya_ble_sdk_callback unknown event type 0x%04x", event->evt);
} break;
}
}
tuya_net_proc_ble_conn
Located in tuya_ble_sensor_rht_demo.c
/**
* @brief Bluetooth connection handler.
* @param None
* @return None
*/
void tuya_net_proc_ble_conn(void)
{
sg_led_status = 0; /* Update the flag of LED status. */
ty_pin_set(LED_PIN, TY_PIN_LOW); /* The LED pin outputs low. */
tuya_ble_timer_stop(sg_led_flash_timer);/* Stop sg_led_flash_timer */
TUYA_APP_LOG_INFO("LED stop falshing.");/* Print message: LED stops blinking */
}
tuya_net_proc_dp_recv
Located in tuya_ble_sensor_rht_demo.c
/* DP ID (The ID of a DP defined on the Tuya Developer Platform) */
#define DP_ID_MAXTEMP_SET 10
#define DP_ID_MINITEMP_SET 11
#define DP_ID_MAXHUM_SET 12
#define DP_ID_MINIHUM_SET 13
/**
* @brief DP data reception handler
* @param[in] dp_data: DP data
* @param[in] dp_len: The total length of DP data.
* @return None
*/
void tuya_net_proc_dp_recv(uint8_t *dp_data, uint16_t dp_len)
{
int32_t val = 0;
/* Check if the length of DP data is 4. */
if (dp_len - 4 == 4) {
/* Concatenate data and print debugging message. */
val = dp_data[4] << 24 | dp_data[5] << 16 | dp_data[6] << 8 | dp_data[7];
TUYA_APP_LOG_DEBUG("val: %x", val);
}
/* Process data by DP_ID. */
switch (dp_data[0]) {
/* The upper limit of temperature: Store and report data and print notification. */
case DP_ID_MAXTEMP_SET:
sg_alarm_thr.temp_max = val;
__report_one_dp_data(DP_ID_MAXTEMP_SET, DT_VALUE, 4, (uint8_t *)&val);
TUYA_APP_LOG_INFO("Set the maximum temperature to %d.", sg_alarm_thr.temp_max);
break;
/* The lower limit of temperature: Store and report data and print notification. */
case DP_ID_MINITEMP_SET:
sg_alarm_thr.temp_min = val;
__report_one_dp_data(DP_ID_MINITEMP_SET, DT_VALUE, 4, (uint8_t *)&val);
TUYA_APP_LOG_INFO("Set the minimum temperature to %d.", sg_alarm_thr.temp_min);
break;
/* The upper limit of humidity: Store and report data and print notification. */
case DP_ID_MAXHUM_SET:
sg_alarm_thr.humi_max = val;
__report_one_dp_data(DP_ID_MAXHUM_SET, DT_VALUE, 4, (uint8_t *)&val);
TUYA_APP_LOG_INFO("Set the maximum humidity to %d.", sg_alarm_thr.humi_max);
break;
/* The lower limit of humidity: Store and report data and print notification. */
case DP_ID_MINIHUM_SET:
sg_alarm_thr.humi_min = val;
__report_one_dp_data(DP_ID_MINIHUM_SET, DT_VALUE, 4, (uint8_t *)&val);
TUYA_APP_LOG_INFO("Set the minimum humidity to %d.", sg_alarm_thr.humi_min);
break;
/* Default */
default:
break;
}
}
tuya_net_proc_ble_unbound
Located in tuya_ble_sensor_rht_demo.c
/**
* @brief Bluetooth unbinding handler
* @param None
* @return None
*/
void tuya_net_proc_ble_unbound(void)
{
sg_led_status = 1; /* Update the flag of LED status. */
ty_pin_set(LED_PIN, TY_PIN_HIGH); /* The LED pin outputs high. */
tuya_ble_timer_start(sg_led_flash_timer); /* Start sg_led_flash_timer */
TUYA_APP_LOG_INFO("LED start falshing."); /* Print message: LED starts blinking */
}
ty_sht3x_measure_single_shot
Located in ty_sht3x.c
#define SHT3X_CMD_MEAS_CLOCKSTR_H 0x2C06 /* One-time measurement: Clock stretching and high repetition */
/**
* @brief Measure data once.
* @param[out] temp: Temperature value.
* @param[out] humi: Humidity value.
* @param[in] temp_scale: Temperature scale.
* @param[in] humi_scale: Humidity scale.
* @return The operation result
*/
uint8_t ty_sht3x_measure_single_shot(int32_t *temp, int32_t *humi, uint8_t temp_scale, uint8_t humi_scale)
{
/* The write command: One-time measurement with the stop signal */
__sht3x_write_cmd(SHT3X_CMD_MEAS_CLOCKSTR_H, 1);
/* Delay of 20 ms */
i2c_delay(20000);
/* Read data and return operation result. */
return __sht3x_read_data(temp, humi, temp_scale, humi_scale);
}
ty_sht3x_start_periodic_measure
Located in ty_sht3x.c
#define SHT3X_CMD_MEAS_PERI_05_H 0x2032 /* Measure data 0.5 times (0.5 Hz) every second, with high repetition. */
#define SHT3X_CMD_MEAS_PERI_05_M 0x2024 /* Measure data 0.5 times (0.5 Hz) every second, with medium repetition. */
#define SHT3X_CMD_MEAS_PERI_05_L 0x202F /* Measure data 0.5 times (0.5 Hz) every second, with low repetition. */
#define SHT3X_CMD_MEAS_PERI_1_H 0x2130 /* Measure data once (1 Hz) every second, with high repetition. */
#define SHT3X_CMD_MEAS_PERI_1_M 0x2126 /* Measure data once (1 Hz) every second, with medium repetition. */
#define SHT3X_CMD_MEAS_PERI_1_L 0x212D /* Measure data once (1 Hz) every second, with low repetition. */
#define SHT3X_CMD_MEAS_PERI_2_H 0x2236 /* Measure data twice (2 Hz) every second, with high repetition. */
#define SHT3X_CMD_MEAS_PERI_2_M 0x2220 /* Measure data twice (2 Hz) every second, with medium repetition. */
#define SHT3X_CMD_MEAS_PERI_2_L 0x222B /* Measure data twice (2 Hz) every second, with low repetition. */
#define SHT3X_CMD_MEAS_PERI_4_H 0x2334 /* Measure data 4 times (4 Hz) every second, with high repetition. */
#define SHT3X_CMD_MEAS_PERI_4_M 0x2322 /* Measure data 4 times (4 Hz) every second, with medium repetition. */
#define SHT3X_CMD_MEAS_PERI_4_L 0x2329 /* Measure data 4 times (4 Hz) every second, with low repetition. */
#define SHT3X_CMD_MEAS_PERI_10_H 0x2737 /* Measure data 10 times (10 Hz) every second, with high repetition. */
#define SHT3X_CMD_MEAS_PERI_10_M 0x2721 /* Measure data 10 times (10 Hz) every second, with medium repetition. */
#define SHT3X_CMD_MEAS_PERI_10_L 0x272A /* Measure data 10 times (10 Hz) every second, with low repetition. */
/**
* @brief Start scheduled measurement.
* @param[in] rept: Repetition
* @param[in] freq: Sampling frequency
* @return None
*/
void ty_sht3x_start_periodic_measure(SHT3X_REPT_E rept, SHT3X_FREQ_E freq)
{
switch (rept) {
/* High repetition */
case REPEATAB_HIGH:
switch (freq) {
case FREQ_HZ5: /* 0.5Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_05_H, 0);
break;
case FREQ_1HZ: /* 1Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_1_H, 0);
break;
case FREQ_2HZ: /* 2Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_2_H, 0);
break;
case FREQ_4HZ: /* 4Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_4_H, 0);
break;
case FREQ_10HZ: /* 10Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_10_H, 0);
break;
default:
break;
}
break;
/* Medium repetition */
case REPEATAB_MEDIUM:
switch (freq) {
case FREQ_HZ5: /* 0.5Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_05_M, 0);
break;
case FREQ_1HZ: /* 1Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_1_M, 0);
break;
case FREQ_2HZ: /* 2Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_2_M, 0);
break;
case FREQ_4HZ: /* 4Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_4_M, 0);
break;
case FREQ_10HZ: /* 10Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_10_M, 0);
break;
default:
break;
}
break;
/* Low repetition */
case REPEATAB_LOW:
switch (freq) {
case FREQ_HZ5: /* 0.5Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_05_L, 0);
break;
case FREQ_1HZ: /* 1Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_1_L, 0);
break;
case FREQ_2HZ: /* 2Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_2_L, 0);
break;
case FREQ_4HZ: /* 4Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_4_L, 0);
break;
case FREQ_10HZ: /* 10Hz */
__sht3x_write_cmd(SHT3X_CMD_MEAS_PERI_10_L, 0);
break;
default:
break;
}
break;
default:
break;
}
}
ty_sht3x_read_data
Located in ty_sht3x.c
#define SHT3X_CMD_FETCH_DATA 0xE000 /* Read data (scheduled measurement) */
/**
* @brief Read data from SHT3x
* @param[out] temp: Temperature value.
* @param[out] humi: Humidity value.
* @param[in] temp_scale: Temperature scale.
* @param[in] humi_scale: Humidity scale.
* @return The operation result
*/
uint8_t ty_sht3x_read_data(int32_t *temp, int32_t *humi, uint8_t temp_scale, uint8_t humi_scale)
{
/* The write command: Read data without the stop signal */
__sht3x_write_cmd(SHT3X_CMD_FETCH_DATA, 0);
/* Read data and return operation result. */
return __sht3x_read_data(temp, humi, temp_scale, humi_scale);
}
__sht3x_write_cmd
Located in ty_sht3x.c
/* The write command bit of I2C*/
#define I2C_CMD_BIT_WRITE 0
/**
* @brief Write command to SHT3x
* @param[in] cmd: The command
* @param[in] stop: Whether to send the stop signal.
* @return None
*/
static void __sht3x_write_cmd(uint16_t cmd, bool stop)
{
/* Split command */
uint8_t cmd_bytes[2];
cmd_bytes[0] = (uint8_t)(cmd >> 8);
cmd_bytes[1] = (uint8_t)(cmd & 0x00FF);
/* I2C transmission */
i2c_start();
i2c_send_bytes((g_dev_addr << 1) | I2C_CMD_BIT_WRITE, cmd_bytes, 2);
if (stop) {
i2c_stop();
}
}
__sht3x_read_data
Located in ty_sht3x.c
/* The read command bit of I2C */
#define I2C_CMD_BIT_READ 1
/**
* @brief Read multiple bytes.
* @param[out] buffer: Buffer
* @param[in] len: Data length
* @return None
*/
static void __sht3x_read_bytes(uint8_t *buffer, uint8_t len)
{
i2c_start();
i2c_rcv_bytes((g_dev_addr << 1) | I2C_CMD_BIT_READ, buffer, len);
i2c_stop();
}
/**
* @brief Calculate the temperature.
* @param[in] raw_data: Raw data.
* @param[in] scale: The scale.
* @return Temperature value in °C.
*/
static int32_t __sht3x_calc_temp(int16_t raw_data, uint8_t scale)
{
int32_t gain = 1;
while(scale--) {
gain *= 10;
}
return (gain * 175 * (int32_t)raw_data / 65535 - gain * 45);
}
/**
* @brief Calculate the humidity.
* @param[in] raw_data: Raw data.
* @param[in] scale: The scale.
* @return Humidity value in %RH.
*/
static int32_t __sht3x_calc_humi(uint16_t raw_data, uint8_t scale)
{
int32_t gain = 1;
while(scale--) {
gain *= 10;
}
return (gain * 100 * (int32_t)raw_data / 65535);
}
/**
* @brief Read data
* @param[out] temp: Temperature value.
* @param[out] humi: Humidity value.
* @param[in] temp_scale: Temperature scale.
* @param[in] humi_scale: Humidity scale.
* @return The operation result
*/
uint8_t __sht3x_read_data(int32_t *temp, int32_t *humi, uint8_t temp_scale, uint8_t humi_scale)
{
uint8_t buf[6];
/* Read 6-byte data: temperature (2 bytes), humidity (2 bytes), and checksum (2 bytes) */
__sht3x_read_bytes(buf, 6);
/* CRC8 checksum */
if ((!__sht3x_check_crc(buf, 2, buf[2])) ||
(!__sht3x_check_crc(buf+3, 2, buf[5]))) {
return 0; /* Check failed, with 0 returned. */
}
/* The data calculated based on the scale. */
*temp = __sht3x_calc_temp(((int16_t)buf[0] << 8) | buf[1], temp_scale);
*humi = __sht3x_calc_humi(((int16_t)buf[3] << 8) | buf[4], humi_scale);
return 1; /* Check succeeded, with 1 returned. */
}
Flash firmware to your board and reset it. If the indicator is blinking, the device is ready for binding.
Pair the device by using the Smart Life app. The indicator comes off on successful binding.
If the device has been bound, the indicator does not blink. When you open the app, the device will automatically connect to it. You can unbind the device as instructed below. Then, the indicator will blink.
The app updates the temperature and humidity data in real time.
Set upper and lower limits on temperature and humidity by using the app.
If one of the metrics goes above or below that limit, the sensor will send a notification to the mobile app.
Is this page helpful?
YesFeedbackIs this page helpful?
YesFeedback