├── data ├── edit.htm.gz ├── favicon.ico ├── graphs.js.gz ├── faviconBlue.png ├── faviconGreen.png ├── faviconPink.png ├── basic.htm └── index.htm ├── docs ├── Thumbs.db ├── dfPlayer1.jpg ├── dfPlayer2.jpg ├── dfPlayer3.jpg ├── dfPlayerESP8266.fzz ├── dfPlayerModuleBack.jpg ├── dfPlayerModuleFront.jpg ├── dfPlayerESP8266_schem.pdf └── dfPlayerESP8266_schem.png ├── libraries └── DFRobotDFPlayerMini │ ├── doc │ └── FN-M16P+Embedded+MP3+Audio+Module+Datasheet.pdf │ ├── library.properties │ ├── .travis.yml │ ├── README.md │ ├── examples │ ├── GetStarted │ │ └── getStarted.ino │ └── FullFunction │ │ └── FullFunction.ino │ ├── DFRobotDFPlayerMini.h │ └── DFRobotDFPlayerMini.cpp ├── dfPlayer ├── BaseConfig.h └── dfPlayer.ino ├── README.md └── tools └── dfPlayer-makeSD.vbs /data/edit.htm.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/edit.htm.gz -------------------------------------------------------------------------------- /data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/favicon.ico -------------------------------------------------------------------------------- /docs/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/Thumbs.db -------------------------------------------------------------------------------- /data/graphs.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/graphs.js.gz -------------------------------------------------------------------------------- /docs/dfPlayer1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayer1.jpg -------------------------------------------------------------------------------- /docs/dfPlayer2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayer2.jpg -------------------------------------------------------------------------------- /docs/dfPlayer3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayer3.jpg -------------------------------------------------------------------------------- /data/faviconBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/faviconBlue.png -------------------------------------------------------------------------------- /data/faviconGreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/faviconGreen.png -------------------------------------------------------------------------------- /data/faviconPink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/data/faviconPink.png -------------------------------------------------------------------------------- /docs/dfPlayerESP8266.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayerESP8266.fzz -------------------------------------------------------------------------------- /docs/dfPlayerModuleBack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayerModuleBack.jpg -------------------------------------------------------------------------------- /docs/dfPlayerModuleFront.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayerModuleFront.jpg -------------------------------------------------------------------------------- /docs/dfPlayerESP8266_schem.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayerESP8266_schem.pdf -------------------------------------------------------------------------------- /docs/dfPlayerESP8266_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/docs/dfPlayerESP8266_schem.png -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/doc/FN-M16P+Embedded+MP3+Audio+Module+Datasheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberttidey/dfPlayer/HEAD/libraries/DFRobotDFPlayerMini/doc/FN-M16P+Embedded+MP3+Audio+Module+Datasheet.pdf -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/library.properties: -------------------------------------------------------------------------------- 1 | name=DFRobotDFPlayerMini 2 | version=1.0.2 3 | author=DFRobot 4 | maintainer=Angelo 5 | sentence=Driver for DFPlayer Mini from DFRobot 6 | paragraph=Easy-to-use and reliable library for DFPlayer Mini 7 | category=Sensors 8 | url=https://github.com/DFRobot/DFRobotDFPlayerMini 9 | architectures=* 10 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | env: 5 | - BOARD=uno 6 | - BOARD=leonardo 7 | - BOARD=esp01 8 | 9 | install: 10 | - python -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)" 11 | 12 | script: 13 | - cd examples/FullFunction 14 | - platformio ci -l ../.. FullFunction.ino --board=$BOARD 15 | - cd ../GetStarted 16 | - platformio ci -l ../.. getStarted.ino --board=$BOARD 17 | 18 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/README.md: -------------------------------------------------------------------------------- 1 | # DFPlayer - A Mini MP3 Player For Arduino 2 | 3 | 4 | DFPlayer - A Mini MP3 Player For Arduino 5 | https://www.dfrobot.com/index.php?route=product/product&product_id=1121 6 | 7 | This example shows the all the function of library for DFPlayer. 8 | 9 | Created 2016-12-07 10 | By [Angelo qiao](Angelo.qiao@dfrobot.com) 11 | 12 | GNU Lesser General Public License. 13 | See for details. 14 | All above must be included in any redistribution 15 | 16 | Notice and Trouble shooting 17 | 18 | 1.Connection and Diagram can be found here 19 | https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram 20 | 2.This code is tested on Arduino Uno, Leonardo, Mega boards. 21 | -------------------------------------------------------------------------------- /dfPlayer/BaseConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | R. J. Tidey 2019/12/30 3 | Basic config 4 | */ 5 | #define FILESYSTYPE 1 6 | 7 | /* 8 | Wifi Manager Web set up 9 | */ 10 | #define WM_NAME "dfPlayer" 11 | #define WM_PASSWORD "password" 12 | 13 | //Update service set up 14 | String host = "dfPlayer"; 15 | const char* update_password = "password"; 16 | 17 | //define actions during setup 18 | //define any call at start of set up 19 | #define SETUP_START 1 20 | //define config file name if used 21 | //#define CONFIG_FILE "/hvFuseConfig.txt" 22 | //set to 1 if SPIFFS or LittleFS used 23 | #define SETUP_FILESYS 1 24 | //define to set up server and reference any extra handlers required 25 | #define SETUP_SERVER 1 26 | //call any extra setup at end 27 | #define SETUP_END 1 28 | 29 | // comment out this define unless using modified WifiManager with fast connect support 30 | #define FASTCONNECT true 31 | 32 | #define AP_AUTHID "12345678" 33 | 34 | //dfPlayer message timeout 35 | #define DFMSG_TIMEOUT 2000 36 | 37 | #include "BaseSupport.h" 38 | -------------------------------------------------------------------------------- /data/basic.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ESP8266 dfPlayer 6 | 9 | 10 | 11 |

dfPlayer

12 |
13 |

14 | Command
15 |
35 | p1 - Folder
36 | p2 - Track
37 | p3 - Extra
38 | 39 |

40 |
41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dfPlayer application for ESP8266 2 | 3 | See schematic for hook up. 4 | Instructable at https://www.instructables.com/id/ESP8266-DfPlayer-Audio-Player/ 5 | 6 | ## Features 7 | - 4 local buttons for standalone use 8 | - mobile browser interface 9 | - Volume 10 | - Play controls 11 | - Folder selection 12 | - Original folder names 13 | - Mute control 14 | - WifiManager for initial set up 15 | - OTA for updates 16 | - File browser for maintenance 17 | - USB support into dfPlayer 18 | - battery monitoring 19 | 20 | ## Basic Web interface (basic.htm) 21 | ### Commands are sent to ip/dfPlayer/cmd with arguments p1,p2,p3 22 | - ?cmd=play&p1=folder&p2=track 23 | - ?cmd=playmp3&p1=track 24 | - ?cmd=volume&p1=level (0-30) 25 | - ?cmd=stop 26 | - ?cmd=volumeup 27 | - ?cmd=volumedown 28 | - ?cmd=speaker&p1=offon (0/1) 29 | - ?cmd=pause 30 | - ?cmd=start 31 | - ?cmd=next 32 | - ?cmd=previous 33 | - ?cmd=mode&p1=type 34 | - ?cmd=loopFolder&p1=folder 35 | - ?cmd=random 36 | - ?cmd=eq&p1=type 37 | - ?cmd=device&p1=type 38 | - ?cmd=setting&p1=folder&p2=track 39 | - ?cmd=sleep 40 | - ?cmd=reset 41 | - ?cmd=raw&p1=cmdcode&p2=par1&p3=par2 42 | - ?cmd=init 43 | 44 | ## Mobile browser interface (/) 45 | - Works using folderMap (see tools) 46 | - Volume slider 47 | - Play controls 48 | - Named folder list 49 | 50 | ## Other web support 51 | - /edit for file browsing and upload 52 | - /upload for simple file upload to bootstrap 53 | - /dfPlayerStatus for basic status info 54 | - /firmware for OTA 55 | 56 | ### Config 57 | - Edit BaseConfig.h 58 | - Wifi Manager set up 59 | - WM_NAME (ssid of wifi manager network) 60 | - WM_PASSWORD (password to connect) 61 | - On start up connect to WM_NAME network and browse to 192.168.4.1 to set up wifi 62 | - update_password 63 | 64 | ### Libraries 65 | - BaseSupport General access routines https://github.com/roberttidey/BaseSupport 66 | - BitMessages Routines to look up and create pulse sequences for a commands 67 | - BitTx Bit bang routines to execute a pulse sequence 68 | - Interrupt driven and supports accurate modulation 69 | - WifiManager 70 | - FS 71 | - DNSServer 72 | - ArduinoJson 73 | - ESP8266mDNS 74 | - ESP8266HTTPUpdateServer 75 | - SoftwareSerial.h 76 | - DFRobotDFPlayerMini.h 77 | - ESP8266WiFi.h 78 | 79 | ### Install procedure 80 | - Normal arduino esp8266 compile and upload 81 | - A simple built in file uploader (/upload) should then be used to upload the base files to SPIFF 82 | edit.htm.gz 83 | index.html (can be changed to refer to different favicon) 84 | favicon*.png 85 | graphs.js.gz 86 | - The /edit operation is then supported to upload basic.htm and SD naming files 87 | 88 | ### Tool for folder / track naming 89 | The dfPlayer uses a very simple folder and track naming scheme 90 | folders are 01 to 99 91 | tracks are 001,002 92 | 93 | To avoid doing tedious renaming and also to support the mobile web interface a vbscript is used 94 | 95 | - Copy normal folders and tracks mp3 to SD card (e.g. album names for folders) 96 | - Run the vbscript and point it at the SD card volume&p1 97 | - Tool will run and in a few seconds will rename all the files 98 | - It will create a file called Folders.txt mapping the renamed folders to their original names 99 | - It will also create a set of Tracks.txt file mapping the tracks to their original names (currently unused) 100 | - The Folders.txt should be uploaded to the ESP8266 via /edit 101 | - Tracks files may also be uploaded. Software may be enhanced to use these at some stage 102 | - SD card can be maintained by deleting folders, adding new named ones and re-running the tool. Renaming will be done on new folders and new map files produced. 103 | 104 | ### Mute 105 | The dfPlayer does not naturally support mute. Volume can be set to 0 but this also mutes the headphone output. 106 | 107 | To get separate speaker mute control a small hardware mod is needed. Replace the 0 Ohm resistor with 10K and solder a mute control onto the pad as shown in the picture in docs. This mute control goes to GPIO16 108 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/examples/GetStarted/getStarted.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | DFPlayer - A Mini MP3 Player For Arduino 3 | 4 | 5 | *************************************************** 6 | This example shows the basic function of library for DFPlayer. 7 | 8 | Created 2014-8-28 9 | By [Angelo qiao](Angelo.qiao@dfrobot.com) 10 | 11 | GNU Lesser General Public License. 12 | See for details. 13 | All above must be included in any redistribution 14 | ****************************************************/ 15 | 16 | /***********Notice and Trouble shooting*************** 17 | 1.Connection and Diagram can be found here 18 | <> 19 | 2.This code is tested on Arduino Uno, Leonardo, Mega boards. 20 | ****************************************************/ 21 | 22 | #include "Arduino.h" 23 | #include "SoftwareSerial.h" 24 | #include "DFRobotDFPlayerMini.h" 25 | 26 | SoftwareSerial mySoftwareSerial(10, 11); // RX, TX 27 | DFRobotDFPlayerMini myDFPlayer; 28 | void printDetail(uint8_t type, int value); 29 | 30 | void setup() 31 | { 32 | mySoftwareSerial.begin(9600); 33 | Serial.begin(115200); 34 | 35 | Serial.println(); 36 | Serial.println(F("DFRobot DFPlayer Mini Demo")); 37 | Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); 38 | 39 | if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. 40 | Serial.println(F("Unable to begin:")); 41 | Serial.println(F("1.Please recheck the connection!")); 42 | Serial.println(F("2.Please insert the SD card!")); 43 | while(true){ 44 | delay(0); // Code to compatible with ESP8266 watch dog. 45 | } 46 | } 47 | Serial.println(F("DFPlayer Mini online.")); 48 | 49 | myDFPlayer.volume(10); //Set volume value. From 0 to 30 50 | myDFPlayer.play(1); //Play the first mp3 51 | } 52 | 53 | void loop() 54 | { 55 | static unsigned long timer = millis(); 56 | 57 | if (millis() - timer > 3000) { 58 | timer = millis(); 59 | myDFPlayer.next(); //Play next mp3 every 3 second. 60 | } 61 | 62 | if (myDFPlayer.available()) { 63 | printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. 64 | } 65 | } 66 | 67 | void printDetail(uint8_t type, int value){ 68 | switch (type) { 69 | case TimeOut: 70 | Serial.println(F("Time Out!")); 71 | break; 72 | case WrongStack: 73 | Serial.println(F("Stack Wrong!")); 74 | break; 75 | case DFPlayerCardInserted: 76 | Serial.println(F("Card Inserted!")); 77 | break; 78 | case DFPlayerCardRemoved: 79 | Serial.println(F("Card Removed!")); 80 | break; 81 | case DFPlayerCardOnline: 82 | Serial.println(F("Card Online!")); 83 | break; 84 | case DFPlayerPlayFinished: 85 | Serial.print(F("Number:")); 86 | Serial.print(value); 87 | Serial.println(F(" Play Finished!")); 88 | break; 89 | case DFPlayerError: 90 | Serial.print(F("DFPlayerError:")); 91 | switch (value) { 92 | case Busy: 93 | Serial.println(F("Card not found")); 94 | break; 95 | case Sleeping: 96 | Serial.println(F("Sleeping")); 97 | break; 98 | case SerialWrongStack: 99 | Serial.println(F("Get Wrong Stack")); 100 | break; 101 | case CheckSumNotMatch: 102 | Serial.println(F("Check Sum Not Match")); 103 | break; 104 | case FileIndexOut: 105 | Serial.println(F("File Index Out of Bound")); 106 | break; 107 | case FileMismatch: 108 | Serial.println(F("Cannot Find File")); 109 | break; 110 | case Advertise: 111 | Serial.println(F("In Advertise")); 112 | break; 113 | default: 114 | break; 115 | } 116 | break; 117 | default: 118 | break; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/DFRobotDFPlayerMini.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DFRobotDFPlayerMini.h 3 | * @brief DFPlayer - An Arduino Mini MP3 Player From DFRobot 4 | * @n Header file for DFRobot's DFPlayer 5 | * 6 | * @copyright [DFRobot]( http://www.dfrobot.com ), 2016 7 | * @copyright GNU Lesser General Public License 8 | * 9 | * @author [Angelo](Angelo.qiao@dfrobot.com) 10 | * @version V1.0 11 | * @date 2016-12-07 12 | */ 13 | 14 | #include "Arduino.h" 15 | 16 | #ifndef DFRobotDFPlayerMini_cpp 17 | #define DFRobotDFPlayerMini_cpp 18 | 19 | 20 | #define DFPLAYER_EQ_NORMAL 0 21 | #define DFPLAYER_EQ_POP 1 22 | #define DFPLAYER_EQ_ROCK 2 23 | #define DFPLAYER_EQ_JAZZ 3 24 | #define DFPLAYER_EQ_CLASSIC 4 25 | #define DFPLAYER_EQ_BASS 5 26 | 27 | #define DFPLAYER_DEVICE_U_DISK 1 28 | #define DFPLAYER_DEVICE_SD 2 29 | #define DFPLAYER_DEVICE_AUX 3 30 | #define DFPLAYER_DEVICE_SLEEP 4 31 | #define DFPLAYER_DEVICE_FLASH 5 32 | 33 | #define DFPLAYER_RECEIVED_LENGTH 10 34 | #define DFPLAYER_SEND_LENGTH 10 35 | 36 | //#define _DEBUG 37 | 38 | #define TimeOut 0 39 | #define WrongStack 1 40 | #define DFPlayerCardInserted 2 41 | #define DFPlayerCardRemoved 3 42 | #define DFPlayerCardOnline 4 43 | #define DFPlayerPlayFinished 5 44 | #define DFPlayerError 6 45 | 46 | #define Busy 1 47 | #define Sleeping 2 48 | #define SerialWrongStack 3 49 | #define CheckSumNotMatch 4 50 | #define FileIndexOut 5 51 | #define FileMismatch 6 52 | #define Advertise 7 53 | 54 | #define Stack_Header 0 55 | #define Stack_Version 1 56 | #define Stack_Length 2 57 | #define Stack_Command 3 58 | #define Stack_ACK 4 59 | #define Stack_Parameter 5 60 | #define Stack_CheckSum 7 61 | #define Stack_End 9 62 | 63 | class DFRobotDFPlayerMini { 64 | Stream* _serial; 65 | 66 | unsigned long _timeOutTimer; 67 | unsigned long _timeOutDuration = 500; 68 | 69 | uint8_t _received[DFPLAYER_RECEIVED_LENGTH]; 70 | uint8_t _sending[DFPLAYER_SEND_LENGTH] = {0x7E, 0xFF, 06, 00, 01, 00, 00, 00, 00, 0xEF}; 71 | 72 | uint8_t _receivedIndex=0; 73 | 74 | void sendStack(); 75 | void sendStack(uint8_t command); 76 | void sendStack(uint8_t command, uint16_t argument); 77 | 78 | void enableACK(); 79 | void disableACK(); 80 | 81 | void uint16ToArray(uint16_t value,uint8_t *array); 82 | 83 | uint16_t arrayToUint16(uint8_t *array); 84 | 85 | uint16_t calculateCheckSum(uint8_t *buffer); 86 | 87 | 88 | 89 | void parseStack(); 90 | bool validateStack(); 91 | 92 | uint8_t device = DFPLAYER_DEVICE_SD; 93 | 94 | public: 95 | 96 | uint8_t _handleType; 97 | uint8_t _handleCommand; 98 | uint16_t _handleParameter; 99 | bool _isAvailable = false; 100 | bool _isSending = false; 101 | 102 | bool handleMessage(uint8_t type, uint16_t parameter = 0); 103 | bool handleError(uint8_t type, uint16_t parameter = 0); 104 | 105 | uint8_t readCommand(); 106 | 107 | bool begin(Stream& stream, bool isACK = true, bool doReset = true); 108 | 109 | bool waitAvailable(); 110 | 111 | bool available(); 112 | 113 | uint8_t readType(); 114 | 115 | uint16_t read(); 116 | 117 | void setTimeOut(unsigned long timeOutDuration); 118 | 119 | void sendStack(uint8_t command, uint8_t argumentHigh, uint8_t argumentLow); 120 | 121 | void next(); 122 | 123 | void previous(); 124 | 125 | void play(int fileNumber=1); 126 | 127 | void volumeUp(); 128 | 129 | void volumeDown(); 130 | 131 | void volume(uint8_t volume); 132 | 133 | void EQ(uint8_t eq); 134 | 135 | void loop(int fileNumber); 136 | 137 | void outputDevice(uint8_t device); 138 | 139 | void sleep(); 140 | 141 | void reset(); 142 | 143 | void start(); 144 | 145 | void pause(); 146 | 147 | void playFolder(uint8_t folderNumber, uint8_t fileNumber); 148 | 149 | void outputSetting(bool enable, uint8_t gain); 150 | 151 | void enableLoopAll(); 152 | 153 | void disableLoopAll(); 154 | 155 | void playMp3Folder(int fileNumber); 156 | 157 | void advertise(int fileNumber); 158 | 159 | void playLargeFolder(uint8_t folderNumber, uint16_t fileNumber); 160 | 161 | void stopAdvertise(); 162 | 163 | void stop(); 164 | 165 | void loopFolder(int folderNumber); 166 | 167 | void randomAll(); 168 | 169 | void enableLoop(); 170 | 171 | void disableLoop(); 172 | 173 | void enableDAC(); 174 | 175 | void disableDAC(); 176 | 177 | int readState(); 178 | 179 | int readVolume(); 180 | 181 | uint8_t readEQ(); 182 | 183 | int readFileCounts(uint8_t device); 184 | 185 | int readCurrentFileNumber(uint8_t device); 186 | 187 | int readFileCountsInFolder(int folderNumber); 188 | 189 | int readFileCounts(); 190 | 191 | int readFolderCounts(); 192 | 193 | int readCurrentFileNumber(); 194 | 195 | }; 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/examples/FullFunction/FullFunction.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | DFPlayer - A Mini MP3 Player For Arduino 3 | 4 | 5 | *************************************************** 6 | This example shows the all the function of library for DFPlayer. 7 | 8 | Created 2016-12-07 9 | By [Angelo qiao](Angelo.qiao@dfrobot.com) 10 | 11 | GNU Lesser General Public License. 12 | See for details. 13 | All above must be included in any redistribution 14 | ****************************************************/ 15 | 16 | /***********Notice and Trouble shooting*************** 17 | 1.Connection and Diagram can be found here 18 | 19 | 2.This code is tested on Arduino Uno, Leonardo, Mega boards. 20 | ****************************************************/ 21 | 22 | #include "Arduino.h" 23 | #include "SoftwareSerial.h" 24 | #include "DFRobotDFPlayerMini.h" 25 | 26 | SoftwareSerial mySoftwareSerial(10, 11); // RX, TX 27 | DFRobotDFPlayerMini myDFPlayer; 28 | void printDetail(uint8_t type, int value); 29 | 30 | void setup() 31 | { 32 | mySoftwareSerial.begin(9600); 33 | Serial.begin(115200); 34 | 35 | Serial.println(); 36 | Serial.println(F("DFRobot DFPlayer Mini Demo")); 37 | Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); 38 | 39 | if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. 40 | Serial.println(F("Unable to begin:")); 41 | Serial.println(F("1.Please recheck the connection!")); 42 | Serial.println(F("2.Please insert the SD card!")); 43 | while(true); 44 | } 45 | Serial.println(F("DFPlayer Mini online.")); 46 | 47 | myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms 48 | 49 | //----Set volume---- 50 | myDFPlayer.volume(10); //Set volume value (0~30). 51 | myDFPlayer.volumeUp(); //Volume Up 52 | myDFPlayer.volumeDown(); //Volume Down 53 | 54 | //----Set different EQ---- 55 | myDFPlayer.EQ(DFPLAYER_EQ_NORMAL); 56 | // myDFPlayer.EQ(DFPLAYER_EQ_POP); 57 | // myDFPlayer.EQ(DFPLAYER_EQ_ROCK); 58 | // myDFPlayer.EQ(DFPLAYER_EQ_JAZZ); 59 | // myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC); 60 | // myDFPlayer.EQ(DFPLAYER_EQ_BASS); 61 | 62 | //----Set device we use SD as default---- 63 | // myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK); 64 | myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD); 65 | // myDFPlayer.outputDevice(DFPLAYER_DEVICE_AUX); 66 | // myDFPlayer.outputDevice(DFPLAYER_DEVICE_SLEEP); 67 | // myDFPlayer.outputDevice(DFPLAYER_DEVICE_FLASH); 68 | 69 | //----Mp3 control---- 70 | // myDFPlayer.sleep(); //sleep 71 | // myDFPlayer.reset(); //Reset the module 72 | // myDFPlayer.enableDAC(); //Enable On-chip DAC 73 | // myDFPlayer.disableDAC(); //Disable On-chip DAC 74 | // myDFPlayer.outputSetting(true, 15); //output setting, enable the output and set the gain to 15 75 | 76 | //----Mp3 play---- 77 | myDFPlayer.next(); //Play next mp3 78 | delay(1000); 79 | myDFPlayer.previous(); //Play previous mp3 80 | delay(1000); 81 | myDFPlayer.play(1); //Play the first mp3 82 | delay(1000); 83 | myDFPlayer.loop(1); //Loop the first mp3 84 | delay(1000); 85 | myDFPlayer.pause(); //pause the mp3 86 | delay(1000); 87 | myDFPlayer.start(); //start the mp3 from the pause 88 | delay(1000); 89 | myDFPlayer.playFolder(15, 4); //play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255) 90 | delay(1000); 91 | myDFPlayer.enableLoopAll(); //loop all mp3 files. 92 | delay(1000); 93 | myDFPlayer.disableLoopAll(); //stop loop all mp3 files. 94 | delay(1000); 95 | myDFPlayer.playMp3Folder(4); //play specific mp3 in SD:/MP3/0004.mp3; File Name(0~65535) 96 | delay(1000); 97 | myDFPlayer.advertise(3); //advertise specific mp3 in SD:/ADVERT/0003.mp3; File Name(0~65535) 98 | delay(1000); 99 | myDFPlayer.stopAdvertise(); //stop advertise 100 | delay(1000); 101 | myDFPlayer.playLargeFolder(2, 999); //play specific mp3 in SD:/02/004.mp3; Folder Name(1~10); File Name(1~1000) 102 | delay(1000); 103 | myDFPlayer.loopFolder(5); //loop all mp3 files in folder SD:/05. 104 | delay(1000); 105 | myDFPlayer.randomAll(); //Random play all the mp3. 106 | delay(1000); 107 | myDFPlayer.enableLoop(); //enable loop. 108 | delay(1000); 109 | myDFPlayer.disableLoop(); //disable loop. 110 | delay(1000); 111 | 112 | //----Read imformation---- 113 | Serial.println(myDFPlayer.readState()); //read mp3 state 114 | Serial.println(myDFPlayer.readVolume()); //read current volume 115 | Serial.println(myDFPlayer.readEQ()); //read EQ setting 116 | Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card 117 | Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number 118 | Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read fill counts in folder SD:/03 119 | } 120 | 121 | void loop() 122 | { 123 | static unsigned long timer = millis(); 124 | 125 | if (millis() - timer > 3000) { 126 | timer = millis(); 127 | myDFPlayer.next(); //Play next mp3 every 3 second. 128 | } 129 | 130 | if (myDFPlayer.available()) { 131 | printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. 132 | } 133 | } 134 | 135 | void printDetail(uint8_t type, int value){ 136 | switch (type) { 137 | case TimeOut: 138 | Serial.println(F("Time Out!")); 139 | break; 140 | case WrongStack: 141 | Serial.println(F("Stack Wrong!")); 142 | break; 143 | case DFPlayerCardInserted: 144 | Serial.println(F("Card Inserted!")); 145 | break; 146 | case DFPlayerCardRemoved: 147 | Serial.println(F("Card Removed!")); 148 | break; 149 | case DFPlayerCardOnline: 150 | Serial.println(F("Card Online!")); 151 | break; 152 | case DFPlayerPlayFinished: 153 | Serial.print(F("Number:")); 154 | Serial.print(value); 155 | Serial.println(F(" Play Finished!")); 156 | break; 157 | case DFPlayerError: 158 | Serial.print(F("DFPlayerError:")); 159 | switch (value) { 160 | case Busy: 161 | Serial.println(F("Card not found")); 162 | break; 163 | case Sleeping: 164 | Serial.println(F("Sleeping")); 165 | break; 166 | case SerialWrongStack: 167 | Serial.println(F("Get Wrong Stack")); 168 | break; 169 | case CheckSumNotMatch: 170 | Serial.println(F("Check Sum Not Match")); 171 | break; 172 | case FileIndexOut: 173 | Serial.println(F("File Index Out of Bound")); 174 | break; 175 | case FileMismatch: 176 | Serial.println(F("Cannot Find File")); 177 | break; 178 | case Advertise: 179 | Serial.println(F("In Advertise")); 180 | break; 181 | default: 182 | break; 183 | } 184 | break; 185 | default: 186 | break; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /data/index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PlayerGreen 14 | 15 | 16 | 17 |
18 | battery_std 19 | 50% 20 |
Mp3 Player ESP
21 |
22 |
23 |
24 | Loading folders... 25 |
26 |
27 | 85 | 86 | 87 | 129 | 130 | 131 | 132 | 133 | 253 | 254 | -------------------------------------------------------------------------------- /tools/dfPlayer-makeSD.vbs: -------------------------------------------------------------------------------- 1 | Option Explicit 2 | 'SD Processor for dfPlayer - Bob Tidey v1 2o Feb 2018 3 | 'This script checks a SD and renames folders and tracks to be compatible with dfPlayer 4 | 'It also maintains Folders.txt file which keeps the original folder name to dfPlayer map 5 | 'Each folder has a Tracks.txt which keeps the original folderName and the original track names to dfPlayer map 6 | 7 | Const SD = "I:\" 8 | Const FOLDERS_FILE = "Folders.txt" 9 | Const TRACKS_FILE = "Tracks.txt" 10 | Const LOGFILENAME = "dfPlayerMakeSDLog.txt" 11 | Const vbCOMMA = "," 12 | Const vbCOLON = ":" 13 | Const MP3_EXT = ".mp3" 14 | Const forReading = 1 15 | Const forWriting = 2 16 | Const forAppending = 8 17 | 18 | 19 | '****************************** 20 | 'Main Script Code goes here 21 | '****************************** 22 | Dim fso 23 | Dim sdRoot 24 | Dim MainFolder 25 | Dim sFolders 26 | Dim nextFree 27 | Dim skipped 28 | Dim eFile 29 | Dim existingFolders 30 | Dim ScriptPath 31 | Dim ScriptTime 32 | Dim Logging 33 | 34 | Set fso = CreateObject("Scripting.FileSystemObject") 35 | InitLogging 36 | ScriptTime = Timer() 37 | sdRoot = InputBox("SD Root","dfPlayer-MakeSD",SD) 38 | If Not Right(sdRoot,1) = "\" Then 39 | sdRoot = sdRoot & "\" 40 | End If 41 | Set MainFolder = fso.GetFolder(sdRoot) 42 | Set sFolders = MainFolder.SubFolders 43 | WriteLog "Start SD Process" 44 | nextFree = "00" 45 | skipped = False 46 | existingFolders = "" 47 | If fso.FileExists(MainFolder.Path & "\" & FOLDERS_FILE & ".bak") Then 48 | WriteLog "Delete old backup " & MainFolder.Path & "\" & FOLDERS_FILE & ".bak" 49 | fso.DeleteFile MainFolder.Path & "\" & FOLDERS_FILE & ".bak" 50 | End If 51 | If fso.FileExists(MainFolder.Path & "\" & FOLDERS_FILE) Then 52 | Set eFile = fso.OpenTextFile(MainFolder.Path & "\" & FOLDERS_FILE, forReading) 53 | existingFolders = eFile.ReadAll() 54 | eFile.Close 55 | WriteLog "Backup " & MainFolder.Path & "\" & FOLDERS_FILE 56 | fso.MoveFile MainFolder.Path & "\" & FOLDERS_FILE, MainFolder.Path & "\" & FOLDERS_FILE & ".bak" 57 | End If 58 | ProcessFolders 59 | UpdateFolders 60 | If Not skipped Then 61 | MsgBox "Finished OK",0, "dfPlayer-MakeSD" 62 | Else 63 | MsgBox "Skipped some folders",0, "dfPlayer-MakeSD" 64 | End If 65 | 66 | 'End of Main Script 67 | 68 | '******************************************* 69 | 'Sub Routines and Function calls follow here 70 | '******************************************* 71 | 72 | '********************************************************************** 73 | 'Routine to process folders 74 | '********************************************************************** 75 | Sub ProcessFolders() 76 | Dim sFolder 77 | WriteLog "Process Folders" 78 | For Each sFolder in sFolders 79 | ProcessFolder sFolder 80 | Next 81 | 82 | End Sub 83 | 84 | '********************************************************************** 85 | 'Routine to rename folders 86 | '********************************************************************** 87 | Sub UpdateFolders() 88 | Dim fFile 89 | Dim iLine 90 | Dim fNewName 91 | Dim fName 92 | Dim Index 93 | 94 | WriteLog "Update Folder Names" 95 | Set fFile = fso.OpenTextFile(MainFolder.Path & "\" & FOLDERS_FILE, forReading) 96 | Do While Not fFile.AtEndofStream 97 | iLine = fFile.ReadLine 98 | Index = 0 99 | If Len(iLIne) > 0 Then 100 | fNewName = Split(iLine,vbCOLON)(0) 101 | fName = Split(iLine, vbCOLON)(1) 102 | If fso.FolderExists(MainFolder.Path & "\" & fName) And Not fso.FolderExists(MainFolder.Path & "\" & fNewName) Then 103 | Index = Index + 1 104 | WriteLog "Rename Folder " & fName & " to " & fNewName 105 | fso.MoveFolder MainFolder.Path & "\" & fName, MainFolder.Path & "\" & fNewName 106 | End If 107 | End If 108 | Loop 109 | fFile.Close 110 | If Index > 0 Then 111 | WriteLog "Updated " & Index & " Folder Names" 112 | End If 113 | 114 | End Sub 115 | 116 | '********************************************************************** 117 | 'Routine to process a single folder 118 | '********************************************************************** 119 | Sub ProcessFolder(sFolder) 120 | Dim f 121 | Dim fs 122 | Dim fFile 123 | Dim fNumber 124 | Dim fNames 125 | Dim fName 126 | Dim Index 127 | Dim iLine 128 | 129 | 'Only process folders that are new 130 | If Len(sFolder.Name) = 2 And isNumeric(sFolder.Name) And fso.FileExists(sFolder.Path & "\" & TRACKS_FILE) Then 131 | WriteLog sFolder.Name & " already processed folder" 132 | Set fFile = fso.OpenTextFile(sFolder.Path & "\" & TRACKS_FILE, forReading) 133 | iLine = fFile.ReadLine 134 | fName = Split(iLine, vbCOLON)(1) 135 | fFile.Close 136 | Set fFile = fso.OpenTextFile(MainFolder.Path & "\" & FOLDERS_FILE, forAppending, True) 137 | fFile.WriteLine sFolder.Name & vbCOLON & fName 138 | fFile.Close 139 | Else 140 | Index = 0 141 | WriteLog "Processing " & sFolder.Name 142 | If Instr(existingFolders, sFolder.Name) > 0 Then 143 | WriteLog "Folder already exists; skipping this one" 144 | Else 145 | If fso.FolderExists(sFolder.Path & "\" & TRACKS_FILE) Then 146 | WriteLog "Tracks file already exists; using that" 147 | Index = 99 148 | Else 149 | Set fNames = CreateObject("System.Collections.ArrayList") 150 | For Each f in sFolder.Files 151 | fNames.Add f.Name 152 | Next 153 | fNames.Sort() 154 | For Each fName in fNames 155 | If lCase(Right(fName,4)) = MP3_EXT Then 156 | If Index = 0 Then 157 | Index = 1 158 | Set fFile = fso.CreateTextFile(sFolder.Path & "\" & TRACKS_FILE, True) 159 | fFile.WriteLine("Title" & vbCOLON & sFolder.Name) 160 | Else 161 | Index = Index + 1 162 | End If 163 | fFile.WriteLine(Right("00" & Index, 3) & vbCOLON & fName) 164 | End If 165 | Next 166 | End If 167 | End If 168 | If Index > 0 Then 169 | fFile.Close 170 | WriteLog Index & " MP3 files found " 171 | findNextFree 172 | If Not nextFree = "NONE" Then 173 | WriteLog "Will use Folder " & nextFree 174 | Set fFile = fso.OpenTextFile(MainFolder.Path & "\" & FOLDERS_FILE, forAppending, True) 175 | fFile.WriteLine nextFree & vbCOLON & sFolder.Name 176 | fFile.Close 177 | Set fFile = fso.OpenTextFile(sFolder.Path & "\" & TRACKS_FILE, forReading) 178 | Index = 0 179 | 'Discard folder name 180 | iLine = fFile.ReadLine 181 | Do While Not fFile.AtEndofStream 182 | Index = Index + 1 183 | iLine = fFile.ReadLine 184 | fNumber = Split(iLine, vbCOLON)(0) 185 | fName = Split(iLine, vbCOLON)(1) 186 | If Len(fName) > 0 Then 187 | fso.MoveFile sFolder.Path & "\" & fName, sFolder.Path & "\" & fNumber & MP3_EXT 188 | End If 189 | Loop 190 | WriteLog "Renamed " & Index & " files" 191 | fFile.Close 192 | If fso.FileExists(MainFolder.Path & "\" & nextFree & "-" & TRACKS_FILE) Then 193 | fso.DeleteFile MainFolder.Path & "\" & nextFree & "-" & TRACKS_FILE 194 | End If 195 | fso.CopyFile sFolder.Path & "\" & TRACKS_FILE, MainFolder.Path & "\" & nextFree & "-" & TRACKS_FILE 196 | Else 197 | WriteLog "Folder skipped - No free slots" 198 | skipped = True 199 | End If 200 | End If 201 | End If 202 | End Sub 203 | 204 | '********************************************************************** 205 | 'Routine to find nextFree FolderNumber 206 | '********************************************************************** 207 | Sub findNextFree() 208 | Dim Index 209 | 210 | Index = 100 211 | If Not nextFree = "NONE" Then 212 | WriteLog "Find next from " & nextFree + 1 213 | For Index = CInt(nextFree) + 1 To 99 214 | If Not fso.FolderExists(MainFolder.Path & "\" & Right("0" & Index, 2)) Then 215 | Exit For 216 | End If 217 | Next 218 | WriteLog "Found next " & Index 219 | End If 220 | If Index > 99 Then 221 | nextFree = "NONE" 222 | Else 223 | nextFree = Right("0" & Index, 2) 224 | End If 225 | End Sub 226 | 227 | '****************************************************************** 228 | 'Sub to init the logging function 229 | '****************************************************************** 230 | Sub InitLogging() 231 | ScriptPath = fso.GetParentFolderName(WScript.ScriptFullName) 232 | Logging = 1 233 | End Sub 234 | 235 | '****************************************************************** 236 | 'Sub to write a log line 237 | '****************************************************************** 238 | Sub WriteLog(Msg) 239 | Const RETRY_MAX = 5 240 | Const RETRY_INTERVAL = 1000 'Milliseconds 241 | Dim logFile 242 | Dim RetryCount 243 | 244 | If Logging <> 0 Then 245 | For RetryCount = 1 To RETRY_MAX 246 | On Error Resume Next 247 | Err.Clear 248 | Set logFile = fso.OpenTextFile(ScriptPath & "\" & LOGFILENAME, forAppending, True) 249 | If Err.Number = 0 Then 250 | logFile.WriteLine Now() & vbCOMMA & CStr(Round(Timer() - ScriptTime, 3)) & vbCOMMA & Msg 251 | logFile.Close 252 | Exit For 253 | End If 254 | WScript.sleep RETRY_INTERVAL 255 | Next 256 | End If 257 | End Sub 258 | -------------------------------------------------------------------------------- /dfPlayer/dfPlayer.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | dfPlayer - A Mini MP3 Player for ESP8266 3 | R.J.Tidey March 2018 4 | ****************************************************/ 5 | #define ESP8266 6 | #include "BaseConfig.h" 7 | #include "SoftwareSerial.h" 8 | #include "DFRobotDFPlayerMini.h" 9 | 10 | int timeInterval = 25; 11 | unsigned long elapsedTime; 12 | 13 | SoftwareSerial mySoftwareSerial(5, 15); // RX, TX 14 | DFRobotDFPlayerMini myDFPlayer; 15 | #define INIT_SKIP -1 16 | #define INIT_START 0 17 | #define INIT_DELAY 1 18 | #define INIT_OK1 2 19 | #define INIT_OK2 3 20 | #define INIT_RUN 4 21 | 22 | int dfPlayerInit = INIT_START; 23 | int dfPlayerType; 24 | int dfPlayerParameter; 25 | 26 | int pinInputs[4] = {4,12,13,14}; 27 | int pinStates[4]; 28 | unsigned long pinTimes[4]; 29 | int pinChanges[4]; 30 | int muteState; 31 | unsigned long pinTimers[4]; 32 | //delay initalising dfPlayer module after power on (mSec) 33 | #define DFPLAYER_STARTUP 4000 34 | #define VOLUP 0 35 | #define VOLDOWN 1 36 | #define SELECT1 2 37 | #define SELECT2 3 38 | #define MUTE 16 39 | #define LONG_PRESS 1000 40 | 41 | int folderSelect = 1; 42 | int fileSelect = 1; 43 | int volume = 15; 44 | String cmd; 45 | String folderMap[100]; 46 | unsigned long resetPeriod; 47 | 48 | //only check battery every 10th loop 49 | #define BATTERY_DIVIDER 10 50 | float ADC_CAL = 0.976; 51 | float battery_mult = 57.0/10.0/1024;//resistor divider, vref, max count 52 | float battery_volts = 4.2; 53 | int batteryCounter = 0; 54 | 55 | void init_dfPlayer() { 56 | Serial.println(); 57 | Serial.println(F("Initializing DFPlayer ... (May take 2 seconds)")); 58 | 59 | //Use softwareSerial to communicate with mp3. 60 | //Extend timeout for getting reset message back (typically takes 1 second) 61 | myDFPlayer.setTimeOut(DFMSG_TIMEOUT); 62 | resetPeriod = millis(); 63 | if (myDFPlayer.begin(mySoftwareSerial)) { 64 | dfPlayerInit = INIT_OK1; 65 | Serial.print(F("DFPlayer Mini online.")); 66 | } else { 67 | dfPlayerInit = INIT_OK2; 68 | Serial.print(F("DFPlayer Mini offline.")); 69 | } 70 | resetPeriod = millis() - resetPeriod; 71 | Serial.println(" Reset period:" + String(resetPeriod)); 72 | } 73 | 74 | void readFolders() { 75 | if(SPIFFS.exists("/Folders.txt")) { 76 | File f = SPIFFS.open("/Folders.txt", "r"); 77 | int Index = 0; 78 | String temp; 79 | while( f.available()) { 80 | temp =f.readStringUntil(10); 81 | temp.replace("\r",""); 82 | temp.toLowerCase(); 83 | Index = temp.substring(0,2).toInt(); 84 | folderMap[Index] = temp.substring(3); 85 | } 86 | f.close(); 87 | } 88 | } 89 | 90 | void getFolder(String folderSearch) { 91 | if(folderSearch.length() < 3) { 92 | folderSelect = folderSearch.toInt(); 93 | } else { 94 | int Index; 95 | String temp; 96 | folderSearch.toLowerCase(); 97 | for(Index = 99; Index > 0;Index--) { 98 | if(folderMap[Index].indexOf(folderSearch)>=0) { 99 | folderSelect = Index; 100 | break; 101 | } 102 | } 103 | } 104 | if(folderSelect < 1 || folderSelect > 99) folderSelect = 0; 105 | } 106 | 107 | void dfPlayerSetVolume(int vol) { 108 | if(vol > 30) vol = 30; 109 | if(vol < 0) vol = 0; 110 | if(vol != volume) { 111 | volume = vol; 112 | myDFPlayer.volume(volume); 113 | saveConfig(); 114 | } 115 | } 116 | 117 | void dfPlayerCmd() { 118 | cmd = server.arg("cmd"); 119 | int p1 = server.arg("p1").toInt(); 120 | int p2 = server.arg("p2").toInt(); 121 | int p3 = server.arg("p3").toInt(); 122 | server.send(200, "text/html", F("dfPlayer cmd being processed")); 123 | Serial.print(cmd);Serial.printf(" p1=%d p2=%d\r\n",p1,p2); 124 | 125 | if(dfPlayerInit != INIT_RUN && dfPlayerInit >= INIT_OK1) { 126 | myDFPlayer.volume(volume); 127 | dfPlayerInit = INIT_RUN; 128 | delaymSec(500); 129 | } 130 | 131 | if(cmd.equalsIgnoreCase("play")) { 132 | getFolder(server.arg("p1")); 133 | if(folderSelect > 0) { 134 | myDFPlayer.playFolder(folderSelect, p2); 135 | } 136 | } else if(cmd.equalsIgnoreCase("playmp3")) { 137 | myDFPlayer.playMp3Folder(p1); 138 | } else if(cmd.equalsIgnoreCase("volume")) { 139 | dfPlayerSetVolume(p1); 140 | } else if(cmd.equalsIgnoreCase("stop")) { 141 | myDFPlayer.stop(); 142 | } else if(cmd.equalsIgnoreCase("volumeup")) { 143 | dfPlayerSetVolume(volume+1); 144 | } else if(cmd.equalsIgnoreCase("volumedown")) { 145 | dfPlayerSetVolume(volume-1); 146 | } else if(cmd.equalsIgnoreCase("speaker")) { 147 | p1 = p1 ? 0 : 1; 148 | digitalWrite(MUTE, p1); 149 | muteState = p1; 150 | saveConfig(); 151 | } else if(cmd.equalsIgnoreCase("pause")) { 152 | myDFPlayer.pause(); 153 | } else if(cmd.equalsIgnoreCase("start")) { 154 | myDFPlayer.start(); 155 | } else if(cmd.equalsIgnoreCase("next")) { 156 | myDFPlayer.next(); 157 | } else if(cmd.equalsIgnoreCase("previous")) { 158 | myDFPlayer.previous(); 159 | } else if(cmd.equalsIgnoreCase("mode")) { 160 | myDFPlayer.loop(p1); 161 | } else if(cmd.equalsIgnoreCase("loopFolder")) { 162 | getFolder(server.arg("p1")); 163 | if(folderSelect > 0) { 164 | myDFPlayer.loopFolder(folderSelect); 165 | } 166 | } else if(cmd.equalsIgnoreCase("random")) { 167 | myDFPlayer.randomAll(); 168 | } else if(cmd.equalsIgnoreCase("eq")) { 169 | myDFPlayer.EQ(p1); 170 | } else if(cmd.equalsIgnoreCase("device")) { 171 | myDFPlayer.outputDevice(p1); 172 | } else if(cmd.equalsIgnoreCase("setting")) { 173 | myDFPlayer.outputSetting(p1,p2); 174 | } else if(cmd.equalsIgnoreCase("sleep")) { 175 | myDFPlayer.sleep(); 176 | } else if(cmd.equalsIgnoreCase("reset")) { 177 | myDFPlayer.reset(); 178 | // needs sendStack public in library 179 | //} else if(cmd.equalsIgnoreCase("raw")) { 180 | // myDFPlayer.sendStack(p1,p2,p3); 181 | } else if(cmd.equalsIgnoreCase("init")) { 182 | init_dfPlayer(); 183 | } 184 | } 185 | 186 | void dfPlayerStatus() { 187 | String response; 188 | int i; 189 | 190 | response = "Init:" + String(dfPlayerInit); 191 | for(i=0;i<4;i++) { 192 | response += "
Button" + String(i) + ":" + String(pinStates[i]); 193 | } 194 | response += "
Battery:" + String(battery_volts); 195 | response += "
Volume:" + String(volume); 196 | response += "
Mute:" + String(muteState); 197 | response += "
Folder:" + String(folderSelect) + "," + folderMap[folderSelect] + "
"; 198 | response += "
dfPlayercmd:" + cmd; 199 | server.send(200, "text/html", response); 200 | } 201 | 202 | void dfPlayerTest() { 203 | String response = "Test"; 204 | 205 | response += "
Available:" + String(myDFPlayer.available()); 206 | response += "
_handleType:" + String(myDFPlayer._handleType); 207 | response += "
_handleCommand:" + String(myDFPlayer._handleCommand); 208 | response += "
_handleParameter:" + String(myDFPlayer._handleParameter); 209 | response += "
_isAvailable:" + String(myDFPlayer._isAvailable); 210 | response += "
_isSending:" + String(myDFPlayer._isSending); 211 | response += "
resetPeriod:" + String(resetPeriod) + "
"; 212 | server.send(200, "text/html", response); 213 | } 214 | 215 | bool dfPlayerFinished() { 216 | myDFPlayer.available(); 217 | return (myDFPlayer._handleCommand == 61); 218 | } 219 | 220 | int checkButtons() { 221 | int i; 222 | int pin; 223 | unsigned long period; 224 | int changed = 0; 225 | 226 | for(i=0; i<4;i++) { 227 | pin = digitalRead(pinInputs[i]); 228 | if(pin == 0 && pinStates[i] == 1){ 229 | pinTimes[i] = elapsedTime; 230 | } else if(pin == 1 && (pinStates[i] == 0)) { 231 | changed = 1; 232 | period = (elapsedTime - pinTimes[i]) * timeInterval; 233 | pinChanges[i] = (period>LONG_PRESS) ? 2:1; 234 | } 235 | pinStates[i] = pin; 236 | } 237 | return changed; 238 | } 239 | 240 | void processButtons() { 241 | if(pinChanges[VOLUP] == 2) { 242 | digitalWrite(MUTE, 0); 243 | muteState = 0; 244 | saveConfig(); 245 | pinChanges[VOLUP] = 0; 246 | } else if (pinChanges[VOLUP] == 1) { 247 | dfPlayerSetVolume(volume+1); 248 | pinChanges[VOLUP] = 0; 249 | } else if (pinChanges[VOLDOWN] == 2) { 250 | digitalWrite(MUTE, 1); 251 | muteState = 1; 252 | saveConfig(); 253 | pinChanges[VOLDOWN] = 0; 254 | } else if (pinChanges[VOLDOWN] == 1) { 255 | dfPlayerSetVolume(volume-1); 256 | pinChanges[VOLDOWN] = 0; 257 | } else if (pinChanges[SELECT1] == 2) { 258 | myDFPlayer.loopFolder(folderSelect); 259 | pinChanges[SELECT1] = 0; 260 | } else if (pinChanges[SELECT1] == 1) { 261 | if(folderSelect < 99) folderSelect++; 262 | pinChanges[SELECT1] = 0; 263 | } else if (pinChanges[SELECT2] == 2) { 264 | myDFPlayer.randomAll(); 265 | pinChanges[SELECT2] = 0; 266 | } else if (pinChanges[SELECT2] == 1) { 267 | if(folderSelect >1) folderSelect--; 268 | pinChanges[SELECT2] = 0; 269 | } 270 | } 271 | 272 | void checkBattery() { 273 | int adc; 274 | batteryCounter++; 275 | if(batteryCounter >= BATTERY_DIVIDER) { 276 | adc = analogRead(A0); 277 | battery_volts = (battery_volts * 15 + battery_mult * ADC_CAL * analogRead(A0)) / 16; 278 | batteryCounter = 0; 279 | } 280 | } 281 | 282 | void readConfig() { 283 | if(SPIFFS.exists("/config.txt")) { 284 | File f = SPIFFS.open("/config.txt", "r");; 285 | int Index = 0; 286 | String temp; 287 | 288 | while(f.available()) { 289 | temp = f.readStringUntil(10); 290 | temp.replace("\r",""); 291 | if(temp.length() && temp.charAt(0) != '#') { 292 | switch(Index) { 293 | case 0: ADC_CAL = temp.toFloat();break; 294 | case 1: volume = temp.toInt();break; 295 | case 2: muteState = temp.toInt();break; 296 | } 297 | Index++; 298 | } 299 | } 300 | f.close(); 301 | } 302 | Serial.print(F("ADC Calibration "));Serial.println(ADC_CAL); 303 | } 304 | 305 | void saveConfig() { 306 | File f = SPIFFS.open("/config.txt", "w"); 307 | f.println(F("#ADC_CAL,volume,mute")); 308 | f.println(ADC_CAL); 309 | f.println(volume); 310 | f.println(muteState); 311 | f.close(); 312 | } 313 | 314 | void setupStart() 315 | { 316 | int i; 317 | for(i=0; i<4;i++) { 318 | pinStates[i] = 1; 319 | pinTimers[i] = elapsedTime; 320 | } 321 | digitalWrite(MUTE, 1); 322 | pinMode(MUTE, OUTPUT); 323 | if(digitalRead(pinInputs[0]) == 0 && digitalRead(pinInputs[1]) == 0) { 324 | dfPlayerInit = INIT_SKIP; 325 | Serial.println(F("Skip init dfPlayer and format SPIFFS")); 326 | } 327 | } 328 | 329 | void extraHandlers() { 330 | server.on("/dfPlayer", dfPlayerCmd); 331 | server.on("/dfPlayerStatus", dfPlayerStatus); 332 | server.on("/test", dfPlayerTest); 333 | } 334 | 335 | void setupEnd() { 336 | delaymSec(500); 337 | Serial.println(F("Read Config")); 338 | readConfig(); 339 | readFolders(); 340 | mySoftwareSerial.begin(9600); 341 | Serial.println(F("Set up complete")); 342 | } 343 | 344 | void loop() { 345 | server.handleClient(); 346 | wifiConnect(1); 347 | delaymSec(timeInterval); 348 | elapsedTime++; 349 | if(dfPlayerInit == INIT_START && elapsedTime * timeInterval > DFPLAYER_STARTUP) { 350 | Serial.println(F("Delayed init of dfPlayer")); 351 | dfPlayerInit = INIT_DELAY; 352 | init_dfPlayer(); 353 | digitalWrite(MUTE, 0); 354 | } 355 | if(dfPlayerInit >= INIT_OK1 && checkButtons()) { 356 | processButtons(); 357 | } 358 | checkBattery(); 359 | } 360 | 361 | -------------------------------------------------------------------------------- /libraries/DFRobotDFPlayerMini/DFRobotDFPlayerMini.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DFRobotDFPlayerMini.cpp 3 | * @brief DFPlayer - An Arduino Mini MP3 Player From DFRobot 4 | * @n Header file for DFRobot's DFPlayer 5 | * 6 | * @copyright [DFRobot]( http://www.dfrobot.com ), 2016 7 | * @copyright GNU Lesser General Public License 8 | * 9 | * @author [Angelo](Angelo.qiao@dfrobot.com) 10 | * @version V1.0 11 | * @date 2016-12-07 12 | */ 13 | 14 | #include "DFRobotDFPlayerMini.h" 15 | 16 | void DFRobotDFPlayerMini::setTimeOut(unsigned long timeOutDuration){ 17 | _timeOutDuration = timeOutDuration; 18 | } 19 | 20 | void DFRobotDFPlayerMini::uint16ToArray(uint16_t value, uint8_t *array){ 21 | *array = (uint8_t)(value>>8); 22 | *(array+1) = (uint8_t)(value); 23 | } 24 | 25 | uint16_t DFRobotDFPlayerMini::calculateCheckSum(uint8_t *buffer){ 26 | uint16_t sum = 0; 27 | for (int i=Stack_Version; iwrite(_sending, DFPLAYER_SEND_LENGTH); 54 | _timeOutTimer = millis(); 55 | _isSending = _sending[Stack_ACK]; 56 | } 57 | 58 | void DFRobotDFPlayerMini::sendStack(uint8_t command){ 59 | sendStack(command, 0); 60 | } 61 | 62 | void DFRobotDFPlayerMini::sendStack(uint8_t command, uint16_t argument){ 63 | _sending[Stack_Command] = command; 64 | uint16ToArray(argument, _sending+Stack_Parameter); 65 | uint16ToArray(calculateCheckSum(_sending), _sending+Stack_CheckSum); 66 | sendStack(); 67 | } 68 | 69 | void DFRobotDFPlayerMini::sendStack(uint8_t command, uint8_t argumentHigh, uint8_t argumentLow){ 70 | uint16_t buffer = argumentHigh; 71 | buffer <<= 8; 72 | sendStack(command, buffer | argumentLow); 73 | } 74 | 75 | void DFRobotDFPlayerMini::enableACK(){ 76 | _sending[Stack_ACK] = 0x01; 77 | } 78 | 79 | void DFRobotDFPlayerMini::disableACK(){ 80 | _sending[Stack_ACK] = 0x00; 81 | } 82 | 83 | bool DFRobotDFPlayerMini::waitAvailable(){ 84 | _isSending = true; 85 | while (!available()){ 86 | delay(0); 87 | } 88 | return _handleType != TimeOut; 89 | } 90 | 91 | bool DFRobotDFPlayerMini::begin(Stream &stream, bool isACK, bool doReset){ 92 | if (isACK) { 93 | enableACK(); 94 | } 95 | else{ 96 | disableACK(); 97 | } 98 | 99 | _serial = &stream; 100 | 101 | if (doReset) { 102 | _timeOutDuration += 3000; 103 | reset(); 104 | waitAvailable(); 105 | _timeOutDuration -= 3000; 106 | delay(200); 107 | } else { 108 | // assume same state as with reset(): online 109 | _handleType = DFPlayerCardOnline; 110 | } 111 | 112 | return (readType() == DFPlayerCardOnline) || !isACK; 113 | } 114 | 115 | uint8_t DFRobotDFPlayerMini::readType(){ 116 | _isAvailable = false; 117 | return _handleType; 118 | } 119 | 120 | uint16_t DFRobotDFPlayerMini::read(){ 121 | _isAvailable = false; 122 | return _handleParameter; 123 | } 124 | 125 | bool DFRobotDFPlayerMini::handleMessage(uint8_t type, uint16_t parameter){ 126 | _receivedIndex = 0; 127 | _handleType = type; 128 | _handleParameter = parameter; 129 | _isAvailable = true; 130 | return _isAvailable; 131 | } 132 | 133 | bool DFRobotDFPlayerMini::handleError(uint8_t type, uint16_t parameter){ 134 | handleMessage(type, parameter); 135 | _isSending = false; 136 | return false; 137 | } 138 | 139 | uint8_t DFRobotDFPlayerMini::readCommand(){ 140 | _isAvailable = false; 141 | return _handleCommand; 142 | } 143 | 144 | void DFRobotDFPlayerMini::parseStack(){ 145 | _handleCommand = *(_received + Stack_Command); 146 | _handleParameter = arrayToUint16(_received + Stack_Parameter); 147 | 148 | switch (_handleCommand) { 149 | case 0x3D: 150 | handleMessage(DFPlayerPlayFinished, _handleParameter); 151 | break; 152 | case 0x3F: 153 | if (_handleParameter & 0x02) { 154 | handleMessage(DFPlayerCardOnline, _handleParameter); 155 | } 156 | break; 157 | case 0x3A: 158 | if (_handleParameter & 0x02) { 159 | handleMessage(DFPlayerCardInserted, _handleParameter); 160 | } 161 | break; 162 | case 0x3B: 163 | if (_handleParameter & 0x02) { 164 | handleMessage(DFPlayerCardRemoved, _handleParameter); 165 | } 166 | break; 167 | case 0x40: 168 | handleMessage(DFPlayerError, _handleParameter); 169 | break; 170 | case 0x41: 171 | _isSending = false; 172 | break; 173 | case 0x3C: 174 | case 0x3E: 175 | case 0x42: 176 | case 0x43: 177 | case 0x44: 178 | case 0x45: 179 | case 0x46: 180 | case 0x47: 181 | case 0x48: 182 | case 0x49: 183 | case 0x4B: 184 | case 0x4C: 185 | case 0x4D: 186 | case 0x4E: 187 | case 0x4F: 188 | _isAvailable = true; 189 | break; 190 | default: 191 | handleError(WrongStack); 192 | break; 193 | } 194 | } 195 | 196 | uint16_t DFRobotDFPlayerMini::arrayToUint16(uint8_t *array){ 197 | uint16_t value = *array; 198 | value <<=8; 199 | value += *(array+1); 200 | return value; 201 | } 202 | 203 | bool DFRobotDFPlayerMini::validateStack(){ 204 | return calculateCheckSum(_received) == arrayToUint16(_received+Stack_CheckSum); 205 | } 206 | 207 | bool DFRobotDFPlayerMini::available(){ 208 | while (_serial->available()) { 209 | delay(0); 210 | if (_receivedIndex == 0) { 211 | _received[Stack_Header] = _serial->read(); 212 | #ifdef _DEBUG 213 | Serial.print(F("received:")); 214 | Serial.print(_received[_receivedIndex],HEX); 215 | Serial.print(F(" ")); 216 | #endif 217 | if (_received[Stack_Header] == 0x7E) { 218 | _isAvailable = false; 219 | _receivedIndex ++; 220 | } 221 | } 222 | else{ 223 | _received[_receivedIndex] = _serial->read(); 224 | #ifdef _DEBUG 225 | Serial.print(_received[_receivedIndex],HEX); 226 | Serial.print(F(" ")); 227 | #endif 228 | switch (_receivedIndex) { 229 | case Stack_Version: 230 | if (_received[_receivedIndex] != 0xFF) { 231 | return handleError(WrongStack); 232 | } 233 | break; 234 | case Stack_Length: 235 | if (_received[_receivedIndex] != 0x06) { 236 | return handleError(WrongStack); 237 | } 238 | break; 239 | case Stack_End: 240 | #ifdef _DEBUG 241 | Serial.println(); 242 | #endif 243 | if (_received[_receivedIndex] != 0xEF) { 244 | return handleError(WrongStack); 245 | } 246 | else{ 247 | if (validateStack()) { 248 | _receivedIndex = 0; 249 | parseStack(); 250 | if (_isAvailable && !_sending[Stack_ACK]) { 251 | _isSending = false; 252 | } 253 | return _isAvailable; 254 | } 255 | else{ 256 | return handleError(WrongStack); 257 | } 258 | } 259 | break; 260 | default: 261 | break; 262 | } 263 | _receivedIndex++; 264 | } 265 | } 266 | 267 | if (_isSending && (millis()-_timeOutTimer>=_timeOutDuration)) { 268 | return handleError(TimeOut); 269 | } 270 | 271 | return _isAvailable; 272 | } 273 | 274 | void DFRobotDFPlayerMini::next(){ 275 | sendStack(0x01); 276 | } 277 | 278 | void DFRobotDFPlayerMini::previous(){ 279 | sendStack(0x02); 280 | } 281 | 282 | void DFRobotDFPlayerMini::play(int fileNumber){ 283 | sendStack(0x03, fileNumber); 284 | } 285 | 286 | void DFRobotDFPlayerMini::volumeUp(){ 287 | sendStack(0x04); 288 | } 289 | 290 | void DFRobotDFPlayerMini::volumeDown(){ 291 | sendStack(0x05); 292 | } 293 | 294 | void DFRobotDFPlayerMini::volume(uint8_t volume){ 295 | sendStack(0x06, volume); 296 | } 297 | 298 | void DFRobotDFPlayerMini::EQ(uint8_t eq) { 299 | sendStack(0x07, eq); 300 | } 301 | 302 | void DFRobotDFPlayerMini::loop(int fileNumber) { 303 | sendStack(0x08, fileNumber); 304 | } 305 | 306 | void DFRobotDFPlayerMini::outputDevice(uint8_t device) { 307 | sendStack(0x09, device); 308 | delay(200); 309 | } 310 | 311 | void DFRobotDFPlayerMini::sleep(){ 312 | sendStack(0x0A); 313 | } 314 | 315 | void DFRobotDFPlayerMini::reset(){ 316 | sendStack(0x0C); 317 | } 318 | 319 | void DFRobotDFPlayerMini::start(){ 320 | sendStack(0x0D); 321 | } 322 | 323 | void DFRobotDFPlayerMini::pause(){ 324 | sendStack(0x0E); 325 | } 326 | 327 | void DFRobotDFPlayerMini::playFolder(uint8_t folderNumber, uint8_t fileNumber){ 328 | sendStack(0x0F, folderNumber, fileNumber); 329 | } 330 | 331 | void DFRobotDFPlayerMini::outputSetting(bool enable, uint8_t gain){ 332 | sendStack(0x10, enable, gain); 333 | } 334 | 335 | void DFRobotDFPlayerMini::enableLoopAll(){ 336 | sendStack(0x11, 0x01); 337 | } 338 | 339 | void DFRobotDFPlayerMini::disableLoopAll(){ 340 | sendStack(0x11, 0x00); 341 | } 342 | 343 | void DFRobotDFPlayerMini::playMp3Folder(int fileNumber){ 344 | sendStack(0x12, fileNumber); 345 | } 346 | 347 | void DFRobotDFPlayerMini::advertise(int fileNumber){ 348 | sendStack(0x13, fileNumber); 349 | } 350 | 351 | void DFRobotDFPlayerMini::playLargeFolder(uint8_t folderNumber, uint16_t fileNumber){ 352 | sendStack(0x14, (((uint16_t)folderNumber) << 12) | fileNumber); 353 | } 354 | 355 | void DFRobotDFPlayerMini::stopAdvertise(){ 356 | sendStack(0x15); 357 | } 358 | 359 | void DFRobotDFPlayerMini::stop(){ 360 | sendStack(0x16); 361 | } 362 | 363 | void DFRobotDFPlayerMini::loopFolder(int folderNumber){ 364 | sendStack(0x17, folderNumber); 365 | } 366 | 367 | void DFRobotDFPlayerMini::randomAll(){ 368 | sendStack(0x18); 369 | } 370 | 371 | void DFRobotDFPlayerMini::enableLoop(){ 372 | sendStack(0x19, 0x00); 373 | } 374 | 375 | void DFRobotDFPlayerMini::disableLoop(){ 376 | sendStack(0x19, 0x01); 377 | } 378 | 379 | void DFRobotDFPlayerMini::enableDAC(){ 380 | sendStack(0x1A, 0x00); 381 | } 382 | 383 | void DFRobotDFPlayerMini::disableDAC(){ 384 | sendStack(0x1A, 0x01); 385 | } 386 | 387 | int DFRobotDFPlayerMini::readState(){ 388 | sendStack(0x42); 389 | if (waitAvailable()) { 390 | return read(); 391 | } 392 | else{ 393 | return -1; 394 | } 395 | } 396 | 397 | int DFRobotDFPlayerMini::readVolume(){ 398 | sendStack(0x43); 399 | if (waitAvailable()) { 400 | return read(); 401 | } 402 | else{ 403 | return -1; 404 | } 405 | } 406 | 407 | uint8_t DFRobotDFPlayerMini::readEQ(){ 408 | sendStack(0x44); 409 | if (waitAvailable()) { 410 | return read(); 411 | } 412 | else{ 413 | return -1; 414 | } 415 | } 416 | 417 | int DFRobotDFPlayerMini::readFileCounts(uint8_t device){ 418 | switch (device) { 419 | case DFPLAYER_DEVICE_U_DISK: 420 | sendStack(0x47); 421 | break; 422 | case DFPLAYER_DEVICE_SD: 423 | sendStack(0x48); 424 | break; 425 | case DFPLAYER_DEVICE_FLASH: 426 | sendStack(0x49); 427 | break; 428 | default: 429 | break; 430 | } 431 | 432 | if (waitAvailable()) { 433 | return read(); 434 | } 435 | else{ 436 | return -1; 437 | } 438 | } 439 | 440 | int DFRobotDFPlayerMini::readCurrentFileNumber(uint8_t device){ 441 | switch (device) { 442 | case DFPLAYER_DEVICE_U_DISK: 443 | sendStack(0x4B); 444 | break; 445 | case DFPLAYER_DEVICE_SD: 446 | sendStack(0x4C); 447 | break; 448 | case DFPLAYER_DEVICE_FLASH: 449 | sendStack(0x4D); 450 | break; 451 | default: 452 | break; 453 | } 454 | if (waitAvailable()) { 455 | return read(); 456 | } 457 | else{ 458 | return -1; 459 | } 460 | } 461 | 462 | int DFRobotDFPlayerMini::readFileCountsInFolder(int folderNumber){ 463 | sendStack(0x4E, folderNumber); 464 | if (waitAvailable()) { 465 | return read(); 466 | } 467 | else{ 468 | return -1; 469 | } 470 | } 471 | 472 | int DFRobotDFPlayerMini::readFolderCounts(){ 473 | sendStack(0x4F); 474 | if (waitAvailable()) { 475 | return read(); 476 | } 477 | else{ 478 | return -1; 479 | } 480 | } 481 | 482 | int DFRobotDFPlayerMini::readFileCounts(){ 483 | return readFileCounts(DFPLAYER_DEVICE_SD); 484 | } 485 | 486 | int DFRobotDFPlayerMini::readCurrentFileNumber(){ 487 | return readCurrentFileNumber(DFPLAYER_DEVICE_SD); 488 | } 489 | 490 | 491 | --------------------------------------------------------------------------------