ESP32 WebRadio – Ascolta le radio di tutto il mondo dal salotto di casa tua

“La radio cambia molto ma di sicuro c’è una cosa, a differenza della televisione che può essere vittima di tanti altri cambiamenti, la radio è fatta fondamentalmente di due cose che non cambieranno mai: uno che parla e un disco che suona”.
Linus

La lunga quarantena in casa è stata una ottima occasione per riprendere in mano alcuni progetti DIY (Do-It-Yourself), come l’idea di realizzare una Web Radio basata su ESP32 (di questi fantastici moduli ne abbiamo già parlato).

la mia ESP32 WebRadio

Da quando ho scoperto il sito radio.garden, di cui abbiamo parlato in passato, ho apprezzato la bellezza di poter ascoltare le trasmissioni radio di tutto il mondo usando Internet. Niente di nuovo, le webradio esistono ormai da anni, ma la riscoperta di questo servizio –e in particolare di alcune stazioni che trasmettono musica di mio gradimento 😉– mi ha ispirato. Ho così iniziato a capire se, invece dell’app sullo smartphone, potevo realizzare qualcosa di indipendente per ascoltarle, come una radio tradizionale ma…web!

I moduli ESP32 sono perfetti per questo lavoro: CPU Xtensa dual-core32-bit LX6, da 200 a 600 MIPS. 520 KB SRAM e 4MByte di flash ROM per il firmware. Connettività BT e WiFi integrata.

Per convertire un segnale digitale in analogico, adatto per essere riprodotto dagli altoparlanti, serve un DACDigital to Analog converter-. Ce ne sono di diversi tipi e con diverse caratteristiche. Avevo già a disposizione questo modulo PCM5102 acquistato su Aliexpress qualche mese fa, così ho deciso di utilizzarlo, sperando che fosse compatibile (TL;DR serve un DAC che non richiede il Master Clock, poiché gli ESP32 non sono in grado di generarlo).

Ecco un esempio di segnale I2S

Alcuni mi hanno giustamente fatto notare che all’interno dei moduli ESP32 è già presente un DAC. Anzi, per essere precisi ce ne sono DUE, collegati rispettivamente ai pins GPIO 25 e GPIO 26. Sono DAC a 8-bit. Un po’ per sfida, un po’ perché le esperienze sull’uso di questi DAC per la riproduzione di musica non sono state eccezionali, ho optato per un DAC esterno: costa pochi euro e la qualità audio è davvero eccellente!

DAC – Digital Analog Converter – Detta in due parole, proprio semplice semplice, si tratta di una tecnica per convertire un valore digitale in una approssimazione analogica. “Approssimazione” perché la qualità della sinusoide generata dipende dalla quantità dei valori (“bit”) per generarla. Più sono i bit, più dettagliato sarà il segnale analogico in uscita. Generalmente la risoluzione dei DAC va da 8 a 12 bit. Ovviamente la qualità audio dei DAC a 12bit sarà superiore.

Insomma, tornando alla radio, la questione è tutt’altro che banale: l’ESP32 deve connettersi allo stream MP3, decodificarlo, inviarlo via I2S a un DAC e poi agli altoparlanti. Nel mentre, interpretare i metadati dello stream e visualizzarli sul display. C’è poi da gestire la parte di controllo, come il volume, cambio di stream etc etc….

Inside my ESP32 WebRadio

È stato un bell’esercizio, forse uno dei più complicati che abbia fatto con questi moduli. Ma alla fine è stato forse l’oggetto DIY che, fino a ora, mi ha dato più soddisfazione.

Se siete incuriositi e volete costruirvi il vostro ricevitore di stream MP3/AAC via Internet, ecco l’elenco dei materiali necessari:

Bill of Material

  • Modulo ESP32. Ho usato una board ESP32 DevKit, presa a pochi euro su AliExpress;
  • CJMCU 5102 DAC, preso anche questo su AliExpress;
  • PCD8544 LCD Display (conosciuto anche come display Nokia 5110), su AliExpress;
  • PAM8403 2*3W modulo amplificatore (su AliExpress);
  • Due altoparlanti da 8 Ohm;
  • 3 resistenze da 10K Ohm 1/8W;
  • 2 trimmer resistivi da 100K Ohm;
  • resistenza da 330 Ohm 1/8W;
  • 3 pulsanti (anche questi presi su AliExpress);

Ho predisposto anche un PIN (D2) per collegarci uno o più NeoPixels (usando una resistenza da 860 Ohm). Al momento ho deciso di non metterli.

PCM5102 DAC

