ESP32-S3高级功能开发

基于小智AI项目实践,本指南详细介绍ESP32-S3的高级功能开发,包括4G通信、本地AI推理、多模态交互等前沿技术的具体实现。

一、4G通信模块集成

1.1 ML307R Cat.1模块接入

适用场景: 户外环境、移动设备、无Wi-Fi覆盖的IoT应用

硬件连接

ESP32-S3     →    ML307R Cat.1
GPIO11       →    TXD (发送数据)
GPIO12       →    RXD (接收数据) 
3.3V         →    VCC (电源)
GND          →    GND (接地)
LDO输出(~5V) →    BAT (电池电源,短接EN使能)

AT命令通信实现

#include "driver/uart.h"
#include "string.h"

#define ML307R_UART_PORT    UART_NUM_1
#define ML307R_TXD_PIN      GPIO_NUM_11
#define ML307R_RXD_PIN      GPIO_NUM_12
#define ML307R_BUFFER_SIZE  1024

typedef enum {
    ML307R_STATE_INIT,
    ML307R_STATE_READY,
    ML307R_STATE_CONNECTED,
    ML307R_STATE_ERROR
} ml307r_state_t;

static ml307r_state_t ml307r_state = ML307R_STATE_INIT;

// 初始化ML307R UART
void ml307r_uart_init() {
    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,
        .source_clk = UART_SCLK_DEFAULT,
    };
    
    ESP_ERROR_CHECK(uart_driver_install(ML307R_UART_PORT, ML307R_BUFFER_SIZE * 2, 0, 0, NULL, 0));
    ESP_ERROR_CHECK(uart_param_config(ML307R_UART_PORT, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(ML307R_UART_PORT, ML307R_TXD_PIN, ML307R_RXD_PIN, 
                                  UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
}

// 发送AT命令
bool ml307r_send_command(const char* command, const char* expected_response, uint32_t timeout_ms) {
    char response[512];
    
    // 发送命令
    uart_write_bytes(ML307R_UART_PORT, command, strlen(command));
    uart_write_bytes(ML307R_UART_PORT, "\r\n", 2);
    
    // 等待响应
    int len = uart_read_bytes(ML307R_UART_PORT, response, sizeof(response) - 1, 
                             pdMS_TO_TICKS(timeout_ms));
    
    if (len > 0) {
        response[len] = '\0';
        ESP_LOGI("ML307R", "命令: %s, 响应: %s", command, response);
        
        if (expected_response && strstr(response, expected_response)) {
            return true;
        }
    }
    
    return false;
}

// 4G网络初始化
esp_err_t ml307r_network_init(const char* apn) {
    ESP_LOGI("ML307R", "初始化4G网络...");
    
    // 检查模块状态
    if (!ml307r_send_command("AT", "OK", 3000)) {
        ESP_LOGE("ML307R", "模块无响应");
        return ESP_FAIL;
    }
    
    // 检查SIM卡
    if (!ml307r_send_command("AT+CPIN?", "+CPIN: READY", 5000)) {
        ESP_LOGE("ML307R", "SIM卡未准备就绪");
        return ESP_FAIL;
    }
    
    // 设置APN
    char apn_cmd[128];
    snprintf(apn_cmd, sizeof(apn_cmd), "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
    if (!ml307r_send_command(apn_cmd, "OK", 3000)) {
        ESP_LOGE("ML307R", "APN设置失败");
        return ESP_FAIL;
    }
    
    // 激活PDP上下文
    if (!ml307r_send_command("AT+CGACT=1,1", "OK", 10000)) {
        ESP_LOGE("ML307R", "网络连接失败");
        return ESP_FAIL;
    }
    
    // 获取IP地址
    if (ml307r_send_command("AT+CGPADDR=1", "+CGPADDR", 5000)) {
        ESP_LOGI("ML307R", "4G网络连接成功");
        ml307r_state = ML307R_STATE_CONNECTED;
        return ESP_OK;
    }
    
    return ESP_FAIL;
}

// HTTP POST请求
esp_err_t ml307r_http_post(const char* url, const char* data, char* response, size_t response_size) {
    if (ml307r_state != ML307R_STATE_CONNECTED) {
        return ESP_ERR_INVALID_STATE;
    }
    
    // 配置HTTP参数
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "AT+HTTPSET=\"URL\",\"%s\"", url);
    if (!ml307r_send_command(cmd, "OK", 3000)) {
        return ESP_FAIL;
    }
    
    ml307r_send_command("AT+HTTPSET=\"CONTENT\",\"application/json\"", "OK", 3000);
    
    // 设置POST数据
    snprintf(cmd, sizeof(cmd), "AT+HTTPDATA=%d", strlen(data));
    uart_write_bytes(ML307R_UART_PORT, cmd, strlen(cmd));
    uart_write_bytes(ML307R_UART_PORT, "\r\n", 2);
    
    vTaskDelay(pdMS_TO_TICKS(100));
    
    uart_write_bytes(ML307R_UART_PORT, data, strlen(data));
    
    // 执行HTTP POST
    if (ml307r_send_command("AT+HTTPPOST", "+HTTPPOST:", 10000)) {
        // 读取响应数据
        ml307r_send_command("AT+HTTPREAD", "+HTTPREAD:", 5000);
        return ESP_OK;
    }
    
    return ESP_FAIL;
}

1.2 4G语音通话功能

// 语音通话控制
typedef struct {
    bool in_call;
    char caller_number[32];
    uint32_t call_duration;
} call_status_t;

static call_status_t call_status = {0};

// 拨打电话
esp_err_t ml307r_make_call(const char* phone_number) {
    char cmd[64];
    snprintf(cmd, sizeof(cmd), "ATD%s;", phone_number);
    
    if (ml307r_send_command(cmd, "OK", 5000)) {
        call_status.in_call = true;
        strcpy(call_status.caller_number, phone_number);
        ESP_LOGI("CALL", "呼叫 %s", phone_number);
        return ESP_OK;
    }
    
    return ESP_FAIL;
}

// 接听电话
esp_err_t ml307r_answer_call() {
    if (ml307r_send_command("ATA", "OK", 3000)) {
        call_status.in_call = true;
        ESP_LOGI("CALL", "接听来电");
        return ESP_OK;
    }
    return ESP_FAIL;
}

// 挂断电话
esp_err_t ml307r_hangup_call() {
    if (ml307r_send_command("ATH", "OK", 3000)) {
        call_status.in_call = false;
        call_status.call_duration = 0;
        ESP_LOGI("CALL", "挂断电话");
        return ESP_OK;
    }
    return ESP_FAIL;
}

// 来电检测任务
void ml307r_call_monitor_task(void* parameter) {
    char buffer[256];
    
    while(1) {
        int len = uart_read_bytes(ML307R_UART_PORT, buffer, sizeof(buffer) - 1, 
                                 pdMS_TO_TICKS(1000));
        if (len > 0) {
            buffer[len] = '\0';
            
            // 检测来电
            if (strstr(buffer, "RING")) {
                ESP_LOGI("CALL", "检测到来电");
                // 触发来电事件处理
                handle_incoming_call();
            }
            
            // 检测呼叫结束
            if (strstr(buffer, "NO CARRIER")) {
                ESP_LOGI("CALL", "通话结束");
                call_status.in_call = false;
            }
        }
    }
}

二、本地AI推理引擎

2.1 TensorFlow Lite Micro集成

内存要求: TensorFlow Lite模型推理至少需要2MB PSRAM,建议使用N16R8配置

环境配置

#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "model_data.h"  // 转换后的模型数据

#define TENSOR_ARENA_SIZE (200 * 1024)  // 200KB推理内存

class EdgeAIEngine {
private:
    tflite::MicroErrorReporter error_reporter;
    tflite::AllOpsResolver resolver;
    const tflite::Model* model;
    tflite::MicroInterpreter* interpreter;
    TfLiteTensor* input;
    TfLiteTensor* output;
    
    // 内存分配器
    uint8_t tensor_arena[TENSOR_ARENA_SIZE];
    
public:
    // 初始化AI引擎
    bool init() {
        // 加载模型
        model = tflite::GetModel(g_model_data);
        if (model->version() != TFLITE_SCHEMA_VERSION) {
            ESP_LOGE("AI", "模型版本不匹配");
            return false;
        }
        
        // 创建解释器
        interpreter = new tflite::MicroInterpreter(
            model, resolver, tensor_arena, TENSOR_ARENA_SIZE, &error_reporter);
        
        // 分配张量
        TfLiteStatus allocate_status = interpreter->AllocateTensors();
        if (allocate_status != kTfLiteOk) {
            ESP_LOGE("AI", "张量分配失败");
            return false;
        }
        
        // 获取输入输出张量
        input = interpreter->input(0);
        output = interpreter->output(0);
        
        ESP_LOGI("AI", "AI引擎初始化成功");
        ESP_LOGI("AI", "输入形状: [%d, %d, %d, %d]", 
                input->dims->data[0], input->dims->data[1], 
                input->dims->data[2], input->dims->data[3]);
        
        return true;
    }
    
    // 语音指令分类
    int classify_voice_command(const float* audio_features, size_t feature_count) {
        // 数据预处理
        for (size_t i = 0; i < feature_count; i++) {
            input->data.f[i] = audio_features[i];
        }
        
        // 推理
        uint64_t start_time = esp_timer_get_time();
        TfLiteStatus invoke_status = interpreter->Invoke();
        uint64_t inference_time = esp_timer_get_time() - start_time;
        
        if (invoke_status != kTfLiteOk) {
            ESP_LOGE("AI", "推理执行失败");
            return -1;
        }
        
        // 获取结果
        float max_score = 0;
        int predicted_class = -1;
        
        for (int i = 0; i < output->dims->data[1]; i++) {
            if (output->data.f[i] > max_score) {
                max_score = output->data.f[i];
                predicted_class = i;
            }
        }
        
        ESP_LOGI("AI", "推理完成,耗时:%lldμs,分类:%d,置信度:%.2f", 
                inference_time, predicted_class, max_score);
        
        return predicted_class;
    }
    
    // 情感识别
    float detect_emotion(const float* audio_features) {
        // 类似的推理流程
        // 返回情感值: -1.0(负面) 到 1.0(正面)
        for (size_t i = 0; i < input->bytes / sizeof(float); i++) {
            input->data.f[i] = audio_features[i];
        }
        
        interpreter->Invoke();
        return output->data.f[0];  // 假设单输出情感值
    }
};

// 全局AI引擎实例
static EdgeAIEngine ai_engine;

音频特征提取

#include <math.h>

// MFCC特征提取简化版
class AudioFeatureExtractor {
private:
    static constexpr int SAMPLE_RATE = 16000;
    static constexpr int FFT_SIZE = 512;
    static constexpr int MFCC_COEFF = 13;
    
public:
    // 提取MFCC特征
    void extract_mfcc(const int16_t* audio_data, size_t samples, float* mfcc_features) {
        // 1. 预加重
        float pre_emphasized[samples];
        pre_emphasized[0] = audio_data[0];
        for (size_t i = 1; i < samples; i++) {
            pre_emphasized[i] = audio_data[i] - 0.97 * audio_data[i-1];
        }
        
        // 2. 加窗 (汉明窗)
        float windowed[FFT_SIZE];
        for (int i = 0; i < FFT_SIZE; i++) {
            float window = 0.54 - 0.46 * cos(2 * M_PI * i / (FFT_SIZE - 1));
            windowed[i] = (i < samples) ? pre_emphasized[i] * window : 0;
        }
        
        // 3. FFT (简化实现,实际需要更高效的FFT库)
        float magnitude_spectrum[FFT_SIZE/2];
        simple_fft_magnitude(windowed, magnitude_spectrum, FFT_SIZE);
        
        // 4. Mel滤波器组
        float mel_energies[26];  // 26个Mel滤波器
        apply_mel_filters(magnitude_spectrum, mel_energies);
        
        // 5. 对数变换和DCT
        for (int i = 0; i < 26; i++) {
            mel_energies[i] = log(mel_energies[i] + 1e-10);
        }
        
        // DCT变换得到MFCC系数
        for (int i = 0; i < MFCC_COEFF; i++) {
            mfcc_features[i] = 0;
            for (int j = 0; j < 26; j++) {
                mfcc_features[i] += mel_energies[j] * cos(M_PI * i * (j + 0.5) / 26);
            }
        }
    }
    
private:
    void simple_fft_magnitude(const float* input, float* magnitude, int size) {
        // 简化的FFT实现(实际使用ESP-DSP库更高效)
        for (int k = 0; k < size/2; k++) {
            float real = 0, imag = 0;
            for (int n = 0; n < size; n++) {
                float angle = -2 * M_PI * k * n / size;
                real += input[n] * cos(angle);
                imag += input[n] * sin(angle);
            }
            magnitude[k] = sqrt(real*real + imag*imag);
        }
    }
    
    void apply_mel_filters(const float* spectrum, float* mel_energies) {
        // Mel滤波器组实现
        // 简化版本,实际需要更精确的Mel scale计算
        for (int i = 0; i < 26; i++) {
            mel_energies[i] = 0;
            int start = i * (FFT_SIZE/2) / 26;
            int end = (i + 1) * (FFT_SIZE/2) / 26;
            for (int j = start; j < end; j++) {
                mel_energies[i] += spectrum[j];
            }
        }
    }
};

2.2 智能语音指令识别

// 语音指令定义
enum VoiceCommand {
    CMD_UNKNOWN = 0,
    CMD_TURN_ON_LIGHT = 1,
    CMD_TURN_OFF_LIGHT = 2,
    CMD_INCREASE_VOLUME = 3,
    CMD_DECREASE_VOLUME = 4,
    CMD_PLAY_MUSIC = 5,
    CMD_STOP_MUSIC = 6,
    CMD_WEATHER_QUERY = 7,
    CMD_TIME_QUERY = 8,
    CMD_MAX
};

class VoiceCommandProcessor {
private:
    AudioFeatureExtractor feature_extractor;
    EdgeAIEngine* ai_engine;
    
    // 指令执行映射
    typedef void (*command_handler_t)();
    command_handler_t command_handlers[CMD_MAX];
    
public:
    VoiceCommandProcessor(EdgeAIEngine* engine) : ai_engine(engine) {
        // 注册指令处理函数
        command_handlers[CMD_TURN_ON_LIGHT] = handle_turn_on_light;
        command_handlers[CMD_TURN_OFF_LIGHT] = handle_turn_off_light;
        command_handlers[CMD_INCREASE_VOLUME] = handle_increase_volume;
        command_handlers[CMD_DECREASE_VOLUME] = handle_decrease_volume;
        command_handlers[CMD_PLAY_MUSIC] = handle_play_music;
        command_handlers[CMD_STOP_MUSIC] = handle_stop_music;
        command_handlers[CMD_WEATHER_QUERY] = handle_weather_query;
        command_handlers[CMD_TIME_QUERY] = handle_time_query;
    }
    
    // 处理语音指令
    bool process_voice_command(const int16_t* audio_data, size_t samples) {
        // 提取音频特征
        float mfcc_features[13];
        feature_extractor.extract_mfcc(audio_data, samples, mfcc_features);
        
        // AI模型推理
        int command_id = ai_engine->classify_voice_command(mfcc_features, 13);
        
        if (command_id > 0 && command_id < CMD_MAX) {
            ESP_LOGI("VOICE", "识别到指令: %d", command_id);
            
            // 执行对应处理函数
            if (command_handlers[command_id]) {
                command_handlers[command_id]();
                return true;
            }
        }
        
        ESP_LOGW("VOICE", "未识别的语音指令");
        return false;
    }
    
private:
    // 指令处理函数实现
    static void handle_turn_on_light() {
        ESP_LOGI("CMD", "执行: 开启灯光");
        // GPIO控制或发送MQTT消息到智能家居
        gpio_set_level(GPIO_NUM_2, 1);
    }
    
    static void handle_turn_off_light() {
        ESP_LOGI("CMD", "执行: 关闭灯光");
        gpio_set_level(GPIO_NUM_2, 0);
    }
    
    static void handle_increase_volume() {
        ESP_LOGI("CMD", "执行: 增加音量");
        // 调用音频系统音量控制
        audio_volume_up();
    }
    
    static void handle_decrease_volume() {
        ESP_LOGI("CMD", "执行: 减少音量");
        audio_volume_down();
    }
    
    static void handle_weather_query() {
        ESP_LOGI("CMD", "执行: 查询天气");
        // 发起天气API请求
        query_weather_api();
    }
    
    static void handle_time_query() {
        ESP_LOGI("CMD", "执行: 查询时间");
        // 获取当前时间并语音播报
        announce_current_time();
    }
};

三、多模态交互系统

3.1 视觉+语音多模态

硬件要求: ESP32-CAM模块或兼容的摄像头模组,配合小智语音系统

视觉处理集成

#include "esp_camera.h"
#include "img_converters.h"

// 摄像头配置 (ESP32-CAM)
camera_config_t camera_config = {
    .pin_pwdn = 32,
    .pin_reset = -1,
    .pin_xclk = 0,
    .pin_sscb_sda = 26,
    .pin_sscb_scl = 27,
    .pin_d7 = 35,
    .pin_d6 = 34,
    .pin_d5 = 39,
    .pin_d4 = 36,
    .pin_d3 = 21,
    .pin_d2 = 19,
    .pin_d1 = 18,
    .pin_d0 = 5,
    .pin_vsync = 25,
    .pin_href = 23,
    .pin_pclk = 22,
    .xclk_freq_hz = 20000000,
    .ledc_timer = LEDC_TIMER_0,
    .ledc_channel = LEDC_CHANNEL_0,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_VGA,  // 640x480
    .jpeg_quality = 10,
    .fb_count = 1
};

class MultiModalProcessor {
private:
    VoiceCommandProcessor* voice_processor;
    bool camera_initialized;
    
public:
    MultiModalProcessor(VoiceCommandProcessor* vp) : voice_processor(vp) {
        camera_initialized = false;
    }
    
    // 初始化摄像头
    bool init_camera() {
        esp_err_t err = esp_camera_init(&camera_config);
        if (err != ESP_OK) {
            ESP_LOGE("CAMERA", "摄像头初始化失败: %s", esp_err_to_name(err));
            return false;
        }
        
        camera_initialized = true;
        ESP_LOGI("CAMERA", "摄像头初始化成功");
        return true;
    }
    
    // 拍照并进行物体识别
    char* capture_and_recognize() {
        if (!camera_initialized) {
            return NULL;
        }
        
        // 拍摄照片
        camera_fb_t* fb = esp_camera_fb_get();
        if (!fb) {
            ESP_LOGE("CAMERA", "拍照失败");
            return NULL;
        }
        
        ESP_LOGI("CAMERA", "拍照成功: %dx%d, 大小: %d bytes", 
                fb->width, fb->height, fb->len);
        
        // 图像识别 (简化版本)
        char* recognition_result = simple_object_recognition(fb->buf, fb->len);
        
        esp_camera_fb_return(fb);
        
        return recognition_result;
    }
    
    // 多模态交互处理
    void process_multimodal_command(const char* voice_text) {
        if (strstr(voice_text, "看看") || strstr(voice_text, "拍照") || strstr(voice_text, "识别")) {
            ESP_LOGI("MULTIMODAL", "触发视觉识别");
            
            char* result = capture_and_recognize();
            if (result) {
                // 将识别结果转换为语音播报
                char response[256];
                snprintf(response, sizeof(response), "我看到了%s", result);
                text_to_speech_and_play(response);
                
                free(result);
            } else {
                text_to_speech_and_play("抱歉,我没有看清楚");
            }
        }
        else if (strstr(voice_text, "拍张照片")) {
            // 仅拍照存储
            camera_fb_t* fb = esp_camera_fb_get();
            if (fb) {
                save_photo_to_sd(fb->buf, fb->len);
                text_to_speech_and_play("照片已保存");
                esp_camera_fb_return(fb);
            }
        }
    }
    
private:
    // 简单物体识别 (可接入云端视觉API)
    char* simple_object_recognition(uint8_t* image_data, size_t size) {
        // 这里可以集成:
        // 1. 本地TensorFlow Lite图像分类模型
        // 2. 云端AI视觉API (百度、阿里云、腾讯云)
        // 3. 简单的颜色/形状检测算法
        
        // 示例:发送到云端API
        return call_cloud_vision_api(image_data, size);
    }
    
    char* call_cloud_vision_api(uint8_t* image_data, size_t size) {
        // Base64编码图像
        char* base64_image = base64_encode(image_data, size);
        
        // 构造JSON请求
        char json_request[4096];
        snprintf(json_request, sizeof(json_request),
                "{\"image\":\"%s\",\"features\":[\"object_detection\"]}", 
                base64_image);
        
        // HTTP POST到视觉API
        char response[1024];
        if (http_post_json("https://vision-api.example.com/detect", 
                          json_request, response, sizeof(response)) == ESP_OK) {
            
            // 解析JSON响应,提取识别结果
            char* result = parse_vision_result(response);
            free(base64_image);
            return result;
        }
        
        free(base64_image);
        return NULL;
    }
};

3.2 手势识别集成

#include "driver/adc.h"

// 简单手势传感器接口
class GestureRecognizer {
private:
    adc_channel_t gesture_channel;
    
public:
    typedef enum {
        GESTURE_NONE,
        GESTURE_SWIPE_LEFT,
        GESTURE_SWIPE_RIGHT, 
        GESTURE_SWIPE_UP,
        GESTURE_SWIPE_DOWN,
        GESTURE_TAP
    } gesture_t;
    
    GestureRecognizer(adc_channel_t channel) : gesture_channel(channel) {
        // 配置ADC
        adc1_config_width(ADC_WIDTH_BIT_12);
        adc1_config_channel_atten(gesture_channel, ADC_ATTEN_DB_11);
    }
    
    // 检测手势
    gesture_t detect_gesture() {
        static int baseline = -1;
        static uint32_t last_change = 0;
        static int change_count = 0;
        
        int current_value = adc1_get_raw(gesture_channel);
        uint32_t now = esp_timer_get_time() / 1000;  // ms
        
        // 建立基线
        if (baseline == -1) {
            baseline = current_value;
            return GESTURE_NONE;
        }
        
        // 检测变化
        int diff = abs(current_value - baseline);
        if (diff > 200) {  // 阈值
            if (now - last_change > 100) {  // 去抖动
                change_count++;
                last_change = now;
                
                if (change_count >= 3) {
                    change_count = 0;
                    
                    // 简单的方向判断
                    if (current_value > baseline) {
                        return GESTURE_SWIPE_UP;
                    } else {
                        return GESTURE_SWIPE_DOWN;
                    }
                }
            }
        } else {
            // 重置
            if (now - last_change > 500) {
                change_count = 0;
                baseline = current_value;
            }
        }
        
        return GESTURE_NONE;
    }
    
    // 手势指令映射
    void handle_gesture_command(gesture_t gesture) {
        switch (gesture) {
            case GESTURE_SWIPE_UP:
                ESP_LOGI("GESTURE", "手势: 向上滑动 - 增加音量");
                audio_volume_up();
                break;
                
            case GESTURE_SWIPE_DOWN:
                ESP_LOGI("GESTURE", "手势: 向下滑动 - 减少音量");
                audio_volume_down();
                break;
                
            case GESTURE_SWIPE_LEFT:
                ESP_LOGI("GESTURE", "手势: 向左滑动 - 上一首");
                play_previous_track();
                break;
                
            case GESTURE_SWIPE_RIGHT:
                ESP_LOGI("GESTURE", "手势: 向右滑动 - 下一首");
                play_next_track();
                break;
                
            case GESTURE_TAP:
                ESP_LOGI("GESTURE", "手势: 点击 - 播放/暂停");
                toggle_playback();
                break;
                
            default:
                break;
        }
    }
};

四、IoT设备控制

4.1 MQTT智能家居集成

#include "mqtt_client.h"

class SmartHomeController {
private:
    esp_mqtt_client_handle_t mqtt_client;
    bool mqtt_connected;
    
    // 设备状态
    typedef struct {
        bool light_on;
        uint8_t brightness;
        uint8_t temperature;
        bool fan_on;
        uint8_t fan_speed;
    } home_status_t;
    
    home_status_t home_status;
    
public:
    SmartHomeController() : mqtt_connected(false) {
        memset(&home_status, 0, sizeof(home_status));
    }
    
    // MQTT事件处理
    static void mqtt_event_handler(void *handler_args, esp_event_base_t base, 
                                  int32_t event_id, void *event_data) {
        SmartHomeController* controller = (SmartHomeController*)handler_args;
        esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
        
        switch (event->event_id) {
            case MQTT_EVENT_CONNECTED:
                ESP_LOGI("MQTT", "连接成功");
                controller->mqtt_connected = true;
                
                // 订阅设备状态主题
                esp_mqtt_client_subscribe(event->client, "home/+/status", 1);
                esp_mqtt_client_subscribe(event->client, "home/xiaozhi/command", 1);
                break;
                
            case MQTT_EVENT_DATA:
                controller->handle_mqtt_message(event->topic, event->topic_len,
                                              event->data, event->data_len);
                break;
                
            case MQTT_EVENT_DISCONNECTED:
                ESP_LOGI("MQTT", "断开连接");
                controller->mqtt_connected = false;
                break;
                
            default:
                break;
        }
    }
    
    // 初始化MQTT连接
    bool init_mqtt(const char* broker_uri) {
        esp_mqtt_client_config_t mqtt_cfg = {
            .broker.address.uri = broker_uri,
            .session.keepalive = 60,
            .session.disable_clean_session = 0,
            .credentials.client_id = "xiaozhi_esp32",
            .credentials.username = "xiaozhi",
            .credentials.authentication.password = "xiaozhi123",
        };
        
        mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
        if (mqtt_client == NULL) {
            ESP_LOGE("MQTT", "客户端初始化失败");
            return false;
        }
        
        esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, 
                                      mqtt_event_handler, this);
        
        esp_err_t err = esp_mqtt_client_start(mqtt_client);
        if (err != ESP_OK) {
            ESP_LOGE("MQTT", "客户端启动失败: %s", esp_err_to_name(err));
            return false;
        }
        
        return true;
    }
    
    // 控制智能灯
    void control_light(bool on, uint8_t brightness = 100) {
        if (!mqtt_connected) return;
        
        char payload[128];
        snprintf(payload, sizeof(payload), 
                "{\"state\":\"%s\",\"brightness\":%d}", 
                on ? "ON" : "OFF", brightness);
        
        esp_mqtt_client_publish(mqtt_client, "home/light/command", 
                               payload, 0, 1, 0);
        
        home_status.light_on = on;
        home_status.brightness = brightness;
        
        ESP_LOGI("SMART_HOME", "灯光控制: %s, 亮度: %d%%", 
                on ? "开启" : "关闭", brightness);
    }
    
    // 控制空调
    void control_airconditioner(uint8_t temperature, bool on = true) {
        if (!mqtt_connected) return;
        
        char payload[128];
        snprintf(payload, sizeof(payload),
                "{\"state\":\"%s\",\"temperature\":%d,\"mode\":\"cool\"}", 
                on ? "ON" : "OFF", temperature);
        
        esp_mqtt_client_publish(mqtt_client, "home/airconditioner/command", 
                               payload, 0, 1, 0);
        
        home_status.temperature = temperature;
        
        ESP_LOGI("SMART_HOME", "空调控制: %s, 温度: %d°C", 
                on ? "开启" : "关闭", temperature);
    }
    
    // 语音指令解析和执行
    void execute_voice_command(const char* command) {
        if (strstr(command, "开灯") || strstr(command, "打开灯")) {
            control_light(true);
            text_to_speech_and_play("灯已打开");
        }
        else if (strstr(command, "关灯") || strstr(command, "关闭灯")) {
            control_light(false);
            text_to_speech_and_play("灯已关闭");
        }
        else if (strstr(command, "调亮") || strstr(command, "亮一点")) {
            uint8_t new_brightness = min(100, home_status.brightness + 20);
            control_light(true, new_brightness);
            text_to_speech_and_play("亮度已调高");
        }
        else if (strstr(command, "调暗") || strstr(command, "暗一点")) {
            uint8_t new_brightness = max(10, home_status.brightness - 20);
            control_light(true, new_brightness);
            text_to_speech_and_play("亮度已调低");
        }
        else if (strstr(command, "开空调")) {
            control_airconditioner(26);
            text_to_speech_and_play("空调已开启,温度26度");
        }
        else if (strstr(command, "关空调")) {
            control_airconditioner(26, false);
            text_to_speech_and_play("空调已关闭");
        }
        else if (strstr(command, "温度") && strstr(command, "度")) {
            // 解析温度数字
            int temp = extract_temperature_from_text(command);
            if (temp >= 16 && temp <= 30) {
                control_airconditioner(temp);
                char response[64];
                snprintf(response, sizeof(response), "温度已设置为%d度", temp);
                text_to_speech_and_play(response);
            }
        }
    }
    
private:
    // 处理MQTT消息
    void handle_mqtt_message(const char* topic, int topic_len, 
                            const char* data, int data_len) {
        char topic_str[64], data_str[256];
        
        strncpy(topic_str, topic, min(topic_len, sizeof(topic_str)-1));
        topic_str[min(topic_len, sizeof(topic_str)-1)] = '\0';
        
        strncpy(data_str, data, min(data_len, sizeof(data_str)-1));
        data_str[min(data_len, sizeof(data_str)-1)] = '\0';
        
        ESP_LOGI("MQTT", "收到消息 - 主题: %s, 数据: %s", topic_str, data_str);
        
        // 解析设备状态更新
        if (strstr(topic_str, "/status")) {
            parse_device_status(topic_str, data_str);
        }
        // 处理远程指令
        else if (strstr(topic_str, "xiaozhi/command")) {
            execute_voice_command(data_str);
        }
    }
    
    // 解析设备状态
    void parse_device_status(const char* topic, const char* data) {
        // 简化的JSON解析
        if (strstr(topic, "light")) {
            if (strstr(data, "\"state\":\"ON\"")) {
                home_status.light_on = true;
            } else if (strstr(data, "\"state\":\"OFF\"")) {
                home_status.light_on = false;
            }
        }
        
        // 更新显示状态
        update_home_status_display();
    }
    
    // 从文本中提取温度数字
    int extract_temperature_from_text(const char* text) {
        // 简单的数字提取
        for (int i = 0; text[i]; i++) {
            if (isdigit(text[i])) {
                int temp = atoi(&text[i]);
                if (temp >= 16 && temp <= 30) {
                    return temp;
                }
            }
        }
        return -1;
    }
};

4.2 传感器数据融合

#include "driver/adc.h"
#include "driver/i2c.h"

// 环境传感器管理
class EnvironmentSensorManager {
private:
    typedef struct {
        float temperature;
        float humidity;
        uint16_t light_level;
        uint16_t air_quality;
        bool motion_detected;
        uint32_t last_update;
    } sensor_data_t;
    
    sensor_data_t sensor_data;
    
public:
    EnvironmentSensorManager() {
        memset(&sensor_data, 0, sizeof(sensor_data));
    }
    
    // 初始化传感器
    void init_sensors() {
        // ADC for light sensor
        adc1_config_width(ADC_WIDTH_BIT_12);
        adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);
        
        // I2C for temperature/humidity sensor (如DHT22, SHT30等)
        i2c_master_init();
        
        ESP_LOGI("SENSORS", "传感器初始化完成");
    }
    
    // 读取所有传感器数据
    void read_all_sensors() {
        uint32_t now = esp_timer_get_time() / 1000;
        
        // 读取光照传感器 (ADC)
        int light_raw = adc1_get_raw(ADC1_CHANNEL_0);
        sensor_data.light_level = map_light_level(light_raw);
        
        // 读取温湿度传感器 (I2C)
        read_temperature_humidity(&sensor_data.temperature, &sensor_data.humidity);
        
        // 读取空气质量传感器
        sensor_data.air_quality = read_air_quality();
        
        // 读取运动传感器
        sensor_data.motion_detected = gpio_get_level(GPIO_NUM_14);
        
        sensor_data.last_update = now;
        
        ESP_LOGI("SENSORS", "环境数据 - 温度:%.1f°C, 湿度:%.1f%%, 光照:%d, 空气质量:%d", 
                sensor_data.temperature, sensor_data.humidity, 
                sensor_data.light_level, sensor_data.air_quality);
    }
    
    // 智能环境控制
    void intelligent_environment_control() {
        read_all_sensors();
        
        // 基于传感器数据的智能决策
        if (sensor_data.temperature > 28.0) {
            ESP_LOGI("AUTO", "温度过高,建议开启空调");
            // 自动开启空调或发送建议
            send_smart_suggestion("temperature_high", sensor_data.temperature);
        }
        
        if (sensor_data.light_level < 100 && sensor_data.motion_detected) {
            ESP_LOGI("AUTO", "检测到运动且光线不足,自动开灯");
            // 自动开启灯光
            control_light_automatically();
        }
        
        if (sensor_data.air_quality > 150) {
            ESP_LOGI("AUTO", "空气质量较差,建议开启净化器");
            send_smart_suggestion("air_quality_poor", sensor_data.air_quality);
        }
        
        // 数据上报到云端
        upload_sensor_data_to_cloud();
    }
    
    // 语音播报环境状态
    void announce_environment_status() {
        char announcement[256];
        snprintf(announcement, sizeof(announcement),
                "当前室内温度%.1f度,湿度%.1f%%,空气质量%s",
                sensor_data.temperature, sensor_data.humidity,
                (sensor_data.air_quality < 50) ? "优秀" : 
                (sensor_data.air_quality < 100) ? "良好" : "一般");
        
        text_to_speech_and_play(announcement);
    }
    
private:
    uint16_t map_light_level(int adc_raw) {
        // 将ADC原始值映射到0-1000的光照级别
        return (adc_raw * 1000) / 4095;
    }
    
    void read_temperature_humidity(float* temp, float* humidity) {
        // I2C读取温湿度传感器数据
        // 这里使用模拟数据,实际需要根据具体传感器实现
        static float sim_temp = 25.0;
        static float sim_humidity = 60.0;
        
        sim_temp += (rand() % 20 - 10) * 0.1;  // ±1度随机变化
        sim_humidity += (rand() % 20 - 10) * 0.5;  // ±5%随机变化
        
        *temp = sim_temp;
        *humidity = sim_humidity;
    }
    
    uint16_t read_air_quality() {
        // 空气质量传感器读取
        return 50 + (rand() % 100);  // 模拟50-150的空气质量指数
    }
    
    void send_smart_suggestion(const char* type, float value) {
        char message[128];
        snprintf(message, sizeof(message), 
                "{\"type\":\"%s\",\"value\":%.1f,\"timestamp\":%d}",
                type, value, (int)(esp_timer_get_time() / 1000000));
        
        // 发送到智能家居系统
        if (mqtt_client) {
            esp_mqtt_client_publish(mqtt_client, "home/xiaozhi/suggestion", 
                                   message, 0, 1, 0);
        }
    }
};

