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;
}
};
学习路径推荐:
- 🔧 ESP32技术规格详解 - 深入了解硬件能力
- 💻 ESP32编程开发指南 - 基础编程技能
- 🎯 AI功能集成文档 - AI能力开发
- ⚠️ 常见问题解答 - 问题排查指南