Il DAC converte un segnale digitale, I2S, in un segnale audio. Il PCM5102, modulo DAC da me utilizzato, ha diversi piedini con altrettante funzioni:

Modulo DAC PCM5102

Il data sheet del chip (www.ti.com/lit/ds/symlink/pcm5102.pdf) ne descrive le funzioni:

Per poterlo usare con l’ESP32 ho effettuato questi collegamenti:

Vcc - N.C.
3.3v - 3.3v
GND - GND
FLT - GND
DMP - GND
SCL - GND
BCK - GPIO 26
DIN - GPIO 22
LCK - GPIO 25
FMT - GND
XMT - 3.3v 

L’uscita audio è in line-out attraverso i 3 PIN (L, GND, R) oppure con il jack audio per le cuffie. Per poter avere una potenza audio sufficiente, ho deciso di usare un modulo amplificatore stereo da 3W, basato su PAM8403, ma l’ingresso audio deve essere limitato nella potenza usando due trimmer da 100K Ohm.

Schema

Lo schema elettrico dei collegamenti, realizzato e condiviso pubblicamente sul portale EasyEDA, è questo:

I pulsanti servono per controllare manualmente la radio. Attraverso il firmware si può decidere a quale funzione associarli. Attualmente i 3 pulsanti (anche se nel mio prototipo sono 4: uno per l’accensione) servono per aumentare o diminuire il volume, cambiare stream e mettere in pausa. Ricordo che con 3 pulsanti si possono avere 3^2 combinazioni 😉

i 4 pulsanti laterali

Firmware

L’hardware è solo una parte del progetto. Gran parte del lavoro viene svolto dal software, che gestisce il collegamento alla rete WiFi, la connessione allo stream MP3/AAC, la decodifica, l’invio al DAC. C’è poi la parte relativa ai controlli e alla gestione del display.

Dettaglio del display

Inoltre, la ESP32 WebRadio ha una interfaccia web responsive (Bootstrap4 e jQuery) per controllare direttamente dallo smartphone, dal PC o da qualunque altro browser, la radio. Via web si può cambiare stazione, aumentare o diminuire il volume, il contrasto, i parametri di configurazione…

L’interfaccia web della ESP32 WebRadio

Tutto il codice è scaricabile dal repository su GitHub: github.com/michelep/ESP32_WebRadio

Per poterlo compilare serve Arduino (io ho la 1.8.12) e il supporto per le board ESP32. È poi necessario installare queste librerie aggiuntive:

Per caricare la cartella /data dentro la partizione SPIFFS, suggerisco di usare l’ottimo Arduino ESP32 filesystem uploader.

*** PRIMA *** di caricare la configurazione data/config.json, ricordatevi di inserire i parametri di connessione alla rete WiFi:

{
  "wifi_essid":"[ESSID rete Wifi]",
  "wifi_password":"[Password rete WiFi]",
  "hostname":"esp32-webradio",
  "ntp-server":"time.ien.it",
  "timezone":"1",
  "stream_id":"0",
  "volume":2,
  "contrast":60
}

Gli URL degli stream delle radio che desideriamo ascoltare sono nel file data/streams.json.

Il codice è tutt’altro che perfetto ma funziona e fa il suo (sporco) lavoro. Contributi, miglioramenti, PR, sono i benvenuti. Tutto è rilasciato sotto licenza GPL quindi fatene l’uso che desiderate.