五、云服务集成

5.1 AI语音服务对接

#include "cJSON.h"

class CloudAIService {
private:
    char api_key[64];
    char base_url[128];
    
public:
    CloudAIService(const char* key, const char* url) {
        strcpy(api_key, key);
        strcpy(base_url, url);
    }
    
    // 语音转文字 (ASR)
    char* speech_to_text(const uint8_t* audio_data, size_t audio_size) {
        // Base64编码音频数据
        char* base64_audio = base64_encode(audio_data, audio_size);
        
        // 构造请求JSON
        cJSON *json = cJSON_CreateObject();
        cJSON *format = cJSON_CreateString("wav");
        cJSON *rate = cJSON_CreateNumber(16000);
        cJSON *channel = cJSON_CreateNumber(1);
        cJSON *speech = cJSON_CreateString(base64_audio);
        
        cJSON_AddItemToObject(json, "format", format);
        cJSON_AddItemToObject(json, "rate", rate);
        cJSON_AddItemToObject(json, "channel", channel);
        cJSON_AddItemToObject(json, "speech", speech);
        
        char* json_string = cJSON_Print(json);
        
        // HTTP POST请求
        char response[1024];
        char full_url[256];
        snprintf(full_url, sizeof(full_url), "%s/speech/v1/asr", base_url);
        
        esp_err_t ret = http_post_with_auth(full_url, api_key, json_string, 
                                           response, sizeof(response));
        
        // 清理内存
        free(base64_audio);
        free(json_string);
        cJSON_Delete(json);
        
        if (ret == ESP_OK) {
            return parse_asr_response(response);
        }
        
        return NULL;
    }
    
