四博 CozyLife AI 中控方案:基于 ESP32-C5 双频 Wi-Fi + 4G 打造智能家居语音控制入口

四博 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 控制中枢。
相关推荐
Change is good3 小时前
桌面型软件(如UE)AI测试工具
人工智能
jkyy20143 小时前
AI赋能智慧座舱:健康有益重构移动健康空间,定义出行健康新范式
大数据·人工智能·物联网·健康医疗
superstarsupers3 小时前
宫庭海出席2026横琴-澳门国际数字艺术博览会 畅谈AI虚拟偶像产业新生态
人工智能·百度
2501_945837434 小时前
OpenClaw:重新定义 AI 执行边界的开源智能体框架
人工智能
沪漂阿龙在努力4 小时前
OpenAI Agents SDK 完全指南:从“只会动嘴”到“真正干活”的AI
人工智能
user29876982706544 小时前
六、深入 Claude Code CLI 源码:会话管理与持久化
人工智能
蓝色的香菇4 小时前
从零写一个智能体:最核心的“化身” —— 循环(Agent Loop)
人工智能
蔡俊锋4 小时前
AI时代:人类从操控者到旁观者的蜕变
人工智能·深度学习·hermes·ai团队·ai团队知识沉淀
阿明观察4 小时前
破局·领航·赋能:解码国家云如何开辟Token经济新路径
大数据·人工智能