智能烧水壶 (Bluetooth版)04——云端控制篇
Posted 三明治开发社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能烧水壶 (Bluetooth版)04——云端控制篇相关的知识,希望对你有一定的参考价值。
1.配网状态检测
要实现和云端进行数据交互,首先要使设备配网。根据功能简述中介绍可知,我们需要先进行以下配网检测处理:
设备状态 | 执行动作 | 绿灯提示 |
---|---|---|
上电时,检测到已被用户绑定 | 不等待配网 | 不闪烁 |
上电时,检测到未被用户绑定 | 开始等待配网 | 开始闪烁 |
长按保温键5秒时,检测到未被用户绑定 | 开始等待配网 | 开始闪烁 |
开始等待配网后3分钟内,检测到已被用户连接 | 停止等待配网 | 停止闪烁 |
开始等待配网3分钟后,检测到仍未被用户绑定 | 停止等待配网,停止蓝牙广播 | 停止闪烁 |
下面我们介绍配网状态检测与处理的实现过程。
a. 在上电初始化时,先对蓝牙连接状态进行判断和标记:
/* 蓝牙连接状态初始化 */
static void ble_connect_status_init(void)
{
tuya_ble_connect_status_t ble_conn_sta;
/* 使用TUYA BLE SDK提供的API获取当前蓝牙连接状态 */
ble_conn_sta = tuya_ble_connect_status_get();
TUYA_APP_LOG_DEBUG("ble connect status: %d", ble_conn_sta);
/* 判断与标记 */
if ((ble_conn_sta == BONDING_UNCONN) ||
(ble_conn_sta == BONDING_CONN) ||
(ble_conn_sta == BONDING_UNAUTH_CONN)) {
F_BLE_BONDING = SET; /* 标记为已绑定 */
F_WAIT_BLE_CONN = CLR; /* 标记为无需等待 */
set_led_green_mode(LED_MODE_FIX); /* 绿灯不闪烁 */
} else {
F_BLE_BONDING = CLR; /* 标记为未绑定 */
F_WAIT_BLE_CONN = SET; /* 标记为开始等待 */
set_led_green_mode(LED_MODE_TWINKLE); /* 绿灯开始闪烁 */
}
}
b. 在主循环中执行等待蓝牙连接与3分钟计时时间达到后关闭蓝牙广播的过程:
#define TIME_ALLOW_CONNECT (3*60*1000) /* 3min */
static uint32_t sg_ble_tm = 0;
FLAG_BIT g_kettle_flag;
#define F_BLE_BONDING g_kettle_flag.bit0
#define F_WAIT_BLE_CONN g_kettle_flag.bit1
/* 等待蓝牙连接 */
static void wait_ble_connect(void)
{
/* 3分钟定时 */
if (!clock_time_exceed(sg_ble_tm, TIME_ALLOW_CONNECT*1000)) {
return;
}
F_WAIT_BLE_CONN = CLR; /* 关闭等待连接标志 */
set_led_green_mode(LED_MODE_FIX); /* 绿灯停止闪烁 */
bls_ll_setAdvEnable(0); /* 关闭蓝牙广播 */
}
/* 更新蓝牙状态 */
static void update_ble_status(void)
{
if (F_BLE_BONDING == CLR) { /* 未绑定? */
if (F_WAIT_BLE_CONN == SET) { /* 等待连接标志打开? */
wait_ble_connect(); /* 等待蓝牙连接 */
}
}
}
c. 在蓝牙连接状态发生改变时做如下处理:
/* 蓝牙连接状态改变时的处理函数 */
void tuya_app_kettle_ble_connect_status_change_handler(tuya_ble_connect_status_t status)
{
if (status == BONDING_CONN) { /* 蓝牙已连接? */
report_all_dp_data(); /* 上报所有DP数据,保证APP显示与设备状态一致 */
if (F_WAIT_BLE_CONN == SET) { /* 等待连接标志打开? */
F_BLE_BONDING = SET; /* 标记为已绑定 */
F_WAIT_BLE_CONN = CLR; /* 停止配网等待 */
set_led_green_mode(LED_MODE_FIX); /* 停止闪烁 */
}
}
if (status == UNBONDING_UNCONN) { /* 设备被解绑? */
F_BLE_BONDING = CLR; /* 标记为未绑定 */
bls_ll_setAdvEnable(0); /* 停止蓝牙广播 */
}
}
/* 处理BLE SDK消息的callback函数 [tuya_ble_app_demo.c] */
static void tuya_cb_handler(tuya_ble_cb_evt_param_t* event)
{
...
case TUYA_BLE_CB_EVT_CONNECTE_STATUS: /* 在状态改变事件发生时调用 */
tuya_app_kettle_ble_connect_status_change_handler(event->connect_status);
TUYA_APP_LOG_INFO("received tuya ble conncet status update event, current connect status = %d", event->connect_status);
break;
...
}
d. 保温键长按5秒时,重新尝试等待配网的执行函数如下:
/* 尝试配网 */
static void try_to_connect_ble(void)
{
F_WAIT_BLE_CONN = SET; /* 打开等待连接标志 */
set_led_green_mode(LED_MODE_TWINKLE); /* 绿灯闪烁 */
bls_ll_setAdvEnable(1); /* 打开蓝牙广播 */
sg_ble_tm = clock_time(); /* 记录当前时间 */
}
2.本地数据上报
在设备配网后,就可以使用APP来控制设备和查看设备上报的数据,下面是数据上报的实现过程。
/* DP ID */
#define DP_ID_BOIL 101
#define DP_ID_KEEP_WARM 102
#define DP_ID_TEMP_CUR 103
#define DP_ID_TEMP_SET 104
#define DP_ID_WATER_TYPE 105
#define DP_ID_FAULT 106
/* DP TYPE */
#define DP_TYPE_BOIL DT_BOOL
#define DP_TYPE_KEEP_WARM DT_BOOL
#define DP_TYPE_TEMP_CUR DT_VALUE
#define DP_TYPE_TEMP_SET DT_VALUE
#define DP_TYPE_WATER_TYPE DT_ENUM
#define DP_TYPE_FAULT DT_ENUM
/* 用于数据上报 */
typedef struct {
uint8_t id; /* DP点ID */
dp_type type; /* DP点数据类型 */
uint8_t len; /* DP点数据长度 */
uint8_t value; /* DP点数据 */
} DP_DATA_T;
/* 用于存储烧水壶模式和DP点参数 */
typedef struct {
MODE_E mode; /* 模式 */
uint8_t boil_turn; /* 煮沸开/关 */
uint8_t temp_cur; /* 当前温度 */
uint8_t temp_set; /* 保温温度 */
uint8_t keep_warm_turn; /* 保温开/关 */
WATER_TYPE_E water_type;/* 用水类型 */
FAULT_E fault; /* 故障 */
} KETTLE_T;
KETTLE_T g_kettle;
/* 获取DP点类型 */
static uint8_t get_dp_type(uint8_t dp_id)
{
dp_type type = 0;
switch (dp_id) {
case DP_ID_BOIL:
type = DP_TYPE_BOIL;
break;
case DP_ID_TEMP_CUR:
type = DP_TYPE_TEMP_CUR;
break;
case DP_ID_TEMP_SET:
type = DP_TYPE_TEMP_SET;
break;
case DP_ID_KEEP_WARM:
type = DP_TYPE_KEEP_WARM;
break;
case DP_ID_WATER_TYPE:
type = DP_TYPE_WATER_TYPE;
break;
case DP_ID_FAULT:
type = DP_TYPE_FAULT;
break;
default:
break;
}
return type;
}
/* 上报一个DP点 */
static void report_one_dp_data(uint8_t dp_id, uint8_t dp_value)
{
DP_DATA_T dp_data_s;
dp_data_s.id = dp_id;
dp_data_s.type = get_dp_type(dp_id);
dp_data_s.len = 0x01;
dp_data_s.value = dp_value;
/* 使用TUYA BLE SDK提供的API上报DP点数据 */
tuya_ble_dp_data_report((uint8_t *)&dp_data_s, sizeof(DP_DATA_T));
}
/* 上报所有DP点 */
static void report_all_dp_data(void)
{
report_one_dp_data(DP_ID_BOIL, g_kettle.boil_turn);
report_one_dp_data(DP_ID_KEEP_WARM, g_kettle.keep_warm_turn);
report_one_dp_data(DP_ID_TEMP_CUR, g_kettle.temp_cur);
report_one_dp_data(DP_ID_TEMP_SET, g_kettle.temp_set);
report_one_dp_data(DP_ID_WATER_TYPE, g_kettle.water_type);
report_one_dp_data(DP_ID_FAULT, g_kettle.fault);
}
3.接收数据处理
在App上改变设备状态时,会从云端下发控制数据,设备在接收到数据后进行如下处理,即可实现云端任务。
/* 设置煮沸功能开/关 */
static void set_boil_turn(uint8_t on_off)
{
if (g_kettle.fault != FAULT_NORMAL) { /* 故障发生时不执行 */
return;
}
g_kettle.boil_turn = on_off; /* 煮沸功能打开/关闭 */
report_one_dp_data(DP_ID_BOIL, g_kettle.boil_turn);
TUYA_APP_LOG_DEBUG("boil turn: %d", g_kettle.boil_turn);
set_led_red(on_off); /* 红色LED点亮/关闭 */
}
/* 设置保温功能开/关 */
static void set_keep_warm_turn(uint8_t on_off)
{
if (g_kettle.fault != FAULT_NORMAL) { /* 故障发生时不执行 */
return;
}
g_kettle.keep_warm_turn = on_off; /* 保温功能打开/关闭 */
report_one_dp_data(DP_ID_KEEP_WARM, g_kettle.keep_warm_turn);
TUYA_APP_LOG_DEBUG("keep warm turn: %d", g_kettle.keep_warm_turn);
set_led_orange(on_off); /* 橙色LED点亮/关闭 */
}
/* 设置保温温度 */
static void set_keep_warm_temp(uint8_t temp)
{
if (g_kettle.temp_set != temp) {
if ((temp >= 45) && (temp <= 90)) {
g_kettle.temp_set = temp; /* 在保温温度设定范围内时才更新参数值 */
}
}
}
/* 设置用水类型 */
static void set_water_type(WATER_TYPE_E type)
{
g_kettle.water_type = type;
}
/* DP点数据接收处理 */
void tuya_app_kettle_dp_data_handler(uint8_t *dp_data)
{
switch (dp_data[0]) {
case DP_ID_BOIL:
set_boil_turn(dp_data[3]);
*(dp_data + 3) = g_kettle.boil_turn;
break;
case DP_ID_KEEP_WARM:
set_keep_warm_turn(dp_data[3]);
*(dp_data + 3) = g_kettle.keep_warm_turn;
break;
case DP_ID_TEMP_SET:
set_keep_warm_temp(dp_data[6]);
*(dp_data + 6) = g_kettle.temp_set; /* VALUE类型下发时数据长度为4字节 */
break;
case DP_ID_WATER_TYPE:
set_water_type(dp_data[3]);
*(dp_data + 3) = g_kettle.water_type;
break;
case DP_ID_TEMP_CUR:
case DP_ID_FAULT:
default:
break;
}
}
/* 处理BLE SDK消息的callback函数 [tuya_ble_app_demo.c] */
static void tuya_cb_handler(tuya_ble_cb_evt_param_t* event)
{
...
case TUYA_BLE_CB_EVT_DP_WRITE: /* 在接收到DP数据时调用 */
dp_data_len = event->dp_write_data.data_len;
memset(dp_data_array, 0, sizeof(dp_data_array));
memcpy(dp_data_array, event->dp_write_data.p_data, dp_data_len);
tuya_app_kettle_dp_data_handler(dp_data_array);
TUYA_APP_LOG_HEXDUMP_DEBUG("received dp write data :", dp_data_array, dp_data_len);
sn = 0;
tuya_ble_dp_data_report(dp_data_array, dp_data_len);
break;
...
}
4.预约功能实现
预约功能可通过云定时功能实现,即在涂鸦IoT平台上产品开发的功能定义页中,打开高级云功能的云定时功能:
打开云定时功能后,还需在设备面板中修改云定时功能的属性,配置煮沸这个dp点,就可以在APP中设置定时煮沸任务,到达定时时间后云端就会下发控制命令触发dp_boil这个dp点数据下发,从而触发烧水壶执行煮沸功能。
小结
至此智能恒温烧水壶就完成了,它可以APP控制,按键控制。具有水质模式切换,保温温度设定,定时烧水,故障告警等功能。在这款智能烧水壶的基础上还有很多功能可以深入开发,使体验更加人性化,智能化。同时您可以基于涂鸦 IoT 平台丰富它的功能,也可以更加方便的搭建更多智能产品原型,加速智能产品的开发流程。
以上是关于智能烧水壶 (Bluetooth版)04——云端控制篇的主要内容,如果未能解决你的问题,请参考以下文章