ESP32-S3对接豆包制作AI桌面数字收音机,桌面闹钟,桌面新闻播报器

ESP32-S3对接豆包制作AI桌面数字收音机,桌面闹钟,桌面新闻播报器

基于ESP32-S3开发板,对接豆包的AI能力,制作一款集数字收音机、桌面闹钟、新闻播报功能于一体的AI桌面设备,核心是实现ESP32-S3与豆包的网络交互,借助豆包的AI能力完成新闻获取、语音合成等,同时通过硬件模块实现时间显示、音频播放等功能。

一、整体实现思路

  1. 硬件层:ESP32-S3作为主控,负责WiFi联网、控制显示模块(展示时间/状态)、音频模块(播放声音)、RTC模块(精准计时);
  2. 软件层 :ESP32-S3通过WiFi调用豆包开放平台API,获取AI能力(新闻摘要、语音合成),同时对接网络电台API实现收音机功能,基于RTC实现闹钟定时触发。

二、硬件准备(核心组件)

组件 作用
ESP32-S3开发板 主控,联网+硬件控制
DS3231 RTC模块 高精度计时(闹钟核心)
SSD1306 OLED屏 显示时间/电台/新闻标题
VS1053音频解码模块 解码播放音频(收音机/播报)
MAX9814麦克风(可选) 语音唤醒/语音输入
5V喇叭/功放 输出声音
5V 1A电源模块 稳定供电

三、软件环境准备

  1. 安装Arduino IDE,在「文件→首选项」添加ESP32开发板地址:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  2. 在「工具→开发板→开发板管理器」安装「esp32」(版本≥2.0.0),选择对应ESP32-S3开发板;
  3. 安装依赖库:
    • Adafruit SSD1306(OLED显示)
    • RTClib(RTC时钟)
    • VS1053(音频解码)
    • ArduinoJson(JSON解析)
    • WiFiHTTPClient(网络请求,内置)

四、豆包API准备

  1. 前往「豆包开放平台」注册账号,创建应用,获取API KeySecret Key
  2. 可调用的核心接口:
    • 文本生成接口:获取新闻摘要、天气等信息;
    • 语音合成接口:将文本转为语音音频流(需参考平台最新接口文档)。

五、核心代码实现(完整可运行)

cpp 复制代码
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <VS1053.h>

// ====================== 配置参数(需替换为自己的) ======================
// WiFi配置
const char* WIFI_SSID = "你的WiFi名称";
const char* WIFI_PWD = "你的WiFi密码";

// 豆包API配置(替换为豆包开放平台获取的密钥)
const char* DOUBAO_API_KEY = "你的豆包API Key";
const char* DOUBAO_TEXT_API = "https://open.doubao.com/api/v1/chat/completions"; // 文本生成接口

// RTC模块
RTC_DS3231 rtc;

// OLED显示配置(I2C)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// VS1053音频模块配置(SPI)
#define VS1053_CS      5
#define VS1053_DCS     6
#define VS1053_DREQ    7
VS1053 player(VS1053_CS, VS1053_DCS, VS1053_DREQ);

// 闹钟配置
int alarmHour = 8;   // 闹钟小时
int alarmMinute = 0; // 闹钟分钟
bool alarmTriggered = false;

// 网络电台URL(替换为真实的MP3流地址)
const char* RADIO_URL = "http://tingtingfm.com/radio/1008.mp3";

// ====================== 函数声明 ======================
void connectWiFi();
String getNewsFromDouBao();
void playAudio(String audioUrl);
void checkAlarm();
void displayTime(DateTime now);

