Guidance to make a musical clock with mp3/Wav

Hello everyone,

I'd like to put together a gift for a friend that is a musical clock that plays a custom mp3/wav audio clip on-the-hour. Each hour a different clip.

A few ideas come to mind but I'm not sure if I'm on the right path.

I've never used the RTC module but assuming I could create a if/then statement in reference to the real time which would send a serial command to maybe a DFPlayer module to play a specific track/file?

Thanks for any nudge in the right direction!

Sounds like you have the right thought process going on..

Make it happen now! LOL

There are plenty of RTC tutorials out there.. and using the DFPLayer mini is super simple as well...

should be a good project for you!

Thank you! I'll give it a go and report back!

Sounds like a good start to me.
All you need to add is a speaker (4-16Ω, 3W) so you can actually hear the sound.

DS3231 modules have an alarm built in. Or, use the Time library.

I find the Catalex YX-5300 to be a painless way to play sounds

I made a clock using a Wemos Mini, DFPlayer mini, speaker and a 60-led ws2812 circle. I can post the code later if you think it would help. Did not use an RTC, the Wemos gets time from NTC over WiFi, but it does use the Time library, which I expect you will also be using, so some of the code should be useful to you.

Thanks PaulRB!

If not much trouble, seeing your code may help.

I'm trying to wrap my head around alarms and if I'm able to send separate commands to the DFPlayer.
Did you use a DFPlayer library? Did you use serial CMD commands to choose track, etc..?

This is a battery project and trying to reduce the power consumption, having the ability to use the SHDN pin on the DFPlayer to toggle the unit on an off. Maybe have a alarm start 5 seconds before the top of the hour, and then shut down after.

Thanks for any help!
n

I made a clock using a Wemos Mini, DFPlayer mini, speaker and a 60-led ws2812 circle. I can post the code later if you think it would help. Did not use an RTC, the Wemos gets time from NTC over WiFi, but it does use the Time library, which I expect you will also be using, so some of the code should be useful to you.

Paul's code will get you most of the way there. I would use a DS3231 RTC using Jack Christensen's DS3232.h library. It is available through the library manager. It is designed to be integrated with the Time Library and becomes a synchronization source for the internal clock.

Your hour event testing becomes a simple

if(hour() != lastHour) //do something

I would not bother with alarms.

Alarms do allow you to make the Arduino sleep, saving battery power.

From the project description it seems all the thing has to do is make some sound at the hour, doing nothing the rest of the time.

Thanks all!

Am I on the right track with this code?

I’m not sure how to set the specific time(s) for each if/then statements.

#include "Arduino.h"
#include <TimeLib.h>
#include "DFRobotDFPlayerMini.h"
#include <DS3232RTC.h>

DFRobotDFPlayerMini myDFPlayer;

void setup()
{
  Serial.begin(9600);
   setSyncProvider(RTC.get);   // the function to get the time from the RTC
  
  
  //----Set DFPlayer Defualts----
  myDFPlayer.volume(10);  //Set volume value (0~30).
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);


void loop()

 if (t != 0) {
      RTC.set(t);   // set the RTC and the system time to the received value
      setTime(t);        
{

if(hour() != lastHour) { //do something
  myDFPlayer.playFolder(1, 1);  //play specific mp3 in SD:/1/001.mp3; Folder Name(1~99); File Name(1~255)
  }
}

Am I on the right track with this code?

Close.

#include "Arduino.h"
#include <TimeLib.h>
#include "DFRobotDFPlayerMini.h"
#include <DS3232RTC.h>

DFRobotDFPlayerMini myDFPlayer;

byte lastHour;

void setup()
{
 Serial.begin(9600);
 setSyncProvider(RTC.get);   // the function to get the time from the RTC

 //----Set DFPlayer Defualts----
 myDFPlayer.volume(10);  //Set volume value (0~30).
 myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

 lastHour = hour();
}

void loop()
{
 //if (t != 0) {
 //     RTC.set(t);   // set the RTC and the system time to the received value
 //     setTime(t);
 //{

 if (hour() != lastHour) //do something
 {
   lastHour = hour();
   myDFPlayer.playFolder(1, 1);  //play specific mp3 in SD:/1/001.mp3; Folder Name(1~99); File Name(1~255)
 }
}

I’m not sure how to set the specific time(s) for each if/then statements.

myDFPlayer.playFolder(1, 1);

What if one of the parameters for the DFPlayer was hour()?

Thank you!

What is the lastHour and Hour parameters?

If lastHour a variable I could rename to the hour of the day?

Fo example, if I wanted to play a song at the top of every hour every day, would the code be close to this?

hour12a = hour(0);minute(0);second(0)
hour1a = hour(1);minute(0);second(0)
hour2a = hour(2);minute(0);second(0)
etc...

What is the lastHour and Hour parameters?

hour() is a time library function which returns the current hour. lastHour is a variable which you set in order to determine when the value returned by the hour() function has changed-- that is, the hour has advanced to the next hour. The comparison of a variable with its last value is the standard way of detecting a change.

I would be worth your time to study the Time Library, and what the functions are.

Fo example, if I wanted to play a song at the top of every hour every day

When hour() is not equal to lastHour, you know that you are at the top of a new hour. Its the equivalent to the minute changing from 59 to 0.

would the code be close to this?

No.

I think the best thing to do is set up 23 tracks/files in a DFPlayer folder, and if the hour changes you play the file with the hour number.

See also the state change detection example in the IDE - that's for the state change of a push button, but the principle is the same.

Hi All,

I worked a bit on some code last night using an alarm function to see if the basics would work.
Although I can trigger a LED to light as a alarm, I can’t get the DFPlayer to play the file.

If willing, would you all take a look at this code? Thank you!

#include <DS3231.h>
#include "DFRobotDFPlayerMini.h"
// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
// Init a Time-data structure
Time  t;

int ledPin = 13; // select the pin for the LED
DFRobotDFPlayerMini myDFPlayer;

void setup()
{
  // Setup Serial connection
  Serial.begin(115200);
  // Uncomment the next line if you are using an Arduino Leonardo
  //while (!Serial) {}
  // Initialize the rtc object
  rtc.begin();
  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(SUNDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(12, 0, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(1, 1, 2016);   // Set the date to DD/MM/YYYY

  pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
  t = rtc.getTime();   // Get data from the DS3231
  // Send date over serial connection
  Serial.print("Date: ");
  Serial.print(t.date, DEC);
  Serial.print("/");
  Serial.print(t.mon, DEC);
  Serial.print("/");
  Serial.print(t.year, DEC);
  Serial.println();

  // Send Day-of-Week and time
  Serial.print("Day of Week: ");
  Serial.print(t.dow, DEC);
  Serial.println();
  Serial.print("Time: ");
  Serial.print(t.hour, DEC);
  Serial.print(":");
  Serial.print(t.min, DEC);
  Serial.print(":");
  Serial.print(t.sec, DEC);
  Serial.println();
  Serial.println("--------------------------------");
  delay(1000); //Delay is for displaying the time in 1 second interval.
if (t.hour == 18 && t.min == 52 && t.sec == 25) 
//Setting alarm/timer at every 2:32:53pm, 
//in other words you can insert t.dow for every Thursday?, t.date for specific date?
  //{ digitalWrite(99, HIGH); delay(5000);
  //{ 
    //digitalWrite (ledPin, HIGH); delay(5000);
 // }
  //else 
  //{
    //digitalWrite (ledPin, LOW);
    //delay(10);
    //}
     {
      myDFPlayer.playFolder(1, 1);  //play specific mp3 in SD:/1/001.mp3; Folder Name(1~99); File Name(1~255)
     }
//Lets say that your component is wired to pin 99 and be switched on for 5 seconds, 
//whatever you want to do with it
  }

I can't get the DFPlayer to play the file.

The DFPlayer requires a software serial (or second hardware serial) connection to the Arduino.

I do no see that in your code. How is the DFPlayer connected to the Arduino?

Have you run the library examples for the DFPlayer?

Thank you.

Currently I have the TX/RX of the Uno connected to the RX/TX of the DFPlayer.
Yet, you’re correct…_I forgot to add the serial info.

How does this look?

#include "DFRobotDFPlayerMini.h"
#include "SoftwareSerial.h"
#include <DS3231.h>
// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
// Init a Time-data structure
Time  t;

int ledPin = 13; // select the pin for the LED

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

void setup()
{
  // Setup Serial connection
  Serial.begin(9600);
  // Uncomment the next line if you are using an Arduino Leonardo
  //while (!Serial) {}
  // Initialize the rtc object
  rtc.begin();
  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(SUNDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(12, 0, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(1, 1, 2016);   // Set the date to DD/MM/YYYY

  pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
  t = rtc.getTime();   // Get data from the DS3231
  // Send date over serial connection
  Serial.print("Date: ");
  Serial.print(t.date, DEC);
  Serial.print("/");
  Serial.print(t.mon, DEC);
  Serial.print("/");
  Serial.print(t.year, DEC);
  Serial.println();

  // Send Day-of-Week and time
  Serial.print("Day of Week: ");
  Serial.print(t.dow, DEC);
  Serial.println();
  Serial.print("Time: ");
  Serial.print(t.hour, DEC);
  Serial.print(":");
  Serial.print(t.min, DEC);
  Serial.print(":");
  Serial.print(t.sec, DEC);
  Serial.println();
  Serial.println("--------------------------------");
  delay(1000); //Delay is for displaying the time in 1 second interval.
if (t.hour == 18 && t.min == 52 && t.sec == 25) 
//Setting alarm/timer at every 2:32:53pm, 
//in other words you can insert t.dow for every Thursday?, t.date for specific date?
  //{ digitalWrite(99, HIGH); delay(5000);
  //{ 
    //digitalWrite (ledPin, HIGH); delay(5000);
 // }
  //else 
  //{
    //digitalWrite (ledPin, LOW);
    //delay(10);
    //}
     {
      myDFPlayer.playFolder(1, 1);  //play specific mp3 in SD:/1/001.mp3; Folder Name(1~99); File Name(1~255)
     }
//Lets say that your component is wired to pin 99 and be switched on for 5 seconds, 
//whatever you want to do with it
  }

How does this look?

What baud rate is software serial running?

According to the library examples I see, I think you need these lines in setup()

mySoftwareSerial.begin(9600);
myDFPlayer.begin(mySoftwareSerial)

Looks like I got it working thanks to your help!

Moving forward, if I wanted to have a different audio track every hour, would I simply add a bunch of IF statements?

Or do I need a ELSE after each?

 #include <DFPlayerMini_Fast.h>
#include <SoftwareSerial.h>
#include <avr/sleep.h>
#include <DS3231.h>
// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
// Init a Time-data structure
Time  t;

SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myDFPlayer;

void setup()
{
  // Setup Serial connection
  Serial.begin(115200);
  mySerial.begin(9600);
  
  myDFPlayer.begin(mySerial);
  
  // Uncomment the next line if you are using an Arduino Leonardo
  //while (!Serial) {}
  // Initialize the rtc object
  rtc.begin();
  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(SUNDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(12, 0, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(1, 1, 2016);   // Set the date to DD/MM/YYYY

  //set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  //sleep_enable();
  //sleep_cpu ();  

}
void loop()
{
  t = rtc.getTime();   // Get data from the DS3231
  // Send date over serial connection
  Serial.print("Date: ");
  Serial.print(t.date, DEC);
  Serial.print("/");
  Serial.print(t.mon, DEC);
  Serial.print("/");
  Serial.print(t.year, DEC);
  Serial.println();

  // Send Day-of-Week and time
  Serial.print("Day of Week: ");
  Serial.print(t.dow, DEC);
  Serial.println();
  Serial.print("Time: ");
  Serial.print(t.hour, DEC);
  Serial.print(":");
  Serial.print(t.min, DEC);
  Serial.print(":");
  Serial.print(t.sec, DEC);
  Serial.println();
  Serial.println("--------------------------------");
  delay(1000); //Delay is for displaying the time in 1 second interval.
if (t.hour == 0 && t.min == 0 && t.sec == 30) 
     {
      myDFPlayer.play(1); //play mp3 file with leading identifier "0001"
     }

  }

Moving forward, if I wanted to have a different audio track every hour, would I simply add a bunch of IF statements?
Or do I need a ELSE after each?

It is better practice to use the else if but in your case it probably does not matter if you use if or else if before each conditional. The processor time to execute the additional comparisons which are not going to run will be small.

https://www.arduino.cc/reference/en/language/structure/control-structure/else/

As discussed earlier in thread, a play instruction which picks up the hour value for a file number is the cleanest way.

Do your best to write the code, and come back with specific problems if any turn up.