【2024 DigiKey创意大赛】环境灯控制系统作品提交
[复制链接]
本帖最后由 wakojosin 于 2024-10-29 23:55 编辑
- 作品简介
原来的项目是打算使用matter协议进行设备间的互联,但是由于网络原因,环境的搭建一直不成功,所以改成了WiFi的形式完成设备联网,然后通过mqtt进行设备间的通讯。
本项目主要用到的物料是esp32-s3-lcd-ev-board和esp32-s3-devkitc-1两个开发板,没有用到额外的传感器灯外围器件。两个板子的主控都是esp32s3,lcd-ev-board具有lcd和触摸屏等外围设备,kevkitc则是只有简单的外设。功能是通过esp32-s3-lcd-ev-board作为控制板,可以监控网络中接入的设备,然后通过UI界面进行展示设备的状态以及控制设备。设备端是以esp32-s3-devkitc-1来完成功能的,主要是当状态改变的时候,主动上报,当控制板下发命令的时候,响应控制命令,当前的控制命令就是电灯。
下面是设备的实物照
图表 1开灯时的界面显示
图表 2关灯时的界面显示
图表 3带上灯光板关灯状态
图表 4带上灯光板开灯状态
图表 5设置界面
二、系统框图
首先介绍一下本系统设计思路,环境灯的主要目标是可以通过一个中控面板方便的控制环境中的灯光系统,在家庭环境中则是可以方便的控制家中的各种各样的灯,所以开发了这么一个环境灯控制系统,本系统主要用到了wifi功能,通讯协议则是选择了mqtt,当有新的设备接入时,中控可以自动将设备添加到设备列表中,然后通过选择不同的灯,就可以控制这个灯的状态,比如开关,色彩等(当前只实现开关功能),同时也可以显示具有温湿度功能的灯所上传的温湿度数据(中控已经实现,但是当前没有带温湿度数据的灯),灯部分则是简单的实现了按键控制LED的开关,然后状态可以自动同步到中控中。
下面简单介绍一下系统软硬件,首先是硬件,下面是lcd-ev-board的原理图截图
图表 6中控主控
图表 7LCD接口原理图
图表 8触摸屏原理图
图表 9屏幕与主板的接口定义
下面是软件的系统框图
图表 10主流程
图表 11LED板流程图
三、各部分功能说明
下面对主要的功能模块进行解释说明,首先是wifi连接,这部分包含了wifi扫描和密码输入,下面是主要的代码逻辑:
下面是清空wifi列表的接口,wifi_list_wifis是wifi列表
void custom_clear_wifi_list(lv_ui *ui)
{
lv_obj_t *parent = ui->wifi_list_wifis;
lv_obj_t *child;
while(lv_obj_get_child_cnt(parent) > 1)
{
child = lv_obj_get_child(parent, 1);
lv_obj_del(child);
}
}
这个是wifi列表按下后的回调函数,主要功能是切换到键盘
static void wifi_list_wifis_item_x_event_handler (lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
switch (code) {
case LV_EVENT_CLICKED:
{
const char *cur_wifi = lv_list_get_btn_text(guider_ui.wifi_list_wifis, lv_event_get_target(e));
char buf[64];
int len = strlen(cur_wifi);
len = len > sizeof(buf)-1 ? sizeof(buf)-1 : len;
memcpy(buf, cur_wifi, len);
buf[len] = '\0';
ui_load_scr_animation(&guider_ui,&guider_ui.get_passwd,guider_ui.get_passwd_del,&guider_ui.wifi_del, setup_scr_get_passwd, LV_SCR_LOAD_ANIM_MOVE_LEFT, 200, 200, false, true);
lv_label_set_text(guider_ui.get_passwd_label_wifi, buf);
break;
}
}
}
这部分是添加wifi的接口,当扫描到wifi后就通过这个接口将扫描结果添加到wifi列表中
void custom_add_wifi_list(lv_ui *ui, const char *str)
{
lv_obj_t *parent = ui->wifi_list_wifis;
lv_obj_t *item = lv_list_add_btn(parent, LV_SYMBOL_WIFI, str);
lv_obj_add_event_cb(item, wifi_list_wifis_item_x_event_handler, LV_EVENT_ALL, ui);
}
接下去介绍一下mqtt部分的主要代码,首先是mqtt的处理任务,用来执行mqtt的连接、断开等控制操作
static void mqttc_process_entry(void *p)
{
struct mqttc_handler *handler = p;
esp_mqtt_client_handle_t client = NULL;
EventGroupHandle_t event = NULL;
uint32_t evt;
while(1)
{
evt = xEventGroupWaitBits(event, MQTTC_EVT_FLAG_ALL_BITS, pdTRUE, pdFALSE, portMAX_DELAY);
if(evt & BIT31)
{
ESP_LOGE(TAG, "wait bits timeout");
continue;
}
if(MQTTC_EVT_FLAG_IS_SET(evt, MQTTC_EVT_FLAG_CONNECTED))
{
int msg_id;
msg_id = esp_mqtt_client_subscribe(client, D2C_HEATBEAT, 0);
ESP_LOGI(TAG, "msg_id=%d", msg_id);
}
if(MQTTC_EVT_FLAG_IS_SET(evt, MQTTC_EVT_FLAG_DISCONNECTED))
{
ESP_LOGI(TAG, "mqtt disconned.");
}
if(MQTTC_EVT_FLAG_IS_SET(evt, MQTTC_EVT_FLAG_START))
{
if(handler->state == MQTTC_STA_DISCONNECTED)
{
ESP_LOGI(TAG, "mqtt client start:");
esp_err_t err = esp_mqtt_client_start(client);
ESP_LOGI(TAG, "%d", err);
handler->state = MQTTC_STA_CONNECTING;
}
}
if(MQTTC_EVT_FLAG_IS_SET(evt, MQTTC_EVT_FLAG_STOP))
{
ESP_LOGI(TAG, "mqtt client stop:");
esp_err_t err = esp_mqtt_client_stop(client);
ESP_LOGI(TAG, "%d", err);
}
}
}
然后是mqtt数据接收及处理部分的代码,这部分通过cJSON对接收到的数据进行解析,然后判断对应的数据项,获取所需的数据,执行对应的功能。
static void mqttc_data_arrived(void *handler, const char *topic, int topic_len, uint8_t *data, int data_len)
{
if(strncmp(topic, D2C_HEATBEAT, topic_len) == 0)
{
cJSON *data_root = cJSON_Parse((char *)data);
struct mqttc_handler *mqc = (struct mqttc_handler *)handler;
do
{
int led;
cJSON *item = cJSON_GetObjectItem(data_root, "led");
led = item->valueint;
item = cJSON_GetObjectItem(data_root, "device");
const char *device = item->valuestring;
ESP_LOGI(TAG, "device:%s, led:%d", device, led);
if(custom_check_device_list(&guider_ui, device) == false)
{
if(mqttc_device_subscribe(mqc, device) != ESP_OK)
{
ESP_LOGE(TAG, "sub failed:%p");
break;
}
custom_add_device_list(&guider_ui, device);
}
char humi[8],temp[8];
item = cJSON_GetObjectItem(data_root, "humi");
if(item != NULL)
{
int int_val = item->valueint;
int decimal_val = int_val%10;
if(decimal_val < 0)
{
decimal_val = -decimal_val;
}
int_val /= 10;
snprintf(humi, sizeof(humi), "%d.%d", int_val, decimal_val);
}
else
{
humi[0] = '\0';
}
item = cJSON_GetObjectItem(data_root, "temp");
if(item != NULL)
{
int int_val = item->valueint;
int decimal_val = int_val%10;
if(decimal_val < 0)
{
decimal_val = -decimal_val;
}
int_val /= 10;
snprintf(temp, sizeof(temp), "%d.%d", int_val, decimal_val);
}
else
{
temp[0] = '\0';
}
custom_update_device_data(&guider_ui, led, humi, temp);
}while(0);
if(data_root)
{
cJSON_Delete(data_root);
data_root = NULL;
}
}
}
至此,核心的业务逻辑已经介绍的差不多了,剩下的就是内容的显示,还有时间同步等相关功能,感兴趣的同学可以直接阅读源码。
四、作品源码
五、作品功能演示视频
六、项目总结
很高兴能够参加本次大赛,虽然没能按原计划学习matter相关的知识,但是从物联网的方向学习了多项技术,从而可以完整的实现一个非常实用的控制方案,也能够非常灵活的进行扩展,作为一个IO控制系统,实现简单的智能家居方案。
由于时间上面安排比较紧张,对于esp32的平台也不够熟悉,中间遇到的问题需要花很长的时间来定位和解决,所以没能够达到预期的成果。虽然大赛有截止时间,但是未来的学习还很长,通过esp32平台希望未来能够学习更多的物联网、AIOT相关的知识。
|