四博 CozyLife AI 中控方案:基于 ESP32-C5 双频 Wi-Fi + 4G 打造智能家居语音控制入口
AI 音箱如果只是"能聊天",其实还不够。真正能落地的 AI 硬件,应该既能听懂用户,又能连接真实设备;既能语音交互,又能控制灯光、插座、窗帘、空调、新风和传感器;既能走 Wi-Fi,又能在无宽带环境下走 4G;既能在线升级,又能支持客户二次开发和量产。
四博 CozyLife AI 中控方案,正是面向这类产品场景设计的一套完整 AIoT 方案。
该方案可基于 ESP32-C5 + 4G 模组 + 屏幕 + 电池 + 麦克风 + 喇叭 构建,支持 2.4G / 5G 双频 Wi-Fi、4G 联网、实时打断、自定义唤醒词、屏幕显示、电池供电、OTA 升级和 CozyLife 智能家居控制。四博开发宝典中 AI-C5 明确描述其基于 ESP32-C5,支持 2.4G 与 5G Wi-Fi、外接电池、屏幕、喇叭、麦克风,并支持 4G 模块接入;硬件参数包含 4 欧 3 瓦喇叭、咪头、3.2V 1200mA 电池和 2 寸 240×296 屏幕。
同时,四博模组选型手册中 ESP32-C5 系列定位为 Wi-Fi 6 2.4G & 5G + BLE + Zigbee + Thread 平台,ESPC5-32、ESPC5-32E、ESPC5-12/12E 等模组可匹配不同整机结构。
一、产品定位
四博 CozyLife AI 中控不是传统蓝牙音箱,而是一个具备联网、语音、屏幕、AI、家居控制能力的智能中枢。
四博 CozyLife AI 中控 =
ESP32-C5 双频 Wi-Fi
+ 4G 联网
+ AI 语音交互
+ 实时打断
+ 自定义唤醒词
+ 屏幕显示
+ 电池供电
+ CozyLife 智能家居控制
+ MCP 工具调用
+ OTA 在线升级
它适合以下产品形态:
AI 智能音箱
AI 智能中控
AI 故事机
AI 学习陪伴设备
AI 桌面助手
AI 智能家居网关
酒店客控终端
养老陪护终端
公寓语音控制面板
海外市场 4G AI 终端
四博 AI 方案选型表中也提到,AI-4G+WIFI 成品板选用 ESP32-C5-32 和 4G 模组,支持 Wi-Fi 入网、2.4G + 5G 频段 Wi-Fi、蓝牙 BT、4G 入网,可选 1.54 寸屏幕、喇叭、麦克风、电池,并可适配小智、豆包、ChatGPT 等主流大模型。
二、系统整体架构
整体架构可以分为四层:
用户语音 / 触摸 / 按键
↓
ESP32-C5 AI 终端
↓
双频 Wi-Fi / 4G / BLE 配网
↓
AI 云端服务 / CozyLife 平台 / MCP 工具层
↓
灯具 / 插座 / 开关 / 空调 / 窗帘 / 新风 / 传感器
端侧 ESP32-C5 主要负责:
1. Wi-Fi 2.4G / 5G 联网
2. 4G 网络接入
3. 麦克风音频采集
4. 喇叭 TTS 播放
5. 实时打断控制
6. 屏幕状态显示
7. 电池供电管理
8. 自定义唤醒词配置
9. MQTT / HTTP / WebSocket 通信
10. MCP 工具调用执行
11. OTA 在线升级
云端主要负责:
1. ASR 语音识别
2. LLM 大模型理解
3. TTS 语音合成
4. CozyLife 设备映射
5. 智能家居控制
6. 场景自动化
7. 用户账号和设备绑定
8. 知识库和智能体管理
三、推荐硬件配置
| 模块 | 推荐配置 |
|---|---|
| 主控 | ESP32-C5 / ESPC5-32 / ESPC5-32E |
| 网络 | 2.4G + 5G Wi-Fi,支持 4G 模组 |
| 蓝牙 | BLE / BluFi 配网 |
| 显示 | 1.54 寸 / 2 寸 / 最大可扩展大屏 |
| 音频输入 | 咪头 / I2S Mic / Codec Mic |
| 音频输出 | 4Ω 3W 喇叭 |
| 电池 | 1200mAh 级电池,支持便携使用 |
| 供电 | Type-C + 电池 |
| 外设 | 按键、LCD、马达、传感器、UART |
| 升级 | HTTPS OTA / 在线烧录平台 |
| 应用 | CozyLife 控制、AI 对话、智能体、MCP |
四、软件模块设计
推荐工程结构如下:
cozylife_ai_c5/
├── main/
│ ├── app_main.c
│ ├── board_config.h
│ ├── wifi_manager.c
│ ├── cellular_4g.c
│ ├── net_manager.c
│ ├── audio_capture.c
│ ├── audio_player.c
│ ├── interrupt_service.c
│ ├── wakeword_service.c
│ ├── lcd_ui.c
│ ├── battery_service.c
│ ├── ai_ws_client.c
│ ├── mcp_service.c
│ ├── cozylife_api.c
│ ├── mqtt_service.c
│ ├── scene_service.c
│ └── ota_service.c
├── components/
│ ├── codec/
│ ├── lcd_driver/
│ ├── modem_4g/
│ └── wakeword_vb6824/
├── partitions_ota.csv
└── sdkconfig.defaults
系统状态机建议:
typedef enum {
SYS_STATE_BOOT = 0,
SYS_STATE_WIFI_CONFIG,
SYS_STATE_4G_CONNECTING,
SYS_STATE_WIFI_CONNECTING,
SYS_STATE_ONLINE,
SYS_STATE_IDLE,
SYS_STATE_LISTENING,
SYS_STATE_THINKING,
SYS_STATE_SPEAKING,
SYS_STATE_INTERRUPTED,
SYS_STATE_OTA,
SYS_STATE_LOW_BATTERY,
SYS_STATE_ERROR
} system_state_t;
五、板级配置示例
下面是一个适合 ESP32-C5 + 4G + 屏幕 + 电池 + 音频的板级配置模板。实际 GPIO 需要根据原理图调整。
#pragma once
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "driver/spi_master.h"
#include "driver/uart.h"
/* 产品名称 */
#define BOARD_NAME "DOIT_COZYLIFE_AI_C5"
/* I2S Audio */
#define PIN_I2S_BCLK GPIO_NUM_4
#define PIN_I2S_WS GPIO_NUM_5
#define PIN_I2S_DIN GPIO_NUM_6
#define PIN_I2S_DOUT GPIO_NUM_7
/* LCD SPI */
#define LCD_HOST SPI2_HOST
#define PIN_LCD_MOSI GPIO_NUM_10
#define PIN_LCD_SCLK GPIO_NUM_11
#define PIN_LCD_CS GPIO_NUM_12
#define PIN_LCD_DC GPIO_NUM_13
#define PIN_LCD_RST GPIO_NUM_14
#define PIN_LCD_BL GPIO_NUM_15
/* 4G 模组 UART */
#define MODEM_UART_PORT UART_NUM_1
#define PIN_MODEM_TX GPIO_NUM_16
#define PIN_MODEM_RX GPIO_NUM_17
#define PIN_MODEM_PWRKEY GPIO_NUM_18
#define PIN_MODEM_RESET GPIO_NUM_19
/* VB6824 / 离线语音 UART */
#define WAKE_UART_PORT UART_NUM_2
#define PIN_WAKE_TX GPIO_NUM_20
#define PIN_WAKE_RX GPIO_NUM_21
/* Button */
#define PIN_BOOT_KEY GPIO_NUM_0
#define PIN_KEY_WAKE GPIO_NUM_1
#define PIN_KEY_VOL_UP GPIO_NUM_2
#define PIN_KEY_VOL_DOWN GPIO_NUM_3
/* Battery ADC */
#define PIN_BAT_ADC GPIO_NUM_8
/* Audio Params */
#define AUDIO_SAMPLE_RATE 16000
#define AUDIO_BITS_PER_SAMPLE 16
#define AUDIO_CHANNELS 1
#define AUDIO_FRAME_MS 20
#define AUDIO_FRAME_SAMPLES (AUDIO_SAMPLE_RATE * AUDIO_FRAME_MS / 1000)
六、主程序框架
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "board_config.h"
#include "wifi_manager.h"
#include "cellular_4g.h"
#include "net_manager.h"
#include "audio_capture.h"
#include "audio_player.h"
#include "interrupt_service.h"
#include "wakeword_service.h"
#include "lcd_ui.h"
#include "battery_service.h"
#include "ai_ws_client.h"
#include "mcp_service.h"
#include "cozylife_api.h"
#include "mqtt_service.h"
#include "ota_service.h"
static const char *TAG = "COZYLIFE_C5";
void app_main(void)
{
ESP_LOGI(TAG, "%s booting...", BOARD_NAME);
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
lcd_ui_init();
lcd_ui_show_status("系统启动中");
battery_service_init();
wakeword_service_init();
audio_capture_init();
audio_player_init();
wifi_manager_init();
cellular_4g_init();
net_manager_init();
ai_ws_client_init();
mcp_service_init();
cozylife_api_init();
mqtt_service_init();
ota_service_init();
interrupt_service_init();
net_manager_start();
xTaskCreatePinnedToCore(audio_capture_task,
"audio_capture",
8192,
NULL,
5,
NULL,
0);
xTaskCreatePinnedToCore(audio_player_task,
"audio_player",
8192,
NULL,
5,
NULL,
1);
xTaskCreatePinnedToCore(ai_ws_client_task,
"ai_ws_client",
10240,
NULL,
6,
NULL,
1);
xTaskCreatePinnedToCore(battery_service_task,
"battery",
4096,
NULL,
3,
NULL,
0);
xTaskCreatePinnedToCore(ota_service_task,
"ota",
6144,
NULL,
3,
NULL,
0);
lcd_ui_show_status("等待联网");
ESP_LOGI(TAG, "system initialized");
}
七、双频 Wi-Fi + 4G 网络管理
AI 终端最怕网络不稳定。ESP32-C5 支持 2.4G / 5G Wi-Fi,配合 4G 模组,可以实现家庭、酒店、公寓、户外、海外场景的多网络覆盖。
网络策略建议:
优先级 1:已配置 Wi-Fi,优先连接 5G
优先级 2:5G 失败,尝试 2.4G
优先级 3:Wi-Fi 不可用,切换 4G
优先级 4:4G 不可用,进入离线唤醒和本地控制模式
网络状态定义:
typedef enum {
NET_TYPE_NONE = 0,
NET_TYPE_WIFI_24G,
NET_TYPE_WIFI_5G,
NET_TYPE_4G
} net_type_t;
typedef enum {
NET_STATE_IDLE = 0,
NET_STATE_CONNECTING,
NET_STATE_CONNECTED,
NET_STATE_FAILED
} net_state_t;
typedef struct {
net_type_t active_type;
net_state_t state;
int rssi;
int online;
} net_status_t;
网络管理逻辑:
static net_status_t g_net = {0};
void net_manager_start(void)
{
lcd_ui_show_status("正在连接 Wi-Fi");
if (wifi_manager_connect_saved() == ESP_OK) {
g_net.active_type = wifi_manager_is_5g() ?
NET_TYPE_WIFI_5G :
NET_TYPE_WIFI_24G;
g_net.state = NET_STATE_CONNECTED;
g_net.online = 1;
lcd_ui_show_status("Wi-Fi 已连接");
ai_ws_client_start();
return;
}
lcd_ui_show_status("Wi-Fi失败,切换4G");
if (cellular_4g_connect() == ESP_OK) {
g_net.active_type = NET_TYPE_4G;
g_net.state = NET_STATE_CONNECTED;
g_net.online = 1;
lcd_ui_show_status("4G 已连接");
ai_ws_client_start();
return;
}
g_net.active_type = NET_TYPE_NONE;
g_net.state = NET_STATE_FAILED;
g_net.online = 0;
lcd_ui_show_status("网络不可用");
}
开发宝典中也给出了 AI-C5 的 Wi-Fi 模式与 4G 模式切换方式:4G 模式下重新开机,在屏幕显示等待网络时双击 boot 键可切换到 Wi-Fi 配网模式;Wi-Fi 模式下在配网界面双击 boot 键可切换到 4G 模式并自动连接。
八、4G 模组 AT 初始化示例
4G 模组一般通过 UART AT 指令连接。下面是一个通用初始化模板:
#include "driver/uart.h"
#include "esp_log.h"
#include <string.h>
static const char *TAG = "CELLULAR_4G";
static esp_err_t modem_send_cmd(const char *cmd,
const char *expect,
int timeout_ms)
{
uart_write_bytes(MODEM_UART_PORT, cmd, strlen(cmd));
char rxbuf[256] = {0};
int len = uart_read_bytes(MODEM_UART_PORT,
rxbuf,
sizeof(rxbuf) - 1,
pdMS_TO_TICKS(timeout_ms));
if (len > 0) {
rxbuf[len] = 0;
ESP_LOGI(TAG, "AT rsp: %s", rxbuf);
if (expect == NULL || strstr(rxbuf, expect)) {
return ESP_OK;
}
}
return ESP_FAIL;
}
void cellular_4g_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_driver_install(MODEM_UART_PORT, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART_PORT, &uart_config);
uart_set_pin(MODEM_UART_PORT,
PIN_MODEM_TX,
PIN_MODEM_RX,
UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE);
gpio_set_direction(PIN_MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_direction(PIN_MODEM_RESET, GPIO_MODE_OUTPUT);
}
esp_err_t cellular_4g_connect(void)
{
modem_send_cmd("AT\r\n", "OK", 1000);
modem_send_cmd("ATE0\r\n", "OK", 1000);
modem_send_cmd("AT+CPIN?\r\n", "READY", 3000);
modem_send_cmd("AT+CSQ\r\n", "OK", 1000);
modem_send_cmd("AT+CREG?\r\n", "OK", 1000);
modem_send_cmd("AT+CGATT=1\r\n", "OK", 5000);
/*
* APN 按运营商或客户 SIM 卡配置
*/
modem_send_cmd("AT+CGDCONT=1,\"IP\",\"cmnet\"\r\n", "OK", 1000);
/*
* 后续可接 PPPoS 或模组内置 TCP/IP 协议栈
*/
return ESP_OK;
}
九、实时打断设计
AI 音箱必须支持实时打断。用户不应该等设备说完才能继续说话。
打断触发来源:
1. 用户再次说唤醒词
2. 用户按下唤醒键
3. 用户触摸屏幕或按键
4. 云端检测到 barge-in
5. 本地 VAD 检测到用户插话
状态定义:
typedef enum {
AUDIO_STATE_IDLE = 0,
AUDIO_STATE_RECORDING,
AUDIO_STATE_UPLOADING,
AUDIO_STATE_PLAYING,
AUDIO_STATE_INTERRUPTED
} audio_state_t;
static volatile audio_state_t g_audio_state = AUDIO_STATE_IDLE;
打断核心代码:
void interrupt_current_session(void)
{
if (g_audio_state == AUDIO_STATE_PLAYING) {
audio_player_stop();
ai_ws_send_control("{\"type\":\"interrupt\"}");
lcd_ui_show_status("已打断,请继续说");
g_audio_state = AUDIO_STATE_INTERRUPTED;
audio_capture_start();
g_audio_state = AUDIO_STATE_RECORDING;
}
}
本地 VAD 打断示例:
static int vad_detect_user_voice(const int16_t *pcm, size_t samples)
{
int64_t energy = 0;
for (size_t i = 0; i < samples; i++) {
energy += abs(pcm[i]);
}
int avg = energy / samples;
return avg > 800;
}
void audio_capture_task(void *arg)
{
int16_t pcm[AUDIO_FRAME_SAMPLES];
size_t bytes_read = 0;
while (1) {
audio_read_pcm(pcm, sizeof(pcm), &bytes_read);
if (g_audio_state == AUDIO_STATE_PLAYING) {
if (vad_detect_user_voice(pcm, AUDIO_FRAME_SAMPLES)) {
interrupt_current_session();
continue;
}
}
if (g_audio_state == AUDIO_STATE_RECORDING) {
ai_ws_send_audio((uint8_t *)pcm, bytes_read);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
开发宝典目录中包含"编译实时打断固件"章节,说明该方案已经将实时打断作为独立能力进行支持。
十、自助修改唤醒词
CozyLife AI 中控可支持客户自助修改唤醒词,例如:
你好小智
你好四博
小 C 小 C
打开管家
Hi CozyLife
开发宝典中包含"VB6824 如何自定义唤醒词"章节,说明该类离线语音方案可进行唤醒词自定义配置。
唤醒词配置结构:
typedef struct {
char wakeword[64];
int sensitivity;
int enabled;
} wakeword_config_t;
通过 NVS 保存唤醒词:
#include "nvs_flash.h"
#include "nvs.h"
esp_err_t wakeword_save_config(const wakeword_config_t *cfg)
{
nvs_handle_t handle;
esp_err_t ret = nvs_open("wakeword", NVS_READWRITE, &handle);
if (ret != ESP_OK) return ret;
nvs_set_str(handle, "word", cfg->wakeword);
nvs_set_i32(handle, "sens", cfg->sensitivity);
nvs_set_i32(handle, "en", cfg->enabled);
nvs_commit(handle);
nvs_close(handle);
return ESP_OK;
}
esp_err_t wakeword_load_config(wakeword_config_t *cfg)
{
nvs_handle_t handle;
size_t len = sizeof(cfg->wakeword);
esp_err_t ret = nvs_open("wakeword", NVS_READONLY, &handle);
if (ret != ESP_OK) return ret;
nvs_get_str(handle, "word", cfg->wakeword, &len);
nvs_get_i32(handle, "sens", &cfg->sensitivity);
nvs_get_i32(handle, "en", &cfg->enabled);
nvs_close(handle);
return ESP_OK;
}
通过 UART 下发给离线语音芯片:
void wake_uart_send(const char *cmd)
{
uart_write_bytes(WAKE_UART_PORT, cmd, strlen(cmd));
}
/*
* 说明:
* 下方 AT 指令为工程封装示例,实际指令格式应以 VB6824 固件协议为准。
*/
esp_err_t wakeword_apply_to_vb6824(const wakeword_config_t *cfg)
{
char cmd[128];
snprintf(cmd, sizeof(cmd),
"AT+WAKEWORD=\"%s\",%d\r\n",
cfg->wakeword,
cfg->sensitivity);
wake_uart_send(cmd);
return ESP_OK;
}
用户通过屏幕或小程序修改唤醒词后:
void user_update_wakeword(const char *word, int sensitivity)
{
wakeword_config_t cfg = {0};
strncpy(cfg.wakeword, word, sizeof(cfg.wakeword) - 1);
cfg.sensitivity = sensitivity;
cfg.enabled = 1;
wakeword_save_config(&cfg);
wakeword_apply_to_vb6824(&cfg);
lcd_ui_show_status("唤醒词已更新");
}
十一、屏幕 UI 设计
屏幕不是简单显示 Logo,而是设备状态窗口。
建议显示状态:
Wi-Fi 连接中
4G 连接中
AI 在线
正在聆听
正在思考
正在播放
已打断
电量低
OTA 升级中
配网二维码
设备验证码
LCD UI 状态枚举:
typedef enum {
UI_PAGE_BOOT = 0,
UI_PAGE_NET_CONNECTING,
UI_PAGE_WIFI_CONFIG,
UI_PAGE_4G_CONNECTING,
UI_PAGE_AI_IDLE,
UI_PAGE_LISTENING,
UI_PAGE_THINKING,
UI_PAGE_SPEAKING,
UI_PAGE_LOW_BATTERY,
UI_PAGE_OTA
} ui_page_t;
UI 更新接口:
void lcd_ui_show_page(ui_page_t page)
{
lcd_clear();
switch (page) {
case UI_PAGE_BOOT:
lcd_draw_text(20, 40, "CozyLife AI");
lcd_draw_text(20, 70, "系统启动中...");
break;
case UI_PAGE_WIFI_CONFIG:
lcd_draw_text(20, 40, "Wi-Fi 配网模式");
lcd_draw_text(20, 70, "请使用小程序配网");
break;
case UI_PAGE_4G_CONNECTING:
lcd_draw_text(20, 40, "4G 网络连接中");
break;
case UI_PAGE_LISTENING:
lcd_draw_text(20, 40, "正在聆听...");
break;
case UI_PAGE_THINKING:
lcd_draw_text(20, 40, "AI 思考中...");
break;
case UI_PAGE_SPEAKING:
lcd_draw_text(20, 40, "AI 正在回答");
break;
case UI_PAGE_LOW_BATTERY:
lcd_draw_text(20, 40, "电量低");
lcd_draw_text(20, 70, "请充电");
break;
case UI_PAGE_OTA:
lcd_draw_text(20, 40, "正在升级");
lcd_draw_text(20, 70, "请勿断电");
break;
default:
lcd_draw_text(20, 40, "AI 在线");
break;
}
}
十二、电池供电管理
电池供电让 AI 中控不局限于固定电源场景,可用于桌面、卧室、床头、移动陪伴设备。
电池状态:
typedef struct {
int voltage_mv;
int percent;
int charging;
int low_power;
} battery_status_t;
电压换算:
static int battery_voltage_to_percent(int mv)
{
if (mv >= 4200) return 100;
if (mv >= 4000) return 85;
if (mv >= 3800) return 65;
if (mv >= 3700) return 45;
if (mv >= 3600) return 25;
if (mv >= 3400) return 10;
return 3;
}
void battery_service_task(void *arg)
{
while (1) {
int mv = battery_read_voltage_mv();
int percent = battery_voltage_to_percent(mv);
if (percent <= 10) {
lcd_ui_show_page(UI_PAGE_LOW_BATTERY);
audio_player_play_prompt("low_battery.wav");
}
mqtt_report_battery(percent, mv);
vTaskDelay(pdMS_TO_TICKS(30000));
}
}
上报电量到 CozyLife 平台:
void mqtt_report_battery(int percent, int voltage_mv)
{
char json[128];
snprintf(json, sizeof(json),
"{"
"\"battery\":%d,"
"\"voltage_mv\":%d"
"}",
percent,
voltage_mv);
mqtt_publish("cozylife/device/property/report", json);
}
十三、CozyLife 智能家居控制模型
设备控制结构:
typedef enum {
DEV_LIGHT = 0,
DEV_SOCKET,
DEV_SWITCH,
DEV_CURTAIN,
DEV_AIR_CONDITIONER,
DEV_FRESH_AIR,
DEV_SENSOR_TEMP,
DEV_SENSOR_PIR,
DEV_UNKNOWN
} device_type_t;
typedef struct {
char device_id[32];
char room[32];
device_type_t type;
int online;
int power;
int brightness;
int color_temp;
int temperature;
int humidity;
} smart_device_t;
typedef struct {
char device_id[32];
char action[32];
int value;
} control_cmd_t;
HTTP 控制接口:
esp_err_t cozylife_control_device(control_cmd_t *cmd)
{
char json[256];
snprintf(json, sizeof(json),
"{"
"\"device_id\":\"%s\","
"\"action\":\"%s\","
"\"value\":%d"
"}",
cmd->device_id,
cmd->action,
cmd->value);
return http_post_json("https://api.customer-platform.com/device/control",
json);
}
灯光控制:
void turn_on_light(const char *device_id)
{
control_cmd_t cmd = {0};
strcpy(cmd.device_id, device_id);
strcpy(cmd.action, "power");
cmd.value = 1;
cozylife_control_device(&cmd);
}
void set_light_brightness(const char *device_id, int brightness)
{
if (brightness < 0) brightness = 0;
if (brightness > 100) brightness = 100;
control_cmd_t cmd = {0};
strcpy(cmd.device_id, device_id);
strcpy(cmd.action, "brightness");
cmd.value = brightness;
cozylife_control_device(&cmd);
}
十四、MCP 工具调用
AI 真正有价值的地方,是把自然语言转换成设备动作。
用户说:
打开客厅灯
把卧室灯调成暖光
关闭所有插座
进入睡眠模式
查询客厅温度
AI 后端返回:
{
"type": "tool_call",
"tool": "cozylife.device.control",
"arguments": {
"device_id": "light_livingroom_01",
"action": "power",
"value": 1
}
}
设备端 MCP 分发:
typedef enum {
MCP_TOOL_DEVICE_CONTROL = 0,
MCP_TOOL_SCENE_RUN,
MCP_TOOL_SENSOR_QUERY,
MCP_TOOL_WAKEWORD_UPDATE,
MCP_TOOL_NET_SWITCH,
MCP_TOOL_UNKNOWN
} mcp_tool_id_t;
typedef struct {
const char *name;
mcp_tool_id_t id;
} mcp_tool_map_t;
static const mcp_tool_map_t g_mcp_tools[] = {
{"cozylife.device.control", MCP_TOOL_DEVICE_CONTROL},
{"cozylife.scene.run", MCP_TOOL_SCENE_RUN},
{"cozylife.sensor.query", MCP_TOOL_SENSOR_QUERY},
{"device.wakeword.update", MCP_TOOL_WAKEWORD_UPDATE},
{"device.network.switch", MCP_TOOL_NET_SWITCH},
};
static mcp_tool_id_t mcp_get_tool_id(const char *name)
{
for (int i = 0; i < sizeof(g_mcp_tools) / sizeof(g_mcp_tools[0]); i++) {
if (strcmp(name, g_mcp_tools[i].name) == 0) {
return g_mcp_tools[i].id;
}
}
return MCP_TOOL_UNKNOWN;
}
MCP 执行:
void mcp_service_handle(cJSON *root)
{
cJSON *tool = cJSON_GetObjectItem(root, "tool");
cJSON *args = cJSON_GetObjectItem(root, "arguments");
if (!cJSON_IsString(tool) || !cJSON_IsObject(args)) {
return;
}
switch (mcp_get_tool_id(tool->valuestring)) {
case MCP_TOOL_DEVICE_CONTROL:
mcp_handle_device_control(args);
break;
case MCP_TOOL_SCENE_RUN:
mcp_handle_scene_run(args);
break;
case MCP_TOOL_SENSOR_QUERY:
mcp_handle_sensor_query(args);
break;
case MCP_TOOL_WAKEWORD_UPDATE:
mcp_handle_wakeword_update(args);
break;
case MCP_TOOL_NET_SWITCH:
mcp_handle_network_switch(args);
break;
default:
ESP_LOGW("MCP", "unknown tool: %s", tool->valuestring);
break;
}
}
十五、场景模式
回家模式:
void scene_home_mode(void)
{
turn_on_light("light_livingroom_01");
set_light_brightness("light_livingroom_01", 80);
control_cmd_t curtain = {0};
strcpy(curtain.device_id, "curtain_livingroom_01");
strcpy(curtain.action, "open");
curtain.value = 100;
cozylife_control_device(&curtain);
control_cmd_t ac = {0};
strcpy(ac.device_id, "air_conditioner_livingroom");
strcpy(ac.action, "cooling");
ac.value = 26;
cozylife_control_device(&ac);
lcd_ui_show_status("回家模式已开启");
}
睡眠模式:
void scene_sleep_mode(void)
{
set_light_brightness("light_bedroom_01", 10);
control_cmd_t socket = {0};
strcpy(socket.device_id, "socket_tv_01");
strcpy(socket.action, "power");
socket.value = 0;
cozylife_control_device(&socket);
control_cmd_t curtain = {0};
strcpy(curtain.device_id, "curtain_bedroom_01");
strcpy(curtain.action, "close");
curtain.value = 100;
cozylife_control_device(&curtain);
lcd_ui_show_status("睡眠模式已开启");
}
离家模式:
void scene_away_mode(void)
{
control_cmd_t cmd = {0};
strcpy(cmd.device_id, "all_lights");
strcpy(cmd.action, "power");
cmd.value = 0;
cozylife_control_device(&cmd);
strcpy(cmd.device_id, "all_sockets");
strcpy(cmd.action, "power");
cmd.value = 0;
cozylife_control_device(&cmd);
strcpy(cmd.device_id, "all_air_conditioners");
strcpy(cmd.action, "power");
cmd.value = 0;
cozylife_control_device(&cmd);
lcd_ui_show_status("离家模式已开启");
}
十六、MQTT 接入 CozyLife / 客户平台
主题设计:
设备属性上报:
cozylife/{device_id}/property/report
设备控制下发:
cozylife/{device_id}/command/set
设备响应:
cozylife/{device_id}/command/reply
OTA 通知:
cozylife/{device_id}/ota/notify
网络状态:
cozylife/{device_id}/network/status
MQTT 初始化:
#include "mqtt_client.h"
static esp_mqtt_client_handle_t g_mqtt_client = NULL;
static void mqtt_event_handler(void *handler_args,
esp_event_base_t base,
int32_t event_id,
void *event_data)
{
esp_mqtt_event_handle_t event = event_data;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
esp_mqtt_client_subscribe(event->client,
"cozylife/+/command/set",
1);
esp_mqtt_client_subscribe(event->client,
"cozylife/+/ota/notify",
1);
break;
case MQTT_EVENT_DATA:
mqtt_handle_message(event->topic,
event->topic_len,
event->data,
event->data_len);
break;
default:
break;
}
}
void mqtt_service_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = "mqtt://broker.customer-platform.com",
};
g_mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(g_mqtt_client,
ESP_EVENT_ANY_ID,
mqtt_event_handler,
NULL);
esp_mqtt_client_start(g_mqtt_client);
}
十七、OTA 与量产升级
AI 终端量产后,OTA 是必须功能。
OTA 可升级:
1. 主固件
2. 唤醒词配置
3. AI 后端地址
4. MCP 工具列表
5. 屏幕 UI 资源
6. 提示音资源
7. CozyLife 控制协议
8. Wi-Fi / 4G 网络策略
版本文件:
{
"project": "cozylife_ai_c5",
"version": "1.0.3",
"chip": "esp32c5",
"url": "https://ota.customer-platform.com/cozylife_c5_v1.0.3.bin",
"md5": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"force": false,
"note": "新增4G/WiFi自动切换、实时打断和自定义唤醒词"
}
OTA 代码:
#include "esp_https_ota.h"
#include "esp_http_client.h"
void ota_check_update(void)
{
esp_http_client_config_t config = {
.url = "https://ota.customer-platform.com/cozylife/latest.bin",
.timeout_ms = 10000,
.keep_alive_enable = true,
};
esp_https_ota_config_t ota_config = {
.http_config = &config,
};
lcd_ui_show_page(UI_PAGE_OTA);
esp_err_t ret = esp_https_ota(&ota_config);
if (ret == ESP_OK) {
lcd_ui_show_status("升级成功,正在重启");
esp_restart();
} else {
lcd_ui_show_status("升级失败");
}
}
分区表示例:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
otadata, data, ota, 0xf000, 0x2000,
phy_init, data, phy, 0x11000, 0x1000,
factory, app, factory, 0x20000, 0x300000,
ota_0, app, ota_0, , 0x300000,
ota_1, app, ota_1, , 0x300000,
storage, data, spiffs, , 0x100000,
十八、开发和量产流程
四博开发宝典中说明,小智 AI 系统硬件设备开源代码可通过 VSCode 安装 ESP-IDF 扩展和编译工具进行开发、编译和烧录;文档中还包含 AI-C5 的硬件连接、源码下载、编译参数、Wi-Fi / 4G 模式切换、设备配网、实时打断固件、自定义唤醒词和在线烧录平台等章节。
开发流程可以概括为:
1. 下载 DOIT_AI 源码
2. 选择 AI-C5 对应 board 配置
3. 配置 ESP-IDF 环境
4. 编译默认固件
5. 烧录到 AI-C5 开发板
6. 通过 SoftAP / BluFi 完成配网
7. 绑定 AI 后端或 CozyLife 平台
8. 开启实时打断固件
9. 配置自定义唤醒词
10. 配置 OTA 地址
11. 进入量产测试
命令示例:
git clone https://github.com/SmartArduino/DOIT_AI.git
cd DOIT_AI
idf.py set-target esp32c5
idf.py menuconfig
idf.py build
idf.py -p COMx flash monitor
若使用四博默认 board 配置,可按工程中的 doit-ai-c5-kit-lcd 默认配置进行编译。
十九、方案核心价值
四博 CozyLife AI-C5 方案的核心价值可以概括为:
1. ESP32-C5 双频 Wi-Fi,覆盖 2.4G / 5G 家庭网络
2. 支持 4G 模组,适合无宽带、移动、海外场景
3. 支持实时打断,AI 对话体验更接近真人
4. 支持自定义唤醒词,方便品牌客户定制
5. 支持屏幕显示,设备状态可视化
6. 支持电池供电,产品形态更灵活
7. 支持 CozyLife 智能家居控制
8. 支持 MCP 工具调用,让 AI 能真正控制设备
9. 支持 OTA,量产后仍可持续升级
10. 代码、文档、视频齐全,降低二次开发门槛
二十、结语
四博 CozyLife AI-C5 方案不是一个简单的 Wi-Fi 音箱方案,而是一套面向 AIoT 落地的智能家居语音中控方案。
它把 ESP32-C5 双频 Wi-Fi、4G 网络、屏幕、电池、麦克风、喇叭、实时打断、自定义唤醒词、MCP 工具调用和 CozyLife 智能家居平台结合在一起,让设备真正具备:
听得懂用户
连得上网络
控得了设备
看得见状态
断得了回复
改得了唤醒词
升得了系统
适配得了量产
一句话总结:
四博 CozyLife AI-C5 方案,
不是把 AI 放进音箱里,
而是把 AI、双频 Wi-Fi、4G、屏幕、电池和智能家居控制,
整合成一个真正可量产、可二次开发、可持续升级的 AIoT 控制中枢。