Overview: ESP32 Web Radio
In this project, we will make ESP32 Web Internet Radio using ESP32 Board, Audio Expansion Shield & OLED Display. The combined ESP32 Audio inherited the DAC chip and SD card module.The I2S chip allows you to play songs stored on the Internet.The SSD1306 screen displays basic information about the song, and the scroll wheel switch on Audio allows you to switch and pause the music.
The Commercial internet radio receivers available in the market are relatively expensive and cost more than 100$. So I decided to make an Internet Radio that is functional, easy to make, and inexpensive. Earlier I made ESP32 Music Player which worked very well, so I decided to use the same device to make an Internet Radio.
Bill of Materials
All the components required for this projects can be easily purchased from Makerfabs. The components purchase link is given below.
| S.N. | Components Name | Description | Quantity | Buy Online |
|---|---|---|---|---|
| 1 | Customized ESP32 Board | MakePython ESP32 Board | 1 | Click Here |
| 2 | Audio Expansion Board | MakePython Audio Expansion | 1 | Click Here |
| 3 | 3D Casing | ESP32 Audio Fixture Kit | 1 | Click Here |
| 4 | Speakers | Speaker with 3.5mm Audio Jack | 1 | Amazon | AliExpress |
| 5 | 5V Power Supply | Power Bank | 1 | Amazon | AliExpress |
Block Diagram of the ESP32 Web Radio
The block diagram of the ESP32 Internet Radio is given below. We use customized ESP32 Module along with ESP32 Audio Expansion Board. The ESP32 Connects to wifi and look for defined radio station online data.
The principle behind the project is that if we can deliver a chunk of streaming data in an exact quantity of 32 bytes to the board in the form of a stream, it will just keep on playing. That means the ESP32 is to connect the streaming site at the fixed port and then receive the streaming data in an exact chunk of 32 bytes at a time. On the other hand, the board will keep on processing the data like an inflow/outflow machine and the stream will continue to play.
Hardware Requirement & Assembly
For this project we need a customized ESP32 Board. MakePython ESP32 is a powerful, generic Wifi+ BLE MCU module that supports both C/C++ & Python programming. It is true “breadboard compatible”, with the very detailed pins explanation, it is easy to learn & use. The MakePython ESP32 is programmed via Arduino IDE.
Similarly, we need an Audio Expansion Board. The Audio expansion board is based on the UDA1334ATS audio DAC, to implement audio functions to ESP projects. It communicates with ESP32 with I2S, and output relative good quality audio.
Apart from these we modules we need 3D Casing which is designed using 3D Modelling Software. The 3D case makes the device compact and small. You can download the STL files from here: 3D Case STL File
Assemble all the hardware explained in ESP32 Music Player.
Now your ESP32 Web Radio is ready to rock.
Adding Esp32-AudioI2S Library to Arduino IDE
The UDA1334ATS IC on ESP32 Audio does not support MP3 hardware decoding. So this library is used for MP3 decoding and volume control. Not only can you read MP3 files from your SD card, but you can also play MP3 stations directly from the Internet.
Source Code & Program
Copy the code from below and upload it to the ESP32 Board. Before uploading there is some modification required in the code.
|
1 2 |
const char *ssid = "Alexahome"; const char *password = "loranthus"; |
Change the WiFi SSID & Paasword from the line above.
|
1 2 3 4 5 6 7 8 9 10 |
String stations[] = { "0n-80s.radionetz.de:8000/0n-70s.mp3", "mediaserv30.live-streams.nl:8000/stream", "www.surfmusic.de/m3u/100-5-das-hitradio,4529.m3u", "stream.1a-webradio.de/deutsch/mp3-128/vtuner-1a", "mp3.ffh.de/radioffh/hqlivestream.aac", // 128k aac "www.antenne.de/webradio/antenne.m3u", "listen.rusongs.ru/ru-mp3-128", "edge.audio.3qsdn.com/senderkw-mp3", "macslons-irish-pub-radio.com/media.asx"}; |
Add your local radio station link or the stations that you want to listen to. For example, I am staying in India & I want to listen to Indian Radio Channels, I would add Indian Radio Stations link.
Here is a complete code for the project.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
#include "Arduino.h" #include "Audio.h" #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> //Digital I/O used //Makerfabs Audio V2.0 #define I2S_DOUT 27 #define I2S_BCLK 26 #define I2S_LRC 25 //SSD1306 #define MAKEPYTHON_ESP32_SDA 4 #define MAKEPYTHON_ESP32_SCL 5 #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //Button const int Pin_vol_up = 39; const int Pin_vol_down = 36; const int Pin_mute = 35; const int Pin_previous = 15; const int Pin_pause = 33; const int Pin_next = 2; Audio audio; const char *ssid = "Alexahome"; const char *password = "loranthus"; struct Music_info { String name; int length; int runtime; int volume; int status; int mute_volume; } music_info = {"", 0, 0, 0, 0, 0}; int volume = 21; int mute_volume = 0; int runtime = 0; int length = 0; String stations[] = { "0n-80s.radionetz.de:8000/0n-70s.mp3", "mediaserv30.live-streams.nl:8000/stream", "www.surfmusic.de/m3u/100-5-das-hitradio,4529.m3u", "stream.1a-webradio.de/deutsch/mp3-128/vtuner-1a", "mp3.ffh.de/radioffh/hqlivestream.aac", // 128k aac "www.antenne.de/webradio/antenne.m3u", "listen.rusongs.ru/ru-mp3-128", "edge.audio.3qsdn.com/senderkw-mp3", "macslons-irish-pub-radio.com/media.asx"}; int station_index = 0; int station_count = sizeof(stations) / sizeof(stations[0]); void setup() { //IO mode init pinMode(Pin_vol_up, INPUT_PULLUP); pinMode(Pin_vol_down, INPUT_PULLUP); pinMode(Pin_mute, INPUT_PULLUP); pinMode(Pin_previous, INPUT_PULLUP); pinMode(Pin_pause, INPUT_PULLUP); pinMode(Pin_next, INPUT_PULLUP); //Serial Serial.begin(115200); //LCD Wire.begin(MAKEPYTHON_ESP32_SDA, MAKEPYTHON_ESP32_SCL); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for (;;) ; // Don't proceed, loop forever } display.clearDisplay(); logoshow(); //connect to WiFi Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" CONNECTED"); lcd_text("Wifi CONNECT"); //Audio(I2S) audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(21); // 0...21 open_new_radio(stations[station_index]); } uint run_time = 0; uint button_time = 0; void loop() { audio.loop(); print_song_time(); //Display logic if (millis() - run_time > 1000) { run_time = millis(); display_music(); } //Button logic if (millis() - button_time > 300) { if (digitalRead(Pin_next) == 0) { Serial.println("Pin_next"); if (station_index < station_count - 1) { station_index++; } else { station_index = 0; } button_time = millis(); open_new_radio(stations[station_index]); } if (digitalRead(Pin_previous) == 0) { Serial.println("Pin_previous"); if (station_index > 0) { station_index--; } else { station_index = station_count - 1; } button_time = millis(); open_new_radio(stations[station_index]); } if (digitalRead(Pin_vol_up) == 0) { Serial.println("Pin_vol_up"); if (volume < 21) volume++; audio.setVolume(volume); button_time = millis(); } if (digitalRead(Pin_vol_down) == 0) { Serial.println("Pin_vol_down"); if (volume > 0) volume--; audio.setVolume(volume); button_time = millis(); } if (digitalRead(Pin_mute) == 0) { Serial.println("Pin_mute"); if (volume != 0) { mute_volume = volume; volume = 0; } else { volume = mute_volume; } audio.setVolume(volume); button_time = millis(); } if (digitalRead(Pin_pause) == 0) { Serial.println("Pin_pause"); audio.pauseResume(); button_time = millis(); } } //Serial logic if (Serial.available()) { String r = Serial.readString(); r.trim(); if (r.length() > 5) { audio.stopSong(); open_new_radio(r); } else { audio.setVolume(r.toInt()); } } } void print_song_time() { runtime = audio.getAudioCurrentTime(); length = audio.getAudioFileDuration(); } void open_new_radio(String station) { audio.connecttohost(station); runtime = audio.getAudioCurrentTime(); length = audio.getAudioFileDuration(); Serial.println("**********start a new radio************"); } void display_music() { int line_step = 24; int line = 0; char buff[20]; ; sprintf(buff, "RunningTime:%d",runtime); display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, line); // Start at top-left corner display.println(stations[station_index]); line += line_step * 2; display.setCursor(0, line); display.println(buff); line += line_step; display.display(); } void logoshow(void) { display.clearDisplay(); display.setTextSize(2); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.println(F("My ESP32")); display.setCursor(0, 20); // Start at top-left corner display.println(F("WEB` RADIO")); display.setCursor(0, 40); // Start at top-left corner display.println(F("")); display.display(); delay(2000); } void lcd_text(String text) { display.clearDisplay(); display.setTextSize(2); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); // Start at top-left corner display.println(text); display.display(); delay(500); } //********************************************** // optional void audio_info(const char *info) { Serial.print("info "); Serial.println(info); } void audio_id3data(const char *info) { //id3 metadata Serial.print("id3data "); Serial.println(info); } void audio_eof_mp3(const char *info) { //end of file Serial.print("eof_mp3 "); Serial.println(info); } void audio_showstation(const char *info) { Serial.print("station "); Serial.println(info); } void audio_showstreaminfo(const char *info) { Serial.print("streaminfo "); Serial.println(info); } void audio_showstreamtitle(const char *info) { Serial.print("streamtitle "); Serial.println(info); } void audio_bitrate(const char *info) { Serial.print("bitrate "); Serial.println(info); } void audio_commercial(const char *info) { //duration in sec Serial.print("commercial "); Serial.println(info); } void audio_icyurl(const char *info) { //homepage Serial.print("icyurl "); Serial.println(info); } void audio_lasthost(const char *info) { //stream URL played Serial.print("lasthost "); Serial.println(info); } void audio_eof_speech(const char *info) { Serial.print("eof_speech "); Serial.println(info); } |
Once the code is uploaded, open your Serial Monitor. You will see the following info logged in.
ESP32 Web Radio Test & Demo
After the code is uploaded to the ESP32 Board, you can start testing the Device by simply powering it ON. Make sure that the device is connected to the Wifi Network.
Now your ESP32 Based Internet Radio is ready. So it’s time to listen to the radio. So insert the Speaker stereo or earphone into a 3.5mm audio jack. You can use the power bank to power the ESP32 Audio Player Board & also the Speaker.
Once powering is done, the device will start playing the default radio station. The OLED Display screen displays the basic information of the .
You can press/move the lower side switch left and right for the next or previous Radio Station. Press it inward to pause. Similarly, the switch on the left is Volume Control & Mute. You can slide it up for increasing volume & down for decreasing volume. Also, you can Press in to mute.















19 Comments
Which Libraries should I use, every time I get Error compiling for board esp32 wrover module
same Problem!!!
connecttohost needs a const char* in the Audio.cpp and not a String!
I have changed the String [] STATIONS in char* in the sketch and its running!
Can you please explain in more detail what exactly did you do to get it running? I cannot make my sketch to compile…. : (
In display_music function I changed line_step to 8 and removed ‘*2’. Now there is enough room for additional text. Can someone give a hint how to get streamtitle to LCD screen? It can be seen from serial console, so it could be possible.
webradio dont work!
dont start radio
This was my first ESP32 project
Few steps required to install the libraries for the ESP32 and the libraries for the Audio and SD card.
I also had to remove the original Arduino SD card as there were conflicting calls to another SD library I had.
I was still getting an error.
Audio::connecttohost(const char*, const char*, const char)
bool connecttohost(const char host, const char* user = “”, const char* pwd = “”);
error: no matching function for call to ‘Audio::connecttoFS(fs::SDFS&, String&)’
audio.connecttoFS(SD, url);
Changed
217 from
audio.connecttohost(station);
to
audio.connecttohost(station.c_str());
I have also found that I can only flash the code when the audio board is not connected.
Different from Arduino boards that I can flash without any button presses required. I’m thinking this is some hardware issue???
I added a couple of global variables to hold the data
//Reserve names for stream info
String sTitle; //Stream Title
String sName; //Stream Station Name
and in the optional data that is populated I populated the values
void audio_showstation(const char *info) {
Serial.print(“station “);
Serial.println(info);
sName = String(info);
}
void audio_showstreamtitle(const char *info) {
Serial.print(“streamtitle “);
Serial.println(info);
sTitle = String(info);
sTitle.replace(“|”, “\n”);
}
and in the display music section added the displayprintln
display.setCursor(0, line); // Start at top-left corner
display.println(dName[station_index]);
display.println(sName); //
display.println(sTitle);
Found can resolve this by holding the channel select toward the 3.5mm output while starting the upload.
This releases the GPIO12.
I was todays year old when I found this!
I built this project and eventually, after a great deal of tinkering, I got it to work. However, I experienced some very strange behavior that I describe below in the hope that someone with more electronics knowledge than me (that’s not too difficult btw) can shed some light on this issue.
Let me start by saying that my soldering ability is not too great either and that may have something to do with my problems.
Anyway, I got the radio to connect to my wifi and begin to connect to a station in the list, but it immediately then connected to the next station in the list – and continued this behavior, preventing the radio stream from being processed. Via the serial monitor (and the addition of comments in the code) I discovered that pin 2 (Pin_next in the code) was being continuously detected to be “low” (meter reads just over 1v which the arduino hw evidently sees as low. The control “wheels” on the audio board all operate correctly, with all but the next control operating as expected (reading 0v when activated, 3.2v when not). The next pin reads 0v when active, 1.07 or so when the wheel is released.
As an act of desperation I briefly “shorted” pin 2 to 3.3v and a miracle happened – the pin worked as expected from then on, allowing me to cycle through all the station list entries and connect to each radio station successfully. This only lasted until I reset the board though, when the bad behavior resumed. I was able to correct it again as before (this time using a resistor to short to 3.3v just in case).
I’m at a loss to understand what’s happening – any ideas?
my configuration for next/previous buttons, since the gpios are in “input_pullup” following link:
GPIO -> button -> 10K resistor -> ground
this way it works. I just used next/prev and a normal variable resistor on the ADC for volume.
Thanks for your reply. The “next” pin seems to be behaving itself now, but I am now experiencing the same problem with the “previous” pin so I conclude the problem is in the mechanics of the selection wheel itself. I’ll use a couple of buttons external to the audio board for next/prev control as you suggest.
Hi !
For this achievement, which version of the ESP32 module should I choose: the WROOM version or the WROVER version?
Hi, I can’t get it to compile, says “sketch too big”. Any ideas?
Sorry for the incomplete reply. Here’s what I intended to write …
I don’t know if this is your problem but I had a similar problem when I tried to use a NodeMCU instead of ESP32. UNO (and the Node MCU) has limited RAM – not enough to declare all the display strings and to initialize the 128×64 OLED display (which needs at least 1KB) so the text strings for the URLs, and the menu strings on the display, are stored in program memory. These strings must first be
copied into buffers in RAM before they can be used in the various Serial.print statements. Hope this helps.
Nice Projekt – my Problem is that my ESP32 will find no WLAN. I used the same Handware you did.