Advertisement
JonD1988

PlaylistdoorbellRev7aRx

Mar 14th, 2023
772
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 16.44 KB | None | 0 0
  1. //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.
  2. //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.
  3. //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.
  4. //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)
  5. //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)
  6. //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).
  7. //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.
  8. //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.
  9. //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.
  10.  
  11. // Include Libraries
  12. #include <WiFi.h>
  13. #include <esp_now.h>
  14. #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."
  15.  
  16. uint8_t broadcastAddress1[] = {0xB8, 0xD6, 0x1A, 0x5B, 0x7B, 0x50}; //MAC Address for Receiver Board E02
  17. uint8_t broadcastAddress2[] = {0xE0, 0x5A, 0x1B, 0x60, 0x8F, 0x6C}; //MAC Address for Receiver Board E07
  18. uint8_t broadcastAddress3[] = {0xB8, 0xD6, 0x1A, 0x5E, 0xBF, 0xCC}; //MAC Address for Receiver Board E03
  19.  
  20. #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."
  21. #define sendDelay 250 //Delay between transmitting to each receiver board
  22.  
  23. 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
  24. 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
  25.  
  26. typedef struct struct_message
  27. { //Beginning of structure definition for struct_message
  28.   int a; //Where button state will be stored
  29.   int b; //Where ident will be stored
  30. } struct_message; //End of structure definition for struct_message
  31.  
  32. struct_message myData; // Create structured data object
  33.  
  34. esp_now_peer_info_t peerInfo; // Register peer - Needed for Sending Message Only, Not Receiving
  35.  
  36. // callback when data is sent
  37. void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
  38. { //Start of OnDataSent callfunction function definition
  39.   char macStr[18];
  40.   Serial.print("Packet to: ");
  41.   // Copies the sender mac address to a string
  42.   snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
  43.            mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  44.   Serial.print(macStr);
  45.   Serial.print(" send status:\t");
  46.   Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  47. } //End of OnDataSent callfunction function definition
  48.  
  49. // Callback function
  50. void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len)
  51. { //Start of onDataRecv callback function definition
  52.   //Get incoming data
  53.   memcpy(&myData, incomingData, sizeof(myData));
  54.  
  55.   //Print to Serial Monitor
  56.   Serial.print("Transmitter Board ");
  57.   Serial.print(myData.b);
  58.   Serial.print(": ");
  59.   Serial.println(myData.a);
  60.  
  61.   Serial.println("");
  62.  
  63.     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
  64.  
  65.     if (result1 == ESP_OK)
  66.     { //Start of if (result1 == ESP_OK) is true
  67.      Serial.println("Message 1 Sent with success");
  68.      Serial.print("Button State Sent: ");
  69.      Serial.println(myData.a);
  70.     } //End of if (result1 == ESP_OK) is true
  71.     else
  72.     { //Start of if (result1 == ESP_OK) is false
  73.      Serial.println("Error sending the data for Message 1");
  74.     } //End of if (result1 == ESP_OK) is false
  75.  
  76.     delay(sendDelay);
  77.     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
  78.  
  79.     if (result2 == ESP_OK)
  80.     { //Start of if (result2 == ESP_OK) is true
  81.      Serial.println("Message 2 Sent with success");
  82.     } //End of if (result2 == ESP_OK) is true
  83.     else
  84.     { //Start of if (result2 == ESP_OK) is false
  85.      Serial.println("Error sending the data for Message 2");
  86.     } //End of if (result2 == ESP_OK) is false
  87.  
  88.     delay(sendDelay);
  89.     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
  90.  
  91.     if (result3 == ESP_OK)
  92.     { //Start of if (result3 == ESP_OK) is true
  93.      Serial.println("Message 3 Sent with success");
  94.     } //End of if (result3 == ESP_OK) is true
  95.     else
  96.     { //Start of if (result3 == ESP_OK) is false
  97.      Serial.println("Error sending the data for Message 3");
  98.     } //End of if (result3 == ESP_OK) is false
  99.  
  100.     delay(sendDelay);
  101.  
  102.   //Play the next song on E01 receiver board
  103.   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)
  104.         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.
  105.         { //Start of if(playNextCount!=1)
  106.         playNext(); //Call the playNext function definition        
  107.         } //End of if(playNextCount!=1)
  108. } //End of onDataRecv callback function definition
  109.  
  110. #include <HardwareSerial.h> //Needed to use Hardware Serial pins of ESP32 - Reference 2
  111. //Now to Use a Hardware Serial Port to Control DFPlayer Mini Clone/Knockoff - Reference 2
  112. //Connect ESP32 GPIO 27 to DFPlayer Mini Pin Tx through 1 kΩ Resistor - Reference 2
  113. //Connect ESP32 GPIO 26 to DFPlayer Mini Pin Rx through 1 kΩ Resistor - Reference 2
  114. HardwareSerial MySerial(1); //- Reference 2
  115. #define DFPlayerTx 27 //- Reference 2
  116. #define DFPlayerRx 26 //- Reference 2
  117.  
  118. #define potPin1 34 // GPIO pin used to connect potentiometer 1 (analog in) - Labeled G34 on board - Used for DFPlayerMini Clone Volume Control
  119. #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
  120. 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
  121.  
  122. void setup()
  123. {  //Start of void setup
  124.  
  125.   MySerial.begin(9600, SERIAL_8N1, DFPlayerTx, DFPlayerRx); //Start up the serial communication to the DFPlayer Mini Clone
  126.   delay(3500);//let everything initialise
  127.  
  128.   valOne = analogRead(potPin1); //Read the value of potentiometer One (value between 0 and 4095)
  129.   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
  130.   changeVolume(volume);//set volume to value specified by potentiometer 1
  131.  
  132.   // Set up Serial Monitor
  133.   Serial.begin(115200);
  134.  
  135.   WiFi.mode(WIFI_STA); // Set ESP32 in STA mode to begin with (temporarily)
  136.  
  137.   // Initialize ESP-NOW
  138.   if (esp_now_init() != 0)
  139.   { //Beginning of if (esp_now_init() != 0)
  140.     Serial.println("Error initializing ESP-NOW");
  141.     return;
  142.   } //End of if (esp_now_init() != 0)
  143.  
  144.   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."
  145.  
  146.   esp_now_register_recv_cb(OnDataRecv); // Once ESPNow is successfully Init, we will register for recv CB to get recv packer info
  147.   esp_now_register_send_cb(OnDataSent); //Define callback for sending data
  148.  
  149.   // register peer
  150.   peerInfo.channel = 0;  
  151.   peerInfo.encrypt = false;
  152.   // register first peer  
  153.   memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
  154.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  155.     Serial.println("Failed to add peer");
  156.     return;
  157.   }
  158.   // register second peer  
  159.   memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
  160.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  161.     Serial.println("Failed to add peer");
  162.     return;
  163.   }
  164.   /// register third peer
  165.   memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
  166.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  167.     Serial.println("Failed to add peer");
  168.     return;
  169.   }
  170.  
  171.   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."
  172.   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."
  173.  
  174. } //End of void setup
  175.  
  176. void loop()
  177. { //Start of void loop
  178.  
  179.   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."
  180.   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.
  181.  
  182. } //End of void loop
  183. //Reference 1- BroadcastModeRev0.ino located in D:\Stuff\Projects\ESP32 Control\Miscellaneous Projects\Playlist Doorbell\BroadcastModeRev0
  184. //Reference 2- ESP32AutoTrumpetRev0.ino D:\Stuff\Projects\ESP32 Control\Audio\ESP32AutoTrumpet\ESP32AutoTrumpetRev0 - This used a clone DFPlayer Mini
  185. //Reference 3- ESP32ProximityDFPlayerMiniRev3.ino located in D:\Stuff\Projects\ESP32 Control\Audio\ESP32ProximityDFPlayerMini\ESP32ProximityDFPlayerMiniRev3 - Note: This used an actual DFPlayer Mini, not a clone
  186. //Reference 4- Reading a potentiometer on ESP32 https://esp32io.com/tutorials/esp32-potentiometer
  187. //Reference 5- Mecanum Wheel Robot Car & ESP-NOW Remote https://www.youtube.com/watch?v=dZttHOxIoek&t=3710s
  188. //Reference 6- https://randomnerdtutorials.com/esp-now-one-to-many-esp32-esp8266/
  189. //Reference 7- https://dronebotworkshop.com/esp-now/#Multiple_Sensors_Modification
  190.  
  191. /*
  192.   Note from Reference 1
  193.   ESP-NOW Multi Unit Demo
  194.   esp-now-multi.ino
  195.   Broadcasts control messages to all devices in network
  196.   Load script on multiple devices
  197.  
  198.   DroneBot Workshop 2022
  199.   https://dronebotworkshop.com
  200. */
  201.  
  202. //Function Definitions - From here down these function definitions come from Reference 2
  203. //this function sends the actual command
  204. //It receives the command byte and ParData is optional info such as track number or volume depending on the command
  205. void sendDFCommand(byte Command, int ParData)
  206. { //Start of sendDFCommand function definition
  207. byte commandData[10]; //This holds all the command data to be sent
  208. byte q;
  209. int checkSum;
  210. Serial.print("Com: ");
  211. Serial.print(Command, HEX);
  212. //Each command value is being sent in Hexadecimal
  213. commandData[0] = 0x7E;//Start of new command
  214. commandData[1] = 0xFF;//Version information
  215. commandData[2] = 0x06;//Data length (not including parity) or the start and version
  216. commandData[3] = Command;//The command that was sent through
  217. commandData[4] = 0x01;//1 = feedback
  218. commandData[5] = highByte(ParData);//High byte of the data sent over
  219. commandData[6] = lowByte(ParData);//low byte of the data sent over
  220. checkSum = -(commandData[1] + commandData[2] + commandData[3] + commandData[4] + commandData[5] + commandData[6]);
  221. commandData[7] = highByte(checkSum);//High byte of the checkSum
  222. commandData[8] = lowByte(checkSum);//low byte of the checkSum
  223. commandData[9] = 0xEF;//End bit
  224. for (q = 0; q < 10; q++) {
  225. //Serial3.write(commandData[q]); //This version was when the command was using the hardware serial port built into the Arduino Mega
  226. MySerial.write(commandData[q]);
  227. }
  228. Serial.println("Command Sent: ");
  229. for (q = 0; q < 10; q++) {
  230. Serial.println(commandData[q],HEX);
  231. }
  232. Serial.println("End Command: ");
  233. delay(100);
  234. } //End of sendDFCommand function definition
  235. //play a specific track number
  236. void playTrack(int tracknum){
  237. Serial.print("Track selected: ");
  238. Serial.println(tracknum);
  239. sendDFCommand(0x03, tracknum);
  240. }
  241. //plays the next track
  242. void playNext(){
  243. Serial.println("Play Next");
  244. sendDFCommand(0x01, 0);
  245. }
  246. //volume increase by 1
  247. void volumeUp() {
  248. Serial.println("Vol UP");
  249. sendDFCommand(0x04, 0);
  250. }
  251. //volume decrease by 1
  252. void volumeDown() {
  253. Serial.println("Vol Down");
  254. sendDFCommand(0x05, 0);
  255. }
  256. //set volume to specific value
  257. void changeVolume(int thevolume) {
  258. sendDFCommand(0x06, thevolume);
  259. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement