Tutorial overview

The 3 components of the banner above summarize this project: how to control a DFPlayer from DFRobot via a web interface

!!


Warning: for obvious questions of rights, there is no demonstration in sound video, because the music is protected by rights. It may seem frustrating, but can only encourage you to do this little editing!
Rest assured, it works very well!

Summary of the amazing possibilities of the DFPlayer

I was pleasantly surprised at his possibilities, especially after reading a lot of tutorials about him.

Indeed, I have even tested beyond the recommended possibilities, for example a 64 MB card works very well. It is a small module, intended to read MP3 files from an SD card. The module is basic stereo - I am surprised at the number of mounts where we see the two wires from the speaker being connected to the two terminals SPK1 and SPK2, to pins 6 and 8, leaving behind a GND ground present between the two! This assembly gives a mono sound, which is rather reducing, for my humble taste.
By the way, plugging in powerful speakers works well, but makes the DFPlayer extremely hot: it is better to make a shielded cable (otherwise we recover all the parasites in the area) and attack a HiFi system from pins 4 and 5, named DAC_1 and DAC_2, the quality is absolutely good. However, it will be necessary to connect the GND leg to the mass if we want to reduce a horrible background noise (there, I think there is a design error, because this leg is indicated as mass, or the proper of one mass is to be connected to all other masses!) Not all commands that are sent over serial communication work well, you should know. Fortunately, there is a pin that gives the status of the DFPlayer: play or not.
Some basic functions are planned, with a very simplistic interface, like I keep pressing a key for a long time -> its louder, on another -> its softer, an obscured function to insert advertising messages during the broadcast of a other sound suggests that the module was designed at the request of a particular client, then widely distributed afterwards ...
Thousands of songs can be stored and played, making them easy to identify.

Observation at interface level:

Nothing satisfactory in what exists.

Having bought this very small circuit with simple possibilities, but rather reduced or even random for certain commands, and after some research on the net, I can only find small 3-button jukeboxes with a simplistic pattern.

So I download the circuit documentation: not much, except a few direct commands (louder, quieter, new song, play such and such a file from that folder, and a programming system based on buttons and resistors. various values quite complex and impractical).

So I find quite simple tutorials, like a 3-musics jukebox ...

That's not enough for me, if I can put 32 or 64 MB of music, I "need" an interface worthy of the power of the chip! And then, my memories of the web, not so distant, come to the surface, and shout to me "Go ahead Pierre, you have time, have fun!"

Bright idea

Since there isn't much possible with buttons, let's go to the web!

Let's move the problem of the impractical interfacing in electronics to the web, more skilled at handling lists, choices, buttons, actions

And there, I took a little pleasure in exploring areas not yet visited by my web practice (great advantage of retirement: we have time, all the time we want to take, and when we want, without a deadline, without any pressure other than that which one wants to put oneself - I was already used to this practice, being on my own for the last 25 years of activity, I have developed database management applications. data bit by bit, taking my time, which is quite pleasant, without worrying about immediate productivity) Here are some avenues explored with interest during this development:

Web server

Who says web says server, because yes, the D1R1 is quite capable of being configured as a server, and if possible with a more polished and less rustic presentation than what I have been able to find.

The Json format

Using JSON format (to see how it works, and use it as a small database, or almost!)

Use of Google Fonts

Use of fonts provided by Google (there is a large selection)

AJAX

Programming in AJAX (very practical because we are in full client / server architecture), but it is pleasant not to have to reload the whole page when only a small part changes, for example when sending a command or when changing a song.

Files storage and import

The ability to import files, and build disk libraries "on the fly", so as not to "hard-code" them. This is one of the parts I'm pretty proud of (the self-made "accordions" with JavaScript modifying the DOM.)

Responsive

Of course the "responsive" part, to be able to drive from a smartphone (no need to reinvent the wheel: Bootstrap libraries do that very well) as well as a big screen computer.

DFPlayer mini de DFRobot : une playlist sur un smartphone grâce à un ESP8266 (D1R1)

The result: an app with a cool interface

Establishment of playlists by simple sliding, various buttons to control the equalizer, controls, display of titles and artists live, etc ...

In summary, a practical application to use, but, let's admit, quite disproportionate in terms of use, because an mp3 player must, in principle, be near you (program it remotely via the web, therefore potentially at home. On the other side of the world, I must admit that I don't really see the point - a radio programmer staying in bed?
A useless development therefore ("But Pierre, there is Deezer now, what's the point of doing that?", sweeps me away my son's girlfriend ...) Regardless, I knew it from the start, but I had my idea in mind (what is called a project) and the result is exactly what I wanted to do (the characteristic of a development: make it happen through programming an idea, an interface, and knowing how to stop at a point, because you can do a lot of things when you know that ..)

And then there is a certain philosophy there, to do something complex, and which is of little use, if it is not the pleasure of making your neurons work, of discovering lots of interesting things, and of share its achievement with you.

As such, I am rather happy to bring (finally) my stone to the Arduino / ESP community, because of course I did not write everything, but especially assembled many libraries, many extracts from various tutorials, in particular the web settings parts for ESP, the various Jquery, Bootstrap and Sortable.js “libraries” among others. A big thank you in passing to all these developers and to this whole OpenSource community to whom we owe so much!
May this project perhaps be of use to you, and at least make you want to go further in the web because, as I have already mentioned, I realize that these two worlds rub shoulders without getting too tamed (I will not quote anyone, but I have read several excellent tutorials in the Arduino / ESP part, but very poor when it comes to displaying something).

Simply control any device from a smartPhone, all while having it "homemade", I find this quite rewarding, we can imagine controlling more important things, automating devices, controlling a machine, why not a more complex automation, always with these small microprocessors connected, at a few dollars, in short, the future is full of surprises ... In any case, me, during all the realization of this remote MP3 player, I took the same pleasure as when I made, as a child, assemblies in Meccano, while listening to all the music I love.

DFPlayer mini : une playlist sur le web grâce à un ESP8266 (D1R1)

The technique: how it works

The general principle for making my project:

The diagram opposite explains the general principle of what I want to achieve: control a DFPlayer from a smartphone or a computer .

The music tracks, stored on the SD card which is itself installed on the DFPlayer, must have a name and number specific to the DFPlayer doc.

Then the web server hosted by the D1R1 card will have a classic structure, an index.html page for the reception, which itself will look for its images in an IMG folder, javaScript in a JVST folder, css in a CSS folder , etc.
Here is the tree structure on the image opposite

Technique des dossiers avec LittleFS
The DFPlayer can read in 16 files, numbered from 01 to 16, songs that must be in the form: 0001 Je suis malade, 0002 Les p’tites femmes de Pigalle, and so on ...

Do not go to folders greater than 16, there is a random management. In this regard, the DFPlayer has great advantages, already mentioned, but some "treacherous" defects, such as the random management of certain direct commands, such as commands sent to give the status - read or not, which return what they are. want to send, but not the reality of the state, which troubled me for a while.

We are therefore going to prepare (I developed a utility this summer on a web page included in the site to help you) carefully numbered .mp3 files, and stored in such and such a folder.

See the code of this utility (a web page which will be loaded in the EEPROM)

And the trick is there: from these files, we will create disc and song definitions in Json format (this is where the utility is used, thanks to a simple Copy / Paste from the list of songs!

An example :
0101 Doctor Renaud, Mister Renard, and all the others below will give a Json which will be automatically read, displayed, used when displaying the reading ...
vinyl1='{"Titres": [{ "dos": "01", "num": "0101", "titre": "Docteur Renaud, Mister Renard", "aut": "Renaud" }, {"dos": "01", "num": "0102", "titre": "Petit Pédé", "aut": "Renaud" }, {"dos": "01", "num": "0103", "titre": "Je Vis Caché", "aut": "Renaud" }, {"dos": "01", "num": "0104", "titre": "Coeur Perdu", "aut": "Renaud" }, {"dos": "01", "num": "0105", "titre": "Manhattan-Kaboul", "aut": "Renaud" }, {"dos": "01", "num": "0106", "titre": "Elle A Vu Le Loup", "aut": "Renaud" }, {"dos": "01", "num": "0107", "titre": "Tout Arrêter...", "aut": "Renaud" }, {"dos": "01", "num": "0108", "titre": "Baltique", "aut": "Renaud" }, {"dos": "01", "num": "0109", "titre": "L\'entarté", "aut": "Renaud" }, {"dos": "01", "num": "0111", "titre": "Mon Nain De Jardin", "aut": "Renaud" }, {"dos": "01", "num": "0112", "titre": "Mal Barrés", "aut": "Renaud" }, {"dos": "01", "num": "0113", "titre": "Corsic\'armes", "aut": "Renaud" }, {"dos": "01", "num": "0114", "titre": "Mon Bistrot Préféré", "aut": "Renaud" } ] }';

Be careful, if this help is important because it creates the Json file correctly, however it remains to name (modify more precisely) the name of the files on the SD card which will be inserted in the DFPlayer.

Process to follow

Usually, you get the name of the tracks from the CD you burned via iTunes or something else. It is already that, because the pure CD format is too old to have foreseen a little bit of space to write the names of the songs and the artists.
I can't help but comment on this, to the attention of the youngest, who have only known mobile telephony, with on-board internet. So micro-computing already widely popularized, in every household, etc. The older ones had the chance to see all this set up, little by little, the first processors, the digitization of sound, first, then image, and finally video, year after year, even decade after decade. I was a Mac user from the start, then very quickly Apple's technical salesman: there was no better place to experience this evolution.
This is to say that the CD was invented when microcomputers did not exist, or stammered in the garage of hackers. While it would have been easy to digitally encode a few small bits of text, it escaped the designers. Not even planned for memory space or registers for the future ...
Well, the revolution was huge, destroyed vinyl and of course brought water to the mill of mp3 and other digital formats. Who, them, had the good idea to provide a little bit of space to put title and other artist name, duration, etc ... End of the apart.
At the start of the page loading, the Json file is imported, and we therefore load all the records ‘vinyl1, vinyl2, .... into RAM. These Jsons will then be read in a loop and will go to make the accordions. If you look at the html code, we only see


				<div id="accordion" >
				</div>

The main role of the app

Clarification on the name of the app: in reality, it is not really an app, but above all a web page. And since it only has one function, and relates directly to the DFPlayer, I take the liberty of calling it an app.

The essential role of the app will therefore be to build lists of songs one after the other, and to send them to the DFPlayer.

Several other commands will also be sent, such as sound level control, using an adjustable slider, just to look pretty and professional.
Regarding the format of the lists, I opted for a simple format, not the least greedy in size since I put tags of each one character, but easy to read for debugging: folder and serial number are separated by a *, and each song ends with an @.
So here is an example of a playlist as it will be sent to D1R1:

06*0007@06*0006@05*0001@01*0142@01*0146@01*0109@07*0001@07*0012@01*0106@01*0184@07*0011@

After having established, on the client side (on his smartphone or PC / Mac) the desired list, we will communicate by URLs or Ajax with the server. This will execute the orders received, and every 2 seconds, will return a list of parameters to the client, in order to update (without reloading the entire page each time) the page: the song played, the current list, l 'artist, the regulated power of the sound, the type of equalizer adjustment, and as all that only moves from time to time, for the unloading, I sent, and also posted, a number at random, practical for see if the transmission is going well.
You can now follow what happens in the ESP program part: this list will be put in a Playlist variable, then be stored on disk in a "Playlist.json" file thanks to LittleFS, and this will then allow to have a list non-volatile, which can be reloaded either on demand, when launching the app, or directly executed (an algorithm searches for the first song, pastes it into a variable, destroys it from the Playlist, and gives the order to the DFPlayer to play it.
This then changes state, the Loop constantly scans this state, and as soon as it changes, will look for the next one in the Playlist cut off from the last song. Simple, efficient.

The ESP listed role

Aside from the installation of Internet libraries (automatic multi-access point connection, launching and configuring the Web server, the "control of the DFPlayer mini" part is extremely limited on the Arduino type programming side, since just one Pin to monitor...

The ESP8266 (D1R1) which acts as the interface between the web and DFRobot's DFPlayer mini to control it through playlists
On the ESP program side, I wanted to build a WiFimulti link, with of course a WebServer and a WifiClient. After having filled in its WiFi codes "in stone", the D1R1 will connect itself to any place in the house. Wonderful little chip, with about 4MB of free space, enough to store people in html. Especially since the text is obviously imported and sent directly to the webserver, without going through the RAM of the D1R1, we can go! My source
The monitoring formula that I have chosen is therefore the hardware possibility offered by the DFPlayer to indicate its state: I am reading, or I am free (by the way, since I am too stupid to correctly send the commands provided for in this sense !)

So I put a wire between the Busy terminal (n ° 16) of the DFPlayer and the D12 pin of the D1R1.
All the rest will consist of constantly monitoring (in the Loop) the server, and interacting with it: hey, I receive an order from a (web) client, I quickly pass it to a function that will execute it. It can be launching the current Playlist, recording it, erasing it, making it louder, changing the type of sound. But it can also answer a question asked by the user, especially by updating by JavaScript and AJAX some display of the page, in particular the song currently played, or a random list sent by a user, and which must then be seen by ALL users (I see it in a big way, as
if several users were going to use the app at the same time !! It's more a memory of a development of a multi-user management app .. .)

Because I have deported most of the web-side functions. The random list part, for example, is created on the web side: this allows you to modify it as you wish with the ease of sortable lists, amputable at will, and then send it to the DFPlayer or save it. Received in the microprocessor, it is then pasted in the Playlist variable, then either played or recorded.
It works fine, but other users are not up to date in the currently played list! That’s why I can one button update the server to let planet earth know that Johnny is going before Cloclo, and the rest follows. When programming this kind of site, you should never forget the role of the server, which one or more clients can see remotely.

This double watch scared me a little, I was afraid that the time of one action would block the other, but no, it's going well. When we look at what is happening through the display on the serial port, it goes very quickly!

Addition to code comments

Now I'm going to add some comments to the ones left in the code (I've left all my comments on purpose, as well as // some scripts so sometimes some want to understand better.)

On the web side, so the html page, the most difficult part to understand is the placement of the disks in the form of accordions. Not the accordions themselves, that is libraries that do that very well, but the way they fill up.
In a JavaScript script, we find this part:

let cpt=NombreDisques();
               		for (var numDisque = 1; numDisque < (cpt+1); numDisque++) {
               			let dossier= "Disque n°"+numDisque;
               			let collaps = "collapsible"+numDisque;
               			let malist="MaListe"+numDisque;
               			str1 = toString(numDisque); // pour gérer DFP qui veut des noms de dossiers en 01, 02, etc.		
               			j=(numDisque.toString());   // idem
               			let nom="**"+j.padStart(2, '0'); // idem
               			let monID="titredisque"+numDisque;
               			var Dat = window['vinyl' + numDisque];//attribution dynamique des noms de variables
               			var Lis = ('MaListe' + numDisque); // idem...
               			var TitreDisque=('titredisque' + numDisque);// c'est pour ajouter l'auteur après le numéro de dossier (ou du disque...)
               			var DefDisque = document.createElement('div');//on crée un div pour l'onglet entier de l'accordéon
               				DefDisque.classList.add('card', 'bg-warning');
               				var Le_div = document.createElement('div');// puis je crée un div conteneur du titre
               				Le_div.classList.add('card-header');
               				var Le_a = document.createElement('a');// avec son a et ses attributs
               				Le_a.classList.add('card-link', 'collapsed');
               				Le_a.style.cssText = " font-family: 'Fugaz One', cursive; font-size: 2rem; color: red;" ;
               				Le_a.setAttribute("data-toggle","collapse");
               				Le_a.setAttribute("data-parent","accordion");
               				Le_a.href="#"+collaps;
               				Le_a.id=monID;
               				Le_a.textContent = dossier;// le titre en question avec l'indexation automatique
               				Le_div.appendChild(Le_a);// établissement de la hiérarchie
               				DefDisque.appendChild(Le_div);// idem
               				
               
               			var ContenuDisque = document.createElement('div');// puis un conteneur d'accordéon
               			ContenuDisque.classList.add('collapse');
               			ContenuDisque.id=collaps;// avec l'indextation automatique
               			var cont = document.createElement('div');
               			cont.classList.add('card-footer');
               			var divListe = document.createElement('div');
               			divListe.id=malist;
               			var morceaux = JSON.parse(Dat);// et là je remplis les div de chaque morceau (les morceaux de musiques en lisant et exploitant les définitions Json. C'est un peu le cœur de la page, où JavaScript est bien exploité !
               			
               				    for(let i = 0; i < morceaux.Titres.length; i++) { // remplissage pour chacun des disques de tous les titres
               				      var monMorceau = document.createElement('div');
               				      var Parametre1 = document.createElement('p');
               				      var Parametre2 = document.createElement('b');
               				      var Parametre3 = document.createElement('b');
               				      
               				    	monMorceau.id = morceaux.Titres[i].dos +"*"+morceaux.Titres[i].num;   //on pourra ainsi identifier le morceau par son id...      
               						    			      	               
               				      Parametre1.innerHTML =  morceaux.Titres[i].titre ;
               				      monMorceau.appendChild(Parametre1);
               				      divListe.appendChild(monMorceau); 
               				    }				    
               				    auteur=morceaux.Titres[1].aut;// je prends le premier de la liste
               				Le_a.insertAdjacentHTML('beforeend', " : "+auteur); 			
               			cont.appendChild(divListe);
               			ContenuDisque.appendChild(cont);
               			DefDisque.appendChild(ContenuDisque);
               			document.getElementById("accordion").appendChild(DefDisque); 
               		
                 	}
               
                

There, to fully understand, you have to know the html, and also the way accordions work, but basically, we create for each piece a
, with a certain class for the title, then a
per piece , which itself contains a

., etc ... Incidentally, these elements will be "dragged" to another

which will serve as a container for the established playlist. This
will of course have the song number as ID, for example 07 * 0011, it is by this ID that the edited list will be retrieved by a fairly magical (powerful, shall we say!) Command from the HTML:

                const myNodelist=document.getElementById("listePlayListe").getElementsByTagName("div");// ici, je récupère la liste avec les éventuels ajouts, par ses ID
                Cette puissante commande me sélectionne les div «enfants» de la div ayant pour ID «listePlayListe», il ne me reste plus qu’à récupérer ma playlist, séparée dans la boucle par des @
                		var plList = "";
                		       for(var i = 0; i < myNodelist.length; ++i){
                		           plList += myNodelist[i].id + "@";
                		       }
                		       
Clever, right?
I don't want to hide a concern at this point that has occupied me for a good afternoon. This is a display that I was not getting back. It's in the highlight part (a different css) of the current song. Reminder of the HTML: an ID is a unique identifier, it allows precisely to retrieve or act on a specific element.
However, the playlists creation system copies the various songs, thus also copying the IDs. So I end up with identical IDs in two different places: one in the accordion (the origin of the song, stored in his accordion album), and the other in the established list!
However, I did not know, html in this case only manages the first one found. And since the accordion is, in essence, folded up, I couldn't see that the highlighting was good, but obscured. Every programmer knows this joy / victory when, Eureka, he understands his mistake.
I had the Eureka in my head, even before I opened the accordion with the element highlighted - a track by Johnny ...

LittleFS, a reliable solution

Store, write and modify files

Since I had to store, write and modify files, I chose this solution, and used it properly, that is, I structured the folders well, with short folder names. It is a very reliable system, easy to use.
It will therefore be necessary to import this library into the Arduino IDE.

My source

The 2 HTML and ESP / Arduino codes

What must be understood is the difference in languages ​​and programming between the Arduino language which will drive the heart of the ESP8266, therefore the hard and soft control of the DFPlayer mini and the HTML, which will make the link between ESP and the whole world (just that!).
The interface between the web and DFRobot's DFPlayer mini to control it through playlists


There will be two different stages, two different logics during development, two different ways of installing the code on the same medium!
I won't dwell on how to send the sketch to the ESP, a bunch of tutorials exist for this, you just need to have the right libraries installed, otherwise it's like burning a UNO.
Indeed, as much as the Arduino IDE will compile the code and burn it in the reserved part of the ESP8266, the HTML part, as well as other files necessary for the app will only be "banally" copied into the memory's EEPROM available.
You will have to debug first, there is no verification. As it is HTML, a simple browser is enough to do the tests. See attached the ease of update, thanks to the LilleFS utility, all the folder included in the data folder is completely copied, with the sub-folders and everything they contain ...

HTML code

The code is widely commented. I have often voluntarily left some traces of help with debbugging

The ESP side code

After importing the various libraries required for the WiFi connection, the Web server, file storage, a pseudo serial port and of course the DFRobotDFPlayerMini, the ESP makes the link, in both directions, between the DFP and the server Web, which will therefore be seen from everywhere (if a channel is declared in its box, or else only locally, with an address of type 92.168.1.34, which must also be configured in its box. Easy to do.

And after the soft, let's see the hard

It is an extremely simple assembly, because of the commands and controls carried out on the web side.

I have already said: the connection is very simple: two wires for powering the circuits (I noticed that the DFPlayer works better at 5V), two wires for the Rx and Tx serial port of the DFPlayer (D10, D11 we use SerialSofware, so do not use the terminals reserved for the serial port on the R1D1 side) and a wire to monitor the status (D12 -> Busy). That's all !

The usual serial connection is used on the other hand for debugging, and there were quite a few before we got there (I am a Sunday developer ...), but it was mostly on the web side (there, we do not debug any the same way. About all these tests, I report a practice during the compilation on the D1R1 board: I had to disconnect one of the terminals D10 or D11, otherwise the serial communication did not pass, and therefore the engraving did not was not happening.

Development history, and its developer

    Retired for 2 and a half years (after a professional life in the graphic arts and a screen printing workshop), living in France, I was offered an Arduino R3 board at Christmas Year 1 at the Covid, and a few extras needed to get started. I did not know the Arduino language at all, had never studied microelectronics, but still had this desire to study this because:
  • I like programming, since the beginnings of Hypercard (there, young people no longer have to follow ... FYI, it was, shortly after the beginnings of the Macintosh, a language delivered with all Macs, quite easy and revolutionary , close to Pascal.)
  • I really like the Internet and especially the dynamic website part (I've done several, including a fairly complex one in php, javascript, CSS, and HTML of course).
  • and above all I am curious about almost everything, technology, IT, mechanics, and remembered having discovered while browsing OpenClassroom the Arduino language 6 or 7 years ago - I was still working -, and said to myself "It would take 2 lives to be able to discover all this!"


  • No, no, not 2 lives, retirement, and successive confinements, gave me time to quietly learn the basics of Arduino, and of course I was very quickly enthusiastic about everything that revolves around the web, especially the small ESP modules, some very small but surprisingly powerful.
    My choice fell, for the practical and inexpensive side, on the D1R1 board which is programmed in Arduino language and allows to have about 4 MB of available (like a small accessible hard drive) in which we can put what we want.
    I think that everyone (apart from the students, and there are obviously many who have exercises to do) who discover this nice world, at some point, wonder what the hell we could do with it? It's so vast, that you also have to limit yourself otherwise you can go all over the place ...

    My various research of course led me to a few Chinese sites (ESPs are Chinese developments), and I must admit that it is tempting to see everything that is being produced, at low prices, in this area.
    Among a few various chips, I said to myself that an SD card reader in mp3 for a few dollars should be nice to bring sound to an application, and my choice fell on the small DFPlayer from DFRobot.

    And, one thing leading to another, from discovery to discovery, the idea therefore arose to create a web interface to pilot this chip.
    Then once the application was more or less finished, I thought to myself that it would be good to share it with others. Also, knowing nothing about blogs and other forums, and not knowing how to do it, I offered to do a tutorial in the form of a website, which fell within my skills.
    That I have, in passing, in-depth learning to do things that I had never done before: screen mirroring, video publication without YouTube or other, knowing how to put "colorized" code in a web page, etc ...

    You have the result of all this in front of you!

    Pierre Saunière, La Chapelle Basse-Mer, near Nantes, France - November 2021

The final assembly of the ESP8266 (D1R1) which is the interface between the web and DFRobot's DFPlayer mini to control it through playlistsThe final assembly

I hope that this project will find a favorable echo among Internet users. If you want to contact me, here is my email (to retype, to avoid the automatic collection of emails ...)