更新时间:2026-01-29 07:21:57下载pdf
本文介绍蓝牙设备支持的时间服务。
蓝牙设备支持本地时间服务,设备上电后时间从 0 开始,时间精度为 1 s,误差取决于不同芯片内部低频晶振的精度或者外部低频晶振的精度。
当设备和 涂鸦 App 每次连接成功时(包括配网、重连),默认设备会向 App 请求时间同步。根据设备请求时间类型的不同,App 返回不同类型的时间(支持云端实时时间、App 本地时间等),之后设备会按照获取到的时间标准执行本地时间服务。
如下图所示,时间服务主要包含 RTC 计时、UTC 时间转换和时间同步三个模块。
其中,RTC 计时主要由 tal_rtc.c 实现,包含芯片平台相关的 RTC 计时服务。UTC 时间转换模块由 tal_utc 组件实现,包含时间戳和通用时间格式转换等内容。时间同步模块的主要功能是从云端/App 同步实时时间。
typedef struct {
UINT8_T timestamp_string[14];
INT16_T time_zone; // Multiply actual time zone by 100.
} tuya_ble_timestamp_data_t;
timestamp_string:13 字节字符串,Unix ms 级时间。
time_zone:有符号型,实际时区的 100 倍,例如北京东八区为 8 × 100 = 800,西 7.5 区为 -750。
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; // Multiply actual time zone by 100.
} tuya_ble_time_noraml_data_t;
nYear:年。nMonth:月。nDay:日。nHour:时。nMin:分。nSec:秒。DayIndex:星期,其中周日 = 0,周一至周六依次为 1 - 6。time_zone:有符号型,实际时区的 100 倍,例如北京东八区为 8 × 100 = 800,西 7.5 区为 -750。typedef struct {
UINT32_T timestamp;
INT16_T time_zone; /**< Multiply actual time zone by 100. */
UINT8_T n_years_dst; /**< how many years of daylight saving time. */
UINT8_T *p_data; /**< the point of dst data. */
UINT16_T data_len; /**< dst data length. */
} tuya_ble_timestamp_with_dst_data_t;
timestamp:Unix 时间戳。time_zone:有符号型,实际时区的 100 倍,例如北京东八区为 8 × 100 = 800,西 7.5 区为 -750。n_years_dst:表示后面有几年的夏令时数据,0 表示没有夏令时数据,1 表示后面只有 1 年的夏令时数据。p_data:夏令时数据。data_len:夏令时数据长度。| 序号 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 1~10 | 10 | start_1 | 第 1 年的夏令时起始时间,10 字节 Unix 时间戳字符串。 |
| 11~20 | 10 | end_1 | 第 1 年的夏令时结束时间,10 字节 Unix 时间戳字符串(必须大于当前时间 timestamp)。 |
| …… | …… | …… | …… |
| ~ | 10 | start_n | 第 n 年的夏令时起始时间,10 字节 Unix 时间戳字符串。 |
| ~ | 10 | end_n | 第 n 年的夏令时结束时间,10 字节 Unix 时间戳字符串。 |
typedef struct {
UINT16_T year;
UINT8_T month;
UINT8_T day;
UINT8_T hour;
UINT8_T min;
UINT8_T sec;
UINT8_T dayIndex; // 0 = Sunday
} tal_utc_date_t;
year:年。month:月。day:日。hour:时。min:分。sec:秒。dayIndex:星期,其中周日 = 0,周一至周六依次为 1 - 6。RTC 上电后从 0 开始计时,RTC 的精度根据不同的芯片或者时钟源的选取会有不同。
接口说明
OPERATE_RET tal_rtc_init(VOID_T);
接口说明
OPERATE_RET tal_rtc_time_set(TIME_T time_sec);
参数说明
| 参数 | 说明 |
|---|---|
| time_sec | 4 字节 Unix 时间戳 |
接口说明
OPERATE_RET tal_rtc_time_get(TIME_T *time_sec);
参数说明
| 参数 | 说明 |
|---|---|
| time_sec | 4 字节 Unix 时间戳的指针 |
接口说明
OPERATE_RET tal_utc_set_time_zone(INT16_T time_zone);
参数说明
| 参数 | 说明 |
|---|---|
| time_zone | 有符号型,实际时区的 100 倍,例如北京东八区为 8 × 100 = 800,西 7.5 区为 -750。 |
接口说明
INT16_T tal_utc_get_time_zone(VOID_T);
参数说明
| 参数 | 说明 |
|---|---|
| 返回值 | 有符号型,实际时区的 100 倍,例如北京东八区为 8 × 100 = 800,西 7.5 区为 -750。 |
将标准的 Unix 时间戳转换成易于理解的日期时间结构类型。
接口说明
OPERATE_RET tal_utc_timestamp2date(UINT32_T timestamp, tal_utc_date_t* date, BOOL_T daylightSaving)
参数说明
| 参数 | 说明 |
|---|---|
| timestamp | 4 字节 Unix 时间戳(从 1970-01-01 00:00:00 开始的秒数) |
| date | 指向转换后日期时间信息的结构体指针,结构体定义见 tal_utc_date_t |
| daylightSaving | 夏令时标志位:
|
将日期时间结构体转换为标准的 Unix 时间戳。
接口说明
UINT32_T tal_utc_date2timestamp(tal_utc_date_t *date, BOOL_T daylightSaving);
参数说明
| 参数 | 说明 |
|---|---|
| date | 指向待转换的日期时间结构体指针,结构体定义见 tal_utc_date_t |
| daylightSaving | 夏令时标志位:
|
| 返回值 | 4 字节 Unix 时间戳(从 1970-01-01 00:00:00 开始的秒数) |
设备与 App 建立连接后,SDK 会自动请求一次时间同步(默认行为)。您可以根据需要,修改宏定义 TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE 来配置请求的时间类型。
| 配置值 | 请求类型与数据格式 |
|---|---|
| 1(SDK 默认值) | 请求云端实时时间
|
| 2 | 请求 App 本地实时时间
|
| 3 | 请求云端实时时间(含夏令时)
|
当设备需要额外获取时间时(例如在定时器中定期同步),开发者可以主动调用本接口。请注意,此操作仅在设备与 App 处于连接状态时有效。
接口说明
tuya_ble_status_t tuya_ble_time_req(UINT8_T time_type);
参数说明
| 参数值 | 说明 |
|---|---|
| 0x00 | 请求云端实时时间
|
| 0x01 | 请求云端实时时间(年月日时分秒格式)
|
| 0x02 | 请求 App 本地实时时间
|
设备每次上电后,tal_rtc_init 接口会初始化设备本地时间,从 0 开始计时。此时设备时间和网络时间不同步,使用 tal_rtc_time_get 和 tal_utc_get_time_zone 查询到的时间为从上电开始的秒数。
每次连接(配网/重连)设备均会请求一次时间同步,可通过 TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE 配置请求的时间类型。不同类型时间的说明请参考上文中对该宏的介绍。
此后还可以通过调用接口 tuya_ble_time_req 请求时间同步。如果需要定时获取实时时间,可以在定时器中调用该函数。注意只有在连接的状态下才能成功获取实时时间,否则会报状态错误。
当同步的时间下发给设备后,设备会依次调用 tal_rtc_time_set 和 tal_utc_set_time_zone 更新本地的时间戳和时区。此时设备时间和网络时间同步,使用 tal_rtc_time_get 和 tal_utc_get_time_zone 查询到的时间为实际的网络时间。
在 app_config.h 中配置每次连接请求的时间类型(SDK 默认配置 = 1,如需更改类型请重定义配置)。
/*
* Whether to automatically perform a time request after the connection is established.
* 1: Request cloud time.
* 2: Request phone local time.
* 3: Request cloud time with Dst.
*/
#define TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE 1
在 tuya_ble_protocol_callback.c 里的 回调事件处理函数 下添加如下代码,即可实现基本功能。
STATIC VOID_T tuya_ble_protocol_callback(tuya_ble_cb_evt_param_t* event)
{
switch (event->evt) {
...
#if (TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE == 1)
case TUYA_BLE_CB_EVT_TIME_STAMP: {
UINT32_T timestamp_s = 0;
UINT32_T timestamp_ms = 0;
tal_util_str_intstr2int((VOID_T*)event->timestamp_data.timestamp_string, 10, ×tamp_s);
tal_util_str_intstr2int((VOID_T*)(event->timestamp_data.timestamp_string+10), 3, ×tamp_ms);
// It should be noted that the SDK already handles called tuya_ble_rtc_set_timestamp api to setting the RTC time and time zone.
// tal_rtc_time_set(timestamp_s);
// tal_utc_set_time_zone(event->timestamp_data.time_zone);
TAL_PR_INFO("TUYA_BLE_CB_EVT_TIME_STAMP - time_zone: %d", event->timestamp_data.time_zone);
TAL_PR_INFO("TUYA_BLE_CB_EVT_TIME_STAMP - timestamp: %d", timestamp_s);
} break;
#endif
case TUYA_BLE_CB_EVT_TIME_NORMAL: {
// It should be noted that the SDK already handles called tuya_ble_rtc_set_timestamp api to setting the RTC time and time zone.
TAL_PR_INFO("TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL, [%d-%d-%d %d:%d:%d w=%d] time_zone:%d", \
event->time_normal_data.nYear, event->time_normal_data.nMonth, event->time_normal_data.nDay,
event->time_normal_data.nHour, event->time_normal_data.nMin, event->time_normal_data.nSec,
event->time_normal_data.DayIndex, event->time_normal_data.time_zone);
} break;
#if (TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE == 2)
case TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL: {
// It should be noted that the SDK already handles called tuya_ble_rtc_set_timestamp api to setting the RTC time and time zone.
TAL_PR_INFO("TUYA_BLE_CB_EVT_APP_LOCAL_TIME_NORMAL, [%d-%d-%d %d:%d:%d w=%d] time_zone:%d", \
event->time_normal_data.nYear, event->time_normal_data.nMonth, event->time_normal_data.nDay,
event->time_normal_data.nHour, event->time_normal_data.nMin, event->time_normal_data.nSec,
event->time_normal_data.DayIndex, event->time_normal_data.time_zone);
} break;
#endif
#if (TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE == 3)
case TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST: {
// It should be noted that the SDK already handles called tuya_ble_rtc_set_timestamp api to setting the RTC time and time zone.
// tal_rtc_time_set(event->timestamp_with_dst_data.timestamp);
// tal_utc_set_time_zone(event->timestamp_with_dst_data.time_zone);
TAL_PR_INFO("TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST - time_zone: %d", event->timestamp_with_dst_data.time_zone);
TAL_PR_INFO("TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST - timestamp: %d", event->timestamp_with_dst_data.timestamp);
TAL_PR_INFO("TUYA_BLE_CB_EVT_TIME_STAMP_WITH_DST - n_years_dst: %d", event->timestamp_with_dst_data.n_years_dst);
for (UINT32_T idx=0 ; idx<event->timestamp_with_dst_data.n_years_dst; idx++) {
UINT32_T timestamp_1 = 0;
UINT32_T timestamp_2 = 0;
tal_util_str_intstr2int(event->timestamp_with_dst_data.p_data + idx*20, 10, ×tamp_1);
tal_util_str_intstr2int(event->timestamp_with_dst_data.p_data + idx*20 + 10, 10, ×tamp_2);
TAL_PR_INFO("DST Year %d, From %d to %d", idx, timestamp_1, timestamp_2);
}
} break;
#endif
...
}
}
TEST_CID_GET_TIME
TEST_CID_REQ_TIME
TEST_CID_SET_RTC_TIME
TEST_CID_GET_RTC_TIME
通过上位机(模拟实际产品)和手机 App 进行数据交互。
查询设备本地时间。调用 tal_rtc_time_get 和 tal_utc_get_time_zone 获取设备本地时间戳和时区,上电后从 0 开始。
配网成功后,默认请求实时时间。通过宏 TUYA_BLE_AUTO_REQUEST_TIME_CONFIGURE 控制请求的时间类型。
手动请求实时时间。实际是调用接口 tuya_ble_time_req 请求时间同步。
查询设备本地时间。调用 tal_rtc_time_get 和 tal_utc_get_time_zone 获取设备本地时间戳和时区,配网成功后同步网络时间。
上位机使用的相关问题,请访问 Logic 上位机使用指南。
在开发过程遇到问题,您可以登录 TuyaOS 开发者论坛 TuyaOS-蓝牙设备开发 版块进行沟通咨询。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