22 comments
  1. …. letto veloce veloce come fare… ci riuscirò?… magari ti faccio sapere… Io speriamo che me la cavo…

    1. Non è così difficile, forza! Se hai un minimo di manualità con Arduino e con il saldatore, stando attento ai collegamenti (che sono diversi) non dovresti avere alcun problema! È un progetto abbastanza rock solid 😉

  2. Ciao ottimo progetto, grazie per la condivisione. Faresti anche qualche foto più dettagliata dei collegamenti? Grazie

  3. Bellissima sulla base di questa disegneró un case da stamapre in 3d per contenere tutto in maniera ordinata e di design.

  4. Per la parte wifi ti consiglio di usare la libreria wifi manager attraverso la quale accende l hotspot in caso non abbia le credenziali giuste e permette di reinserire quelle corrette in quella maniera diventa portatile ovunque.

    1. L’avevo fatto ma non mi ha dato risultati soddisfacenti. Sto comunque lavorando anche a questa funzione, attualmente in wishlist 😉 grazie comunque per il suggerimento!

      1. non appena ho un pò di tempo libero inizio ad assemblare su di una board. Come mai non è soddisfacente io lo uso su un sensore IOT con batteria e pannello solare basato su esp8266 lo trovo molto utile poichè per i più vari motivi quando cambio nome alla rete non devo fare acrobazie per andarlo a smontare e riprogrammarlo parte in automatico in hotspot aggiorno la rete e funziona come nulla fosse.

  5. Hello Michele, i have a problem:

    C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio\ESP32_WebRadio.ino: In function ‘void setup()’:

    ESP32_WebRadio:278:18: error: ‘loadConfigFile’ was not declared in this scope

    loadConfigFile();

    ^

    ESP32_WebRadio:304:17: error: ‘initWebServer’ was not declared in this scope

    initWebServer();

    ^

    ESP32_WebRadio:363:18: error: ‘printStreamsDB’ was not declared in this scope

    printStreamsDB();

    ^

    C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio\ESP32_WebRadio.ino: In function ‘bool playStream(uint8_t)’:

    ESP32_WebRadio:480:28: error: ‘getStreamURL’ was not declared in this scope

    if(getStreamURL(stream_id)) {

    ^

    exit status 1

    ‘loadConfigFile’ was not declared in this scope

    Can you help me? Thanks in advance.

          1. Bad luck for me:

            Arduino: 1.8.13 (Windows 7), Board: “DOIT ESP32 DEVKIT V1, 80MHz, 921600, None”

            sketch\ESP32_WebRadio.ino.cpp.o:(.literal._Z10playStreamh+0x18): undefined reference to `getStreamURL(unsigned char)’

            sketch\ESP32_WebRadio.ino.cpp.o:(.literal._Z5setupv+0x98): undefined reference to `loadConfigFile()’

            sketch\ESP32_WebRadio.ino.cpp.o:(.literal._Z5setupv+0xa0): undefined reference to `initWebServer()’

            sketch\ESP32_WebRadio.ino.cpp.o:(.literal._Z5setupv+0xac): undefined reference to `printStreamsDB()’

            sketch\ESP32_WebRadio.ino.cpp.o: In function `playStream(unsigned char)’:

            C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio/ESP32_WebRadio.ino:490: undefined reference to `getStreamURL(unsigned char)’

            sketch\ESP32_WebRadio.ino.cpp.o: In function `setup()’:

            C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio/ESP32_WebRadio.ino:288: undefined reference to `loadConfigFile()’

            C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio/ESP32_WebRadio.ino:314: undefined reference to `initWebServer()’

            C:\Users\Valentin\Desktop\ESP32_WebRadio-master\ESP32_WebRadio/ESP32_WebRadio.ino:373: undefined reference to `printStreamsDB()’

            collect2.exe: error: ld returned 1 exit status

            exit status 1

            Error compiling for board DOIT ESP32 DEVKIT V1.

          2. It’s a linker error caused by it not found, and link, the other files. Maybe an issue with Arduino 1.8.13 on Windows? I’ve tried build it on Linux without any fuss..try to check linker path, maybe it’s caused by a wrong configuration.

  6. Hello Michelle!

    I want to add a new “Prev Stream” button to GPIO 33 (pin22) but I couldn’t. I have made the following changes:

    // Control buttons
    #define BUTTONS_NUM 4
    const int BUTTONS_PINS [BUTTONS_NUM] = {34, 35, 32, 33};

    if (buttons) {
    DEBUG_PRINT (“[BUTTON] Pressed”);
    DEBUG_PRINTLN (String (buttons));
    switch (buttons) {
    case 1: // BUTTONS 1 – Volume UP
    if (config.volume MIN_VOLUME) {
    config.volume = config.volume-1;
    }
    break;
    case 3: // BUTTONS 3 – Next stream
    nextStream ();
    break;
    case 4: // BUTTONS 4 – Prev stream
    prevStream ();
    break;
    }
    }
    }

    I didn’t succeed, can you help me?

    1. Hi Valentin, you can see the right value on serial debug log (DEBUG_PRINT(….)). However, buttons simply contains the value originated by button pressure in binary way, i.e. if you press button 4, the value should be 8 (00001000b). Just to be more clear, if you press button 1 and 4, value should be 0001001b, i.e. 9 as decimal value.

      Happy hacking!

  7. Is it alright?

    case 1: // BUTTONS 1 – Volume UP
    if(config.volume MIN_VOLUME) {
    config.volume = config.volume-1;
    }
    break;
    case 3: // BUTTONS 1+2 – Play/Pause
    togglePlay();
    break;
    case 4: // BUTTONS 3 – Next stream
    nextStream();
    break;
    case 5: // BUTTONS 3+1
    break;
    case 6: // BUTTONS 2+3
    break;
    case 7: // BUTTONS 1+2+3
    break;
    case 8: // BUTTONS 4 – Prev stream
    break;
    default:
    break;

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.