Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Rev 0 Created 1/24/2023 by Jonathan DeWitt. This sketch is for a wireless doorbell system. It can have quite a few transmitters and receivers. The sketch is the same for both. There is a glitch in this version. When the system powers up the first time a song is played. This will happen if the power cycles too. But then it behaves normally.
- //Rev 1 Created 1/24/2023 by Jonathan DeWitt. In Rev 0 there was a glitch. When the doorbell system first booted up the playNext function would be called which played the second MP3 file on the microSD card. The code that caused this was the code which evaluated the pushbutton built into the board (not the remotely connected pushbuttons). Rev 1 code eliminates the glitch using an if-statement in the void loop.
- //Rev 2 Created 2/17/2023 by Jonathan DeWitt. In Rev 1 the volume for the DFPlayer Mini clone was hardcoded to be 10. In Rev 2 this feature was changed to be set by a potentiometer connected to GPIO 34.
- //Rev 4 Created 3/7/2023 by Jonathan DeWitt. Note: Rev 3 did not work as well as I hoped. So, Rev 4 is based off of Rev 2 code. In revision 4 I added code on line 155 to disable the WiFi sleep mode. In lines 9, 11, 184, 185, 239, and 240 I added code to set up a watchdog timer. It is my hope that these will fix the intermittent issues I was seeing in Revision 2 Code (DFPlayer Mini Freezeup After Playing a Song and ESP32 Receiver Board Freezup)
- //Rev 5Tx Created 3/9/2023 by Jonathan DeWitt. Rev 5Tx was meant for the transmitter (button) boards. This is my first attempt to cut out all of the bloated code from earlier versions (commented them out) and do a one to many approach where each button board transmits to the three receiver boards (which are specifically addressed in lines 12, 13, and 14). Note the user needs to change the value stored in ident on line 18 to match the number of the board you are using (so the receivers can identify which board transmitted the structure to them)
- //Rev 5Rx Created 3/9/2023 by Jonathan DeWitt. Rev 5Rx was meant to match Rev 5Tx. I do wonder if I need to put an interrupt so that the callback function will interrupt if the analogRead is being performed. I'm actually considering moving the analogRead for the volume control to the setup to read once at startup. If the user really wants to change the volume they can move the dial and restart the ESP32. Note: Ident is in line 16 and will need changed between 1, 2, and 3. Note: Do not put anything in the void loop unless there is an interrupt on the received data. When the analog read for the potentiometer was in the void loop it was blocking reception (or at least acting on that reception). Moving the POT reading to the setup worked. There is a workaround. If you change the volume knob and press reset on the ESP32 boards of the receivers it will change the volume while the song is playing. Just be aware that the song will then not change until a second press of the transmitter boards because the ESP32 receiver board's play next counter has reset. The ESP32 receiver boards are programmed not to respond until a second press of the button (to ignore the bootup play).
- //Rev 6Rx Created 3/9/2023 by Jonathan DeWitt. Rev 6Rx is an exact copy of Rev 5Rx except all code that isn't needed (was commented out) was removed. This code pairs with Rev 6Tx.
- //Rev 7Rx Created 3/13/2023 by Jonathan DeWitt. Rev 7Rx is based off of the Rev 6Rx code, the Rev 7Tx code, and the Rev 6Relay code. This code is solely meant to go onto receiver board E01. E01 will now relay the signal from the transmitter boards to E02 and E03. E02 and E03 still have Rev 6Rx code loaded onto them.
- //Rev 7aRx Created 3/13/2023 by Jonathan DeWitt. For some reason the relay board wasn't working. So, I decided to try directly addressing E06.
- // Include Libraries
- #include <WiFi.h>
- #include <esp_now.h>
- #include <esp_task_wdt.h> //Watchdog Timer Library - Reference 5 59:40-minute mark in video - According to Bill at DroneBot Workshop "I've implemented a watchdog timer on this. A watchdog timer is something that looks at your code. And if it sees your code isn't responding after a preset period of time, it'll perform an action. In my case, it'll restart the ESP32. I've done this so that if the car happens to lose a signal or something goes wrong and it is still running, it will turn itself off and reset."
- uint8_t broadcastAddress1[] = {0xB8, 0xD6, 0x1A, 0x5B, 0x7B, 0x50}; //MAC Address for Receiver Board E02
- uint8_t broadcastAddress2[] = {0xE0, 0x5A, 0x1B, 0x60, 0x8F, 0x6C}; //MAC Address for Receiver Board E07
- uint8_t broadcastAddress3[] = {0xB8, 0xD6, 0x1A, 0x5E, 0xBF, 0xCC}; //MAC Address for Receiver Board E03
- #define WDT_TIMEOUT 3 //Watchdog Timer Timeout Period Defined - Reference 5 59:40-minute mark in video - According to Bill at DroneBot Workshop "If the watchdog timer doesn't see a response within three seconds it will reboot."
- #define sendDelay 250 //Delay between transmitting to each receiver board
- int ident = 1; //Change this variable for each receiver .. unique identifier for the board E01 will be value of 1 and E02 will be value of 2 and E03 will be the value of 3
- int playNextCount=0; //Keeps track of how many times the playNext function is called by the button built into the board - this is because the first time the board boots up it activates the DFPlayer Mini Clone
- typedef struct struct_message
- { //Beginning of structure definition for struct_message
- int a; //Where button state will be stored
- int b; //Where ident will be stored
- } struct_message; //End of structure definition for struct_message
- struct_message myData; // Create structured data object
- esp_now_peer_info_t peerInfo; // Register peer - Needed for Sending Message Only, Not Receiving
- // callback when data is sent
- void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
- { //Start of OnDataSent callfunction function definition
- char macStr[18];
- Serial.print("Packet to: ");
- // Copies the sender mac address to a string
- snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
- mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
- Serial.print(macStr);
- Serial.print(" send status:\t");
- Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
- } //End of OnDataSent callfunction function definition
- // Callback function
- void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len)
- { //Start of onDataRecv callback function definition
- //Get incoming data
- memcpy(&myData, incomingData, sizeof(myData));
- //Print to Serial Monitor
- Serial.print("Transmitter Board ");
- Serial.print(myData.b);
- Serial.print(": ");
- Serial.println(myData.a);
- Serial.println("");
- esp_err_t result1 = esp_now_send(broadcastAddress1, (uint8_t *) &myData, sizeof(myData)); //Send data to receiver board E02 - stores results of sending in result 1
- if (result1 == ESP_OK)
- { //Start of if (result1 == ESP_OK) is true
- Serial.println("Message 1 Sent with success");
- Serial.print("Button State Sent: ");
- Serial.println(myData.a);
- } //End of if (result1 == ESP_OK) is true
- else
- { //Start of if (result1 == ESP_OK) is false
- Serial.println("Error sending the data for Message 1");
- } //End of if (result1 == ESP_OK) is false
- delay(sendDelay);
- esp_err_t result2 = esp_now_send(broadcastAddress2, (uint8_t *) &myData, sizeof(myData)); //Send data to receiver board E07 - stores results of sending in result 2
- if (result2 == ESP_OK)
- { //Start of if (result2 == ESP_OK) is true
- Serial.println("Message 2 Sent with success");
- } //End of if (result2 == ESP_OK) is true
- else
- { //Start of if (result2 == ESP_OK) is false
- Serial.println("Error sending the data for Message 2");
- } //End of if (result2 == ESP_OK) is false
- delay(sendDelay);
- esp_err_t result3 = esp_now_send(broadcastAddress3, (uint8_t *) &myData, sizeof(myData)); //Send data to receiver board E03 - stores results of sending in result 3
- if (result3 == ESP_OK)
- { //Start of if (result3 == ESP_OK) is true
- Serial.println("Message 3 Sent with success");
- } //End of if (result3 == ESP_OK) is true
- else
- { //Start of if (result3 == ESP_OK) is false
- Serial.println("Error sending the data for Message 3");
- } //End of if (result3 == ESP_OK) is false
- delay(sendDelay);
- //Play the next song on E01 receiver board
- playNextCount++; //Increment the playNextCount counter each time the playNext function is called or rather each time a message is recieved (should be the same number)
- if(playNextCount!=1) //When the microcontroller first boots up the built-in button code calls playNext() and plays an MP3 file. I do not want this. On that iteration playNextCount=1. This if-statement prevents playNext from being called on that iteration only.
- { //Start of if(playNextCount!=1)
- playNext(); //Call the playNext function definition
- } //End of if(playNextCount!=1)
- } //End of onDataRecv callback function definition
- #include <HardwareSerial.h> //Needed to use Hardware Serial pins of ESP32 - Reference 2
- //Now to Use a Hardware Serial Port to Control DFPlayer Mini Clone/Knockoff - Reference 2
- //Connect ESP32 GPIO 27 to DFPlayer Mini Pin Tx through 1 kΩ Resistor - Reference 2
- //Connect ESP32 GPIO 26 to DFPlayer Mini Pin Rx through 1 kΩ Resistor - Reference 2
- HardwareSerial MySerial(1); //- Reference 2
- #define DFPlayerTx 27 //- Reference 2
- #define DFPlayerRx 26 //- Reference 2
- #define potPin1 34 // GPIO pin used to connect potentiometer 1 (analog in) - Labeled G34 on board - Used for DFPlayerMini Clone Volume Control
- #define ADC_Max 4095 // This is the default ADC max value on the ESP32 (12 bit ADC width). this width can be set (in low-level oode) from 9-12 bits, for a range of max values of 512-4096
- int valOne, volume; //valOne is the analog value read from potPin1. volume is what valOne will be mapped to in order to change the volume of the DFPlayer Mini clone
- void setup()
- { //Start of void setup
- MySerial.begin(9600, SERIAL_8N1, DFPlayerTx, DFPlayerRx); //Start up the serial communication to the DFPlayer Mini Clone
- delay(3500);//let everything initialise
- valOne = analogRead(potPin1); //Read the value of potentiometer One (value between 0 and 4095)
- volume = map(valOne, 0, ADC_Max, 0, 30); //Changes the analog read value from 0 to 4095 to a range between 0 and 30 - Maximum volume for the DFPlayer Mini clone is 30
- changeVolume(volume);//set volume to value specified by potentiometer 1
- // Set up Serial Monitor
- Serial.begin(115200);
- WiFi.mode(WIFI_STA); // Set ESP32 in STA mode to begin with (temporarily)
- // Initialize ESP-NOW
- if (esp_now_init() != 0)
- { //Beginning of if (esp_now_init() != 0)
- Serial.println("Error initializing ESP-NOW");
- return;
- } //End of if (esp_now_init() != 0)
- WiFi.setSleep(false); //Disable WiFi Sleep Mode - Reference 5 1:02:40-minute mark in video - According to Bill at DroneBot Workshop "This command is not a requirement. But if you don't do it you can have intermittent issues. I've found this really helped a lot."
- esp_now_register_recv_cb(OnDataRecv); // Once ESPNow is successfully Init, we will register for recv CB to get recv packer info
- esp_now_register_send_cb(OnDataSent); //Define callback for sending data
- // register peer
- peerInfo.channel = 0;
- peerInfo.encrypt = false;
- // register first peer
- memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
- if (esp_now_add_peer(&peerInfo) != ESP_OK){
- Serial.println("Failed to add peer");
- return;
- }
- // register second peer
- memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
- if (esp_now_add_peer(&peerInfo) != ESP_OK){
- Serial.println("Failed to add peer");
- return;
- }
- /// register third peer
- memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
- if (esp_now_add_peer(&peerInfo) != ESP_OK){
- Serial.println("Failed to add peer");
- return;
- }
- esp_task_wdt_init(WDT_TIMEOUT, true); // Enable watchdog timer - true is "panic mode" to restart - Reference 5 1:03:17-minute mark in video - According to Bill at DroneBot Workshop "Here is where we enable the watchdog timer. And we enable it to that timeout which I've set to three seconds and true. And what true is is it puts the watchdog timer into panic mode. And in panic mode it will just restart if it times out."
- esp_task_wdt_add(NULL); // Add current thread to watchdog timer - Reference 5 According to Bill at DroneBot Workshop "And we're adding the current thread to the watchdog timer. You can monitor whatever we want. But if we add a null value here it'll just monitor the current thread which is exactly what we want."
- } //End of void setup
- void loop()
- { //Start of void loop
- esp_task_wdt_reset(); //Reset watchdog timer - Reference 5 1:05:20-minute mark in video - According to Bill at DroneBot Workshop "We'll call this to reset the watchdog timer, to let it know we're still alive."
- delay(50); //Short delay - I believe this is related to the watchdog timer reset - but am not certain about that. Even if it isn't related to the watchdog timer, a 50 ms delay is so short I'm hoping it won't affect my code.
- } //End of void loop
- //Reference 1- BroadcastModeRev0.ino located in D:\Stuff\Projects\ESP32 Control\Miscellaneous Projects\Playlist Doorbell\BroadcastModeRev0
- //Reference 2- ESP32AutoTrumpetRev0.ino D:\Stuff\Projects\ESP32 Control\Audio\ESP32AutoTrumpet\ESP32AutoTrumpetRev0 - This used a clone DFPlayer Mini
- //Reference 3- ESP32ProximityDFPlayerMiniRev3.ino located in D:\Stuff\Projects\ESP32 Control\Audio\ESP32ProximityDFPlayerMini\ESP32ProximityDFPlayerMiniRev3 - Note: This used an actual DFPlayer Mini, not a clone
- //Reference 4- Reading a potentiometer on ESP32 https://esp32io.com/tutorials/esp32-potentiometer
- //Reference 5- Mecanum Wheel Robot Car & ESP-NOW Remote https://www.youtube.com/watch?v=dZttHOxIoek&t=3710s
- //Reference 6- https://randomnerdtutorials.com/esp-now-one-to-many-esp32-esp8266/
- //Reference 7- https://dronebotworkshop.com/esp-now/#Multiple_Sensors_Modification
- /*
- Note from Reference 1
- ESP-NOW Multi Unit Demo
- esp-now-multi.ino
- Broadcasts control messages to all devices in network
- Load script on multiple devices
- DroneBot Workshop 2022
- https://dronebotworkshop.com
- */
- //Function Definitions - From here down these function definitions come from Reference 2
- //this function sends the actual command
- //It receives the command byte and ParData is optional info such as track number or volume depending on the command
- void sendDFCommand(byte Command, int ParData)
- { //Start of sendDFCommand function definition
- byte commandData[10]; //This holds all the command data to be sent
- byte q;
- int checkSum;
- Serial.print("Com: ");
- Serial.print(Command, HEX);
- //Each command value is being sent in Hexadecimal
- commandData[0] = 0x7E;//Start of new command
- commandData[1] = 0xFF;//Version information
- commandData[2] = 0x06;//Data length (not including parity) or the start and version
- commandData[3] = Command;//The command that was sent through
- commandData[4] = 0x01;//1 = feedback
- commandData[5] = highByte(ParData);//High byte of the data sent over
- commandData[6] = lowByte(ParData);//low byte of the data sent over
- checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
- commandData[7] = highByte(checkSum);//High byte of the checkSum
- commandData[8] = lowByte(checkSum);//low byte of the checkSum
- commandData[9] = 0xEF;//End bit
- for (q = 0; q < 10; q++) {
- //Serial3.write(commandData[q]); //This version was when the command was using the hardware serial port built into the Arduino Mega
- MySerial.write(commandData[q]);
- }
- Serial.println("Command Sent: ");
- for (q = 0; q < 10; q++) {
- Serial.println(commandData[q],HEX);
- }
- Serial.println("End Command: ");
- delay(100);
- } //End of sendDFCommand function definition
- //play a specific track number
- void playTrack(int tracknum){
- Serial.print("Track selected: ");
- Serial.println(tracknum);
- sendDFCommand(0x03, tracknum);
- }
- //plays the next track
- void playNext(){
- Serial.println("Play Next");
- sendDFCommand(0x01, 0);
- }
- //volume increase by 1
- void volumeUp() {
- Serial.println("Vol UP");
- sendDFCommand(0x04, 0);
- }
- //volume decrease by 1
- void volumeDown() {
- Serial.println("Vol Down");
- sendDFCommand(0x05, 0);
- }
- //set volume to specific value
- void changeVolume(int thevolume) {
- sendDFCommand(0x06, thevolume);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement