Well I have successfully completed my sketch to use my DS1307 RTC to accurately announce ships time (the old 8 bells). I used the buzzer for the development but would like to get a real bell sound. My thoughts were to drive a solenoid to ring a bell (repurposed bike bell was my initial thought), but I am running into issues with this idea in sourcing the proper relay/power supply/ solenoid to achieve this. Does anyone have a related bell ringing circuit to share?
Hello
Take a MP3 Player Shield or a sound chip.
Find a door bell? On that normally rings... it has a bell and a solenoid...
I implemented a Ships Clock using the DFPlayer board. and an Arduino. The 8 Bell sounds files (mp3) are put on an SD Card in the DF Player. The Arduino controls the the DF Player. Amazon has 5 DF Players for $14.00.
The Arduino that I used was the NodeMCU ESP8266 that has Wifi Capabilities. The "Time" is sync'ed to a NTP server so it always up to date with the correct time
Yes ...
Hmmm... I had not thought of using a DF player, i have one for another project (Princess cruise sleep to waves and music ap that i was in process of writing). Can you share your sketch? I am using a rt clock to control the time, but would like to see your NTP server ap.
What did you sample for the bell sound files?
you should be able to download 8 sound files from a site like soundsnap.com. those files would be put on the df player.
then it is just a matter of selecting the right file for play back at the right time
let me know if you need any help
Here's the made code. I am still adding features and cleaning up stuff, but I have had it fully operational with the basic functional for a while
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <SoftwareSerial.h>
const int intVolume = 3; // Set volume to maximum (0 to 30).
const int TimeOffset = -5;
int lastTriggerMin = 99;
const byte CmdPlayNext = 0x01;
const byte CmdPlayPrevious = 0x02;
const byte CmdPlayRootTrack = 0x03;
const byte CmdIncreaseVol = 0x04;
const byte CmdDecreaseVol = 0x05;
const byte CmdSetVolume = 0x06;
const byte CmdSpecifyEQ = 0x07;
const byte CmdSetSleep = 0x0A;
const byte CmdReset = 0x0C;
const byte CmdPlay = 0x0D;
const byte CmdPause = 0x0E;
const byte CmdStop = 0x16;
//Return Code
const byte CmdProcessed = 0x41;
WiFiUDP ntpUDP;
NTPClient ntpClientX(ntpUDP, "192.168.1.1");
ESP8266WebServer server(80);
// Use pins 2 and 3 to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = D2; //
static const uint8_t PIN_MP3_RX = D3; //
SoftwareSerial SoftSerial(PIN_MP3_RX, PIN_MP3_TX);
int idxRec = 0;
const int Rows = 10;
String rec[Rows][4];
void setup() {
//Init USB serial port for debugging
Serial.begin(115200);
InitWiFi();
//NTP Client
ntpClientX.setTimeOffset(TimeOffset * 3600);
ntpClientX.begin();
//Get the Current time
ntpClientX.update();
// Init serial port for DFPlayer Mini
SoftSerial.begin(9600);
delay(2000);
//Clear Buffer
Serial.print("Clear Buffer ");
//This will probally result in a "Serial Error"
if (SoftSerial.available()) {
byte rtn[20];
GetResult(rtn);
}
SetVolume(intVolume );
delay(1000);
server.on("/", handleRoot);
server.onNotFound(handleNotFound);
server.begin();
}
void loop() {
if (SoftSerial.available()) {
Serial.print("Main Line Serial... ");
byte rtn[20];
GetResult(rtn);
}
ntpClientX.update();
AdjustTime();
int intCurrMin = ntpClientX.getMinutes();
// Only process for CurrMin = 0 or 30
if ((lastTriggerMin != intCurrMin) && (intCurrMin % 30 ) == 0) {
int intBells = GetBellCount(ntpClientX.getHours(), intCurrMin);
String tm = ntpClientX.getFormattedTime();
Serial.print("Current time: ");
Serial.println(tm);
Serial.print("--- Bells: ");
Serial.println(intBells);
Serial.println(QueryStatus(), HEX); //Use this to make sure the unit is allve
delay(100);
//Play the Bells
byte rtn = PlayTrack(intBells);
lastTriggerMin = intCurrMin;
Serial.print("LastTriggerMin (0 or 30): " );
Serial.println(lastTriggerMin);
delay(500);
rec[idxRec][0] = tm;
rec[idxRec][1] = String(intBells);
rec[idxRec][2] = "0x" + String(rtn, HEX);
//rec[idxRec][3] = String(DP);
idxRec = (idxRec + 1) % Rows;
}
server.handleClient();
}
int GetBellCount(int intHour, int intMinute) {
//Bells are on a 4 hour cycle
//Even Number at Hour marks :00
//Odd Number at 30 Minute mark :30
//Max 8 Bells at 0, 4, 8, 12, 16, 20 hours.
if (intHour < 0 || intHour >= 24 )
return 0;
if (intMinute % 30 > 0)
return 0;
if (intMinute < 0 || intMinute >= 60 )
return 0;
int intBells = ((intHour % 4) * 2); // Top of Hour Calculation. Always Even Number
if (intMinute == 30) // Bottom of Hour Adjustment
intBells += 1;
if (intBells == 0)
intBells = 8;
return intBells;
}
byte SetVolume(byte level) {
Serial.print ("Set Volume: ");
Serial.println (level);
if (level > 30)
level = 30;
return Send_Cmd(0x6, 0, level);
}
int GetVolume() {
Serial.println("Get Volume");
if (Send_Cmd(0x43, 0, 0) == CmdProcessed) {
byte rtn[20];
GetResult(rtn);
return rtn[6];
}
return -1;
}
int GetRootFileCnt() {
Serial.println("GetRootFileCnt");
if (Send_Cmd(0x48, 0, 0) == CmdProcessed) {
byte rtn[20];
GetResult(rtn);
return (rtn[5] << 8) + rtn[6];
}
return -1;
}
byte PlayTrack(byte track) {
Serial.print ("Play Track: ");
Serial.println (track);
byte rtn = Send_Cmd(0x06, 0, track);
if (rtn != CmdProcessed) //Try it again
{
delay(250);
rtn = Send_Cmd(0x03, 0, track);
}
return rtn;
}
byte QueryStatus() {
Serial.println ("Query Status: ");
return Send_Cmd(0x42, 0, 0);
}
byte Send_Cmd(byte cmd, byte param1, byte param2) {
//Base Array
byte b[] = {0x7E, 0xFF, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xEF};
b[0] = 0x7E; //Start Byte
b[1] = 0xFF; //Version. Always FF
b[2] = 0x6; //Command Length - Usally 6
b[3] = cmd;
b[4] = 1; //Need Feedback. 0 = No. 1 = Yes.
b[5] = param1;
b[6] = param2;
//Bytes 7 and 8 are Check Sum.
// Calc Check Sum
CheckSum(b);
b[9] = 0xEF; //End Byte
// Send data to DF Player
Serial.print("-> Send: ");
for (int i = 0; i < 10; i++) {
SoftSerial.write(b[i]);
Serial.print(b[i], HEX);
Serial.print(",");
}
Serial.println();
byte rtn[20];
return GetResult(rtn);
}
void CheckSum(byte code[]) {
unsigned int sum = 0;
for (int i = 1; i < 7; i++)
sum += code[i];
sum = 0xFFFF - sum + 1;
//Serial.println();
//Serial.print("CheckSum ");
//Serial.println(sum >> 8, HEX); //High Order Byte
//Serial.println(sum & 0xff, HEX); //Low Order Byte
code[7] = sum >> 8; //High Order Byte
code[8] = sum & 0xFF; //Low Order Byte
}
byte GetResult(byte rtn[]) {
byte b = 0;
int idx = 0;
unsigned long startMillis = millis();
// 0xEF End Byte
while ((b != 0xEF) && abs(startMillis - millis()) < 500) {
if (SoftSerial.available())
{
b = SoftSerial.read();
rtn[idx++] = b;
}
}
ProcessRtn(rtn, idx);
return rtn[3];
}
byte ProcessRtn(byte b[], int cnt) {
Serial.print("<- Return: ");
for (int i = 0; i < cnt ; i++) {
Serial.print(b[i], HEX);
Serial.print(",");
}
Serial.println();
switch (b[3]) {
case 0x40: //Module Returned an Error
GetErrorText(b[6]);
break;
case 0x41: //Module Returned Feedback Response
Serial.println("Cmd Processed");
break;
case 0x42:
Serial.print("Current Status: ");
switch (b[6]) {
case 0:
Serial.println("Stopped");
break;
case 1:
Serial.println("Playing");
break;
case 2:
Serial.println("Paused");
break;
}
break;
case 0x48:
Serial.print("Root File Count: ");
Serial.println((b[5] << 8) + b[6]);
break;
case 0x3A:
if (b[6] = 2)
Serial.println("SD Card Inserted");
break;
case 0x3b:
if (b[6] = 2)
Serial.println("SD Card Removed");
break;
case 0x3c:
case 0x3D:
Serial.println("Track Finished");
break;
}
return b[3];
}
void GetErrorText(byte n) {
switch (n) {
case 1:
Serial.println("Error: Module Busy");
break;
case 2:
Serial.println("Error: Sleep Mode");
break;
case 3:
Serial.println("Error: Serial Error");
break;
case 4:
Serial.println("Error: Checksum error");
break;
case 5:
Serial.println("Error: Checksum error");
break;
case 6:
Serial.println("Error: Specified track is not found");
break;
case 7:
Serial.println("Error: Insertion error");
break;
case 8:
Serial.println("Error: SD card reading failed");
break;
case 0xA:
Serial.println("Error: ntered into sleep mode");
break;
default:
Serial.println("Error: SD card reading failed(");
break;
}
}
I do have a "NTP" File at is referenced in some function calls. It handles some UTC offset and automatically handles DST
void AdjustTime(){
unsigned long epochTime = ntpClientX.getEpochTime();
int offset = (TimeOffset + isDST(epochTime)) * 3600;
ntpClientX.setTimeOffset(offset);
}
bool isDST(unsigned long epochTime) {
//Get a time structure
struct tm *ptm = gmtime ((time_t *) & epochTime);
int intDay = ptm->tm_mday;
int intMonth = ptm->tm_mon + 1;
int dow = ntpClientX.getDay();
//Serial.print(intMonth);
//Serial.print("/");
//Serial.println(intDay);
if (intMonth < 3 || intMonth > 11) return 0;
if (intMonth > 3 && intMonth < 11) return 1;
int previousSunday = intDay - dow;
//In march, we are DST if our previous Sunday was on or after the 8th.
if (intMonth == 3) return previousSunday >= 8;
//In November we must be before the first Sunday to be DST.
//That means the previous Sunday must be before the 1st.
return previousSunday <= 0;
}
As referenced previously, I am using the ESP8266 Node MCU with built in WiFI and the DF Player Module. I was not able to get the DF Player library working with the arduino, so I put my own code together.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.