void setup() {
  Serial.begin(115200);
  
  // 初始化I2C(OLED/RTC共用)
  Wire.begin(21, 22); // SDA=21, SCL=22(可按实际接线调整)
  
  // 初始化OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("OLED初始化失败"));
    while(1);
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  
  // 初始化RTC
  if (!rtc.begin()) {
    Serial.println(F("RTC初始化失败"));
    display.setCursor(0, 0);
    display.print("RTC Error!");
    display.display();
    while(1);
  }
  // 首次使用设置时间(仅第一次运行时取消注释)
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  
  // 初始化音频模块
  SPI.begin(18, 19, 23); // SCK=18, MISO=19, MOSI=23
  if (!player.begin()) {
    Serial.println(F("音频模块初始化失败"));
    display.setCursor(0, 10);
    display.print("Audio Error!");
    display.display();
    while(1);
  }
  player.switchToMP3Mode(); // 切换到MP3播放模式
  
  // 连接WiFi
  connectWiFi();
  
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("WiFi Connected!");
  display.display();
  delay(2000);
}

void loop() {
  // 获取当前时间
  DateTime now = rtc.now();
  
  // 实时显示时间
  displayTime(now);
  
  // 检查闹钟是否触发
  checkAlarm();
  
  // 示例:每小时整点播报新闻(可自定义频率)
  if(now.minute() == 0 && now.second() == 0) {
    String news = getNewsFromDouBao();
    // 显示新闻开头(OLED显示字数有限)
    display.setCursor(0, 30);
    display.print("News: ");
    display.print(news.length() > 15 ? news.substring(0, 15) + "..." : news);
    display.display();
    
    // 【扩展】调用豆包语音合成接口,将新闻转为音频并播放
    // String audioUrl = getAudioFromDouBao(news); // 需实现语音合成逻辑
    // playAudio(audioUrl);
  }
  
  delay(1000);
}

// 连接WiFi
void connectWiFi() {
  display.setCursor(0, 0);
  display.print("Connecting WiFi...");
  display.display();
  
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected! IP: " + WiFi.localIP().toString());
}

// 从豆包API获取新闻摘要
String getNewsFromDouBao() {
  // 先检查WiFi连接
  if(WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }
  
  HTTPClient http;
  http.begin(DOUBAO_TEXT_API);
  // 设置请求头(参考豆包开放平台文档)
  http.addHeader("Content-Type", "application/json");
  http.addHeader("Authorization", "Bearer " + String(DOUBAO_API_KEY));
  
  // 构建请求体:要求返回简短的当日热点新闻
  String requestBody = "{\"model\":\"doubao-pro\",\"messages\":[{\"role\":\"user\",\"content\":\"请返回今日热点新闻摘要,100字以内,简洁易懂\"}],\"max_tokens\":100}";
  
  int httpCode = http.POST(requestBody);
  String news = "No news"; // 默认值
  
  if(httpCode > 0) {
    if(httpCode == HTTP_CODE_OK) {
      String response = http.getString();
      Serial.println("豆包API返回:" + response);
      
      // 解析JSON获取新闻内容(需匹配豆包API实际返回格式)
      DynamicJsonDocument doc(1024);
      DeserializationError error = deserializeJson(doc, response);
      if(!error) {
        news = doc["choices"][0]["message"]["content"].as<String>();
      }
    }
  } else {
    Serial.println("API请求失败,错误码:" + String(httpCode));
  }
  
  http.end();
  return news;
}

// 播放网络音频流(收音机/语音播报)
void playAudio(String audioUrl) {
  // 启动音频流播放(需根据VS1053库完善)
  player.startPlayingStream(audioUrl);
  while(player.playingMusic) {
    // 播放中更新OLED状态
    display.setCursor(0, 20);
    display.print("Playing...");
    display.display();
    delay(100);
  }
}

// 检查闹钟是否触发
void checkAlarm() {
  DateTime now = rtc.now();
  // 匹配闹钟时间且未触发过
  if(now.hour() == alarmHour && now.minute() == alarmMinute && !alarmTriggered) {
    Serial.println("闹钟触发!");
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Alarm!");
    display.display();
    
    // 播放闹钟提示音(可替换为豆包合成的语音)
    playAudio("http://example.com/alarm.mp3");
    alarmTriggered = true;
  }
  
  // 分钟变化后重置触发状态
  if(now.minute() != alarmMinute) {
    alarmTriggered = false;
  }
}

// 格式化显示时间/日期
void displayTime(DateTime now) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0, 0);
  
  // 格式化时间:HH:MM:SS(补零)
  String hour = now.hour() < 10 ? "0" + String(now.hour()) : String(now.hour());
  String minute = now.minute() < 10 ? "0" + String(now.minute()) : String(now.minute());
  String second = now.second() < 10 ? "0" + String(now.second()) : String(now.second());
  String timeStr = hour + ":" + minute + ":" + second;
  display.print(timeStr);
  
  // 显示日期
  display.setTextSize(1);
  display.setCursor(0, 25);
  String dateStr = String(now.year()) + "-" + 
                   (now.month() < 10 ? "0" + String(now.month()) : String(now.month())) + "-" + 
                   (now.day() < 10 ? "0" + String(now.day()) : String(now.day()));
  display.print(dateStr);
  
  display.display();
}

六、关键代码解释

  1. WiFi连接connectWiFi() 确保ESP32-S3联网,是调用豆包API的前提;
  2. 豆包API调用getNewsFromDouBao() 通过HTTPClient向豆包开放平台发送POST请求,获取新闻摘要,需替换为自己的API Key并匹配最新接口格式;
  3. 闹钟逻辑checkAlarm() 对比RTC时间和设定闹钟时间,触发时播放提示音,避免重复触发;
  4. 音频播放playAudio() 基于VS1053库播放网络音频流(收音机/语音),需替换真实的音频URL;
  5. OLED显示displayTime() 格式化显示时间/日期,同时可展示新闻、播放状态等。

七、补充说明

  1. 豆包API适配:需参考豆包开放平台最新文档调整请求头、请求体格式,语音合成功能需单独调用对应接口;
  2. 硬件接线
    • OLED/DS3231共用I2C总线,VS1053使用SPI总线,需按代码中引脚定义接线,或自行修改引脚;
    • 音频模块需接喇叭/功放,确保声音输出;
  3. 网络电台URL:需替换为可访问的、支持MP3流的免费网络电台地址(可自行搜索)。

总结

  1. 该设备核心是ESP32-S3通过WiFi调用豆包开放平台API获取AI能力,同时控制硬件完成时间显示、音频播放;
  2. 硬件需搭配DS3231(高精度计时)、VS1053(音频解码)、OLED(显示),确保闹钟、收音机、播报功能落地;
  3. 关键步骤是申请豆包API Key、配置网络请求参数、适配硬件接线,补充语音合成接口调用逻辑即可完成完整功能。
相关推荐
主机哥哥2 小时前
阿里云OpenClaw极简部署教程,打造专属AI助手!
人工智能·阿里云·云计算
AI营销快线2 小时前
决胜2026:原圈科技AI CRM系统如何领跑汽车销服一体化变革?
人工智能
qwy7152292581632 小时前
13-图像的透视
人工智能·opencv·计算机视觉
光羽隹衡2 小时前
计算机视觉——Opencv(图像直方图与掩膜)
人工智能·opencv·计算机视觉
KG_LLM图谱增强大模型2 小时前
a16z 最新AI市场状态报告:独角兽崛起与科技超级周期
人工智能
xixixi777772 小时前
Prompt脱敏——不损失(或尽量少损失)原文本语义和上下文价值的前提下,防止原始敏感数据暴露给模型服务方、潜在的攻击者或出现在模型训练数据中
人工智能·microsoft·ai·大模型·数据安全·提示词·敏感信息
凡泰极客科技2 小时前
新浪财经专访凡泰极客梁启鸿:金融App的AI落地应避哪些坑
人工智能·金融
量子-Alex2 小时前
【大模型技术报告】Qwen2-VL技术报告解读
人工智能
得赢科技2 小时前
2026年料汁定制公司深度评测报告
人工智能