    // 文字转语音 (TTS)
    uint8_t* text_to_speech(const char* text, size_t* audio_size) {
        // 构造TTS请求
        cJSON *json = cJSON_CreateObject();
        cJSON *text_item = cJSON_CreateString(text);
        cJSON *voice = cJSON_CreateString("zh-CN-XiaoxiaoNeural");
        cJSON *speed = cJSON_CreateNumber(1.0);
        cJSON *format = cJSON_CreateString("wav");
        
        cJSON_AddItemToObject(json, "text", text_item);
        cJSON_AddItemToObject(json, "voice", voice);
        cJSON_AddItemToObject(json, "speed", speed);
        cJSON_AddItemToObject(json, "format", format);
        
        char* json_string = cJSON_Print(json);
        
        // HTTP POST请求
        char response[4096];
        char full_url[256];
        snprintf(full_url, sizeof(full_url), "%s/speech/v1/tts", base_url);
        
        esp_err_t ret = http_post_with_auth(full_url, api_key, json_string, 
                                           response, sizeof(response));
        
        cJSON_Delete(json);
        free(json_string);
        
        if (ret == ESP_OK) {
            return parse_tts_response(response, audio_size);
        }
        
        return NULL;
    }
    
    // 大模型对话
    char* chat_with_llm(const char* message, const char* system_prompt = NULL) {
        cJSON *json = cJSON_CreateObject();
        cJSON *messages = cJSON_CreateArray();
        
        // 系统提示词
        if (system_prompt) {
            cJSON *system_msg = cJSON_CreateObject();
            cJSON_AddStringToObject(system_msg, "role", "system");
            cJSON_AddStringToObject(system_msg, "content", system_prompt);
            cJSON_AddItemToArray(messages, system_msg);
        }
        
        // 用户消息
        cJSON *user_msg = cJSON_CreateObject();
        cJSON_AddStringToObject(user_msg, "role", "user");
        cJSON_AddStringToObject(user_msg, "content", message);
        cJSON_AddItemToArray(messages, user_msg);
        
        cJSON_AddItemToObject(json, "messages", messages);
        cJSON_AddStringToObject(json, "model", "deepseek-chat");
        cJSON_AddNumberToObject(json, "max_tokens", 500);
        cJSON_AddNumberToObject(json, "temperature", 0.7);
        
        char* json_string = cJSON_Print(json);
        
        // HTTP POST请求
        char response[2048];
        char full_url[256];
        snprintf(full_url, sizeof(full_url), "%s/chat/completions", base_url);
        
        esp_err_t ret = http_post_with_auth(full_url, api_key, json_string, 
                                           response, sizeof(response));
        
        cJSON_Delete(json);
        free(json_string);
        
        if (ret == ESP_OK) {
            return parse_chat_response(response);
        }
        
        return NULL;
    }
    
private:
    esp_err_t http_post_with_auth(const char* url, const char* api_key, 
                                 const char* data, char* response, size_t response_size) {
        esp_http_client_config_t config = {
            .url = url,
            .method = HTTP_METHOD_POST,
        };
        
        esp_http_client_handle_t client = esp_http_client_init(&config);
        
        // 设置请求头
        esp_http_client_set_header(client, "Content-Type", "application/json");
        
        char auth_header[128];
        snprintf(auth_header, sizeof(auth_header), "Bearer %s", api_key);
        esp_http_client_set_header(client, "Authorization", auth_header);
        
        esp_http_client_set_post_field(client, data, strlen(data));
        
        esp_err_t err = esp_http_client_perform(client);
        
        if (err == ESP_OK) {
            int data_read = esp_http_client_read_response(client, response, response_size - 1);
            response[data_read] = '\0';
        }
        
        esp_http_client_cleanup(client);
        return err;
    }
    
    char* parse_asr_response(const char* response) {
        cJSON *json = cJSON_Parse(response);
        if (!json) return NULL;
        
        cJSON *result = cJSON_GetObjectItem(json, "result");
        if (!result) {
            cJSON_Delete(json);
            return NULL;
        }
        
        char* text = strdup(result->valuestring);
        cJSON_Delete(json);
        return text;
    }
    
    char* parse_chat_response(const char* response) {
        cJSON *json = cJSON_Parse(response);
        if (!json) return NULL;
        
        cJSON *choices = cJSON_GetObjectItem(json, "choices");
        if (!choices || !cJSON_IsArray(choices)) {
            cJSON_Delete(json);
            return NULL;
        }
        
        cJSON *first_choice = cJSON_GetArrayItem(choices, 0);
        if (!first_choice) {
            cJSON_Delete(json);
            return NULL;
        }
        
        cJSON *message = cJSON_GetObjectItem(first_choice, "message");
        cJSON *content = cJSON_GetObjectItem(message, "content");
        
        char* reply = strdup(content->valuestring);
        cJSON_Delete(json);
        return reply;
    }
};

学习路径推荐: