Слухати інтернет-радіо через телефон або комп’ютер не завжди зручно: пристрій має бути поряд, Bluetooth — підключений, а батарея — не розряджена. Якщо хочеться просто ввімкнути музику на кухні, в майстерні чи дитячій — логічніше зробити окремий пристрій, який працює сам по собі.
У цьому проєкті ви зберете компактне інтернет-радіо на базі ESP32-C3. Воно автоматично підключається до Wi-Fi, запускає потік і керується лише двома кнопками. Без застосунків, без сполучення і без зайвих дій — увімкнув живлення і слухаєш.
Наприкінці статті ви знайдете готовий код і 3D-модель корпусу.
Що вийде в результаті
- Робоче інтернет-радіо з Wi-Fi підключенням
- Відтворення MP3-потоку через I2S-підсилювач
- Керування гучністю кнопками
- Автоматичне перепідключення при обриві потоку
- Готовий корпус для 3D-друку
Використовувані компоненти
- ESP32-C3 Mini — мікроконтролер
- MAX98357A — I2S-підсилювач із вбудованим ЦАП
- Динамік 3 Вт (рекомендується 4Ω)
- Кнопки tact switch ×2
- Дроти DuPont
- 3D-друкований корпус
Як це працює
- ESP32 підключається до Wi-Fi мережі (у коді вкажіть налаштування вашого Wi-Fi)
- Отримує потік інтернет-радіо у форматі MP3 (замініть url радіостанції на свій)
- Далі аудіо декодується і передається по інтерфейсу I2S на підсилювач
- MAX98357A підсилює сигнал і виводить звук на динамік
- Вся логіка працює автономно — без зовнішніх пристроїв
Схема підключення MAX98357A
Підключення по I2S:
- BCLK → GPIO 5
- LRC → GPIO 3
- DIN → GPIO 7
- VIN → 5V
- GND → GND
Поради зі збирання
Перевірте правильність підключення BCLK, LRC та DIN
Використовуйте динамік 4Ω 3 Вт для нормальної гучності
Забезпечте стабільне живлення 5V
Не підключайте динамік безпосередньо до ESP32
Що важливо знати про MAX98357A
MAX98357A — це цифровий підсилювач класу D з інтерфейсом I2S і вбудованим ЦАП. Він дозволяє безпосередньо виводити звук з ESP32 без складних аналогових схем, завдяки чому ідеально підходить для DIY аудіо-проєктів.
Якщо немає звуку
1. Перевірте піни I2S
Найчастіше помилка в підключенні BCLK / LRC / DIN
2. Перевірте динамік
Оптимально — 4Ω 3 Вт
3. Живлення
Нестабільні 5V = спотворення або зникнення звуку
Використовувані бібліотеки
- WiFi.h
- AudioGeneratorMP3
- AudioFileSourceHTTPStream
- AudioOutputI2S
Підсумок
Зібравши цей пристрій, ви отримаєте повністю автономне інтернет-радіо, яке вмикається однією кнопкою і не потребує смартфона чи комп’ютера. Це чудова база для подальших проєктів на ESP32: можна додати дисплей, перемикання станцій або інтеграцію з розумним будинком.
З усіх питань щодо проєкту ви можете написати в коментарях нижче.
Internet Radio on ESP32 – Arduino Sketch
#include <WiFi.h>
#include "AudioFileSourceHTTPStream.h"
#include "AudioFileSourceBuffer.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"
// ===== SETTINGS =====
const char* ssid = "YOUR-WIFI";
const char* password = "YOUR-PASS";
const char* streamUrl = "http://zt01.cdn.eurozet.pl/zet-net.mp3";
// usable pins (NOT 0 and 1)
#define VOL_UP_PIN 2
#define VOL_DOWN_PIN 4
float currentVolume = 0.21;
const float volumeStep = 0.03;
// buttons
unsigned long volUpPressTime = 0;
unsigned long volDownPressTime = 0;
// audio
AudioGeneratorMP3* mp3 = nullptr;
AudioFileSourceHTTPStream* file = nullptr;
AudioFileSourceBuffer* buff = nullptr;
AudioOutputI2S* out = nullptr;
// ===== START STREAM =====
void startStream() {
Serial.println("Starting stream");
if (mp3) { mp3->stop(); delete mp3; mp3 = nullptr; }
if (buff) { delete buff; buff = nullptr; }
if (file) { delete file; file = nullptr; }
file = new AudioFileSourceHTTPStream(streamUrl);
buff = new AudioFileSourceBuffer(file, 32768); // was 16384 → 32 KB more stable
mp3 = new AudioGeneratorMP3();
if (!mp3->begin(buff, out)) {
Serial.println("Error: mp3->begin() failed");
} else {
Serial.println("MP3 decoder started");
}
}
// ===== BUTTONS =====
void handleButtons() {
unsigned long now = millis();
// VOL UP
if (digitalRead(VOL_UP_PIN) == LOW) {
if (volUpPressTime == 0) {
volUpPressTime = now;
}
} else if (volUpPressTime > 0) {
unsigned long pressDuration = now - volUpPressTime;
if (pressDuration < 800 && pressDuration > 50) { // debounce ~50 ms
currentVolume += volumeStep;
if (currentVolume > 1.0) currentVolume = 1.0;
out->SetGain(currentVolume);
Serial.print("Volume ↑: ");
Serial.println(currentVolume, 2);
}
volUpPressTime = 0;
}
// VOL DOWN
if (digitalRead(VOL_DOWN_PIN) == LOW) {
if (volDownPressTime == 0) {
volDownPressTime = now;
}
} else if (volDownPressTime > 0) {
unsigned long pressDuration = now - volDownPressTime;
if (pressDuration < 800 && pressDuration > 50) {
currentVolume -= volumeStep;
if (currentVolume < 0.0) currentVolume = 0.0;
out->SetGain(currentVolume);
Serial.print("Volume ↓: ");
Serial.println(currentVolume, 2);
}
volDownPressTime = 0;
}
}
// ===== SETUP =====
void setup() {
Serial.begin(115200);
delay(500);
pinMode(VOL_UP_PIN, INPUT_PULLUP);
pinMode(VOL_DOWN_PIN, INPUT_PULLUP);
Serial.print("WiFi...");
WiFi.begin(ssid, password);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) {
delay(300);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi OK");
// WiFi.setTxPower(WIFI_POWER_8_5dBm); // commented out — often interferes with stability
} else {
Serial.println("\nWiFi FAIL");
}
out = new AudioOutputI2S();
out->SetPinout(5, 3, 7); // your pins — left as is
out->begin(); // important: begin AFTER SetPinout
out->SetGain(currentVolume);
startStream();
}
// ===== LOOP =====
void loop() {
if (mp3 && mp3->isRunning()) {
if (!mp3->loop()) {
Serial.println("Stream interrupted → restarting...");
delay(300);
startStream();
}
}
handleButtons();
delay(5); // small pause to avoid 100% CPU usage
}
Коментарі до статті
Дякую.
Додати коментар