stevie135s
Published © GPL3+

Chiming Clock

An update of a previous big ben digital chiming clock, with an Android bluetooth app to adjust the time and set the date on boot up.

IntermediateWork in progress5 hours52
Chiming Clock

Things used in this project

Hardware components

DFPlayer - A Mini MP3 Player
DFRobot DFPlayer - A Mini MP3 Player
×1
esp32 d1 wemos
×1
ST7735S Colour Display
×1
PI DS3231
×1

Story

Read more

Custom parts and enclosures

Sound File Zip

Put these one at a time onto a Fat32 formatted micro sdcard

Android App

Connect to the project over bluetooth at boot to set the time

Schematics

Circuit

Wiring for the ESP32 Wemos D1 Mini

Code

Chiming_Clock

Arduino
Arduino Code
/*  **************************************************************************
     Digital Chiming Clock Project using ST7735 80 x 160 (RGB) .96 inch IPS Display
     With an ESP32 Wemos D1 and a DS3231 RTC:
     Set The Time Using Bluetooth Low Energy every bootup (20second scan)
     Before Going To Clock Mode.

     Pin Used With The ESP32 :
     IO22 SCL RTC
     IO21 SDA RTC

     RST RST  ST7735
     GPIO 5 CS
     GPIO 26 DC
     GPIO 18 SCL/SCK *These markings are confusing
     GPIO 23 MOSI

     **************************************************************************
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <DFRobotDFPlayerMini.h>
#include <SPI.h>
#include <DS3231.h>      //https://github.com/NorthernWidget/DS3231/releases
#include <Wire.h>

#define TFT_RST  -1
#define TFT_CS   5
#define TFT_DC   26

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
DFRobotDFPlayerMini myDFPlayer;
DS3231 myRTC;

// inverted color definitions
#define BLACK   0xFFFF
#define WHITE   0x0000
#define BLUE    0x07FF
#define RED     0xFFE0
#define GREEN   0xF81F
#define YELLOW  0xF800
#define BROWN   0x9F6D
#define L_BLUE  0x51E4

#define SERVICE_UUID        "fe45c941-9b87-4ef1-ac31-990dd686f813"
#define CHARACTERISTIC_UUID "ebc2e890-8ad5-4d51-a4a1-0e60efc9df4a"

String BT_IN;
char inString[13];
byte L_Hour = 18;   // Last Hour
byte L_Min = 43;    // Last Minute
byte L_Sec = 10;    // Last Second
byte L_Dow = 6;     // Last Day Of The Week
byte L_Date = 11;   // Last Date
byte L_Month = 11;  // Last Month
byte L_Temp = 28;   // Last Temperature
byte L_Year;        // Last Year
byte YEAR = 20;     // Year 2000
byte YEAR_2;        // Last 2 digits of the year

byte Sec, Min, HOUR, Hour2, Dow, Date, MONTH, Temp; // Variables from RTC
bool h12Flag, pmFlag;                     //Unused 12h pm Flags
bool century = false;
bool Blink = 1;
byte Led = 2; // Led Pin Used On The ESP32 Wemos

String DAYS_OF_WEEK [] {"Dummy", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
uint32_t value = 0;
bool deviceConnected = false;
bool deviceDisconnected = false;

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      deviceDisconnected = false;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      deviceDisconnected = true;
    }
};

void Set_DS3231 () {
  while (deviceConnected) {
    std::string value = pCharacteristic->getValue();
    if (value.length() == 15) {
      BT_IN = (value.c_str());
      pCharacteristic->setValue("");
      inString[0] = BT_IN[0]; //Y
      inString[1] = BT_IN[1]; //Y
      inString[2] = BT_IN[2]; //M
      inString[3] = BT_IN[3]; //M
      inString[4] = BT_IN[4]; //D
      inString[5] = BT_IN[5]; //D
      inString[6] = BT_IN[6]; //w
      inString[7] = BT_IN[7]; //H
      inString[8] = BT_IN[8]; //H
      inString[9] = BT_IN[9]; //M
      inString[10] = BT_IN[10]; //M
      inString[11] = BT_IN[11]; //S
      inString[12] = BT_IN[12]; //S


      YEAR_2 = (((inString[0] - 48) * 10) + (inString[1] - 48));
      // now month
      MONTH = (((inString[2] - 48) * 10) + (inString[3] - 48));
      // now date
      Date = (((inString[4] - 48) * 10) + (inString[5] - 48));
      // now Day of Week
      Dow = (inString[6] - 48);
      // now hour
      HOUR = (((inString[7] - 48) * 10) + (inString[8] - 48));
      // now minute
      Min = (((inString[9] - 48) * 10) + (inString[10] - 48));
      // now second
      Sec = (((inString[11] - 48) * 10) + (inString[12] - 48));

      myRTC.setClockMode(false);// set to 24h
      myRTC.setYear(YEAR_2);
      myRTC.setMonth(MONTH);
      myRTC.setDate(Date);
      myRTC.setDoW(Dow);
      myRTC.setHour(HOUR);
      myRTC.setMinute(Min);
      myRTC.setSecond(Sec);
      myRTC.turnOffAlarm(1);
      myRTC.turnOffAlarm(2);
      Serial.println("The Time Has Been Set");
      delay(600);
      BLEDevice:: deinit(true);
      Serial.println("Bluetooth has been turned off");
      delay(600);             // Allow RTC registers to set before any read occurs

    }
  }
}
void setup () {
  Serial1.begin(9600,SERIAL_8N1,10,9);
  myDFPlayer.begin(Serial1);
  pinMode(Led, OUTPUT);
  tft.initR (INITR_BLACKTAB);
  tft.setRotation (3);    // Display Lasdscape
  tft.fillScreen (BLACK);
  Wire.begin();

  BLEDevice::init("Chiming Clock");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
  pCharacteristic->addDescriptor(new BLE2902());
  pCharacteristic->setValue("");
  pService->start();
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  BLEDevice::startAdvertising();

  myDFPlayer.volume(15);
  myDFPlayer.play(25);
  delay (5000);

  // Loop While Waiting For Bluetooth

  for (int x = 26; x < 46; x++) {
    if (!deviceConnected) {
       myDFPlayer.volume(15);
       myDFPlayer.play(x);
    }
    else {
      x = 47;
    }
    digitalWrite(Led, Blink);
    Blink = !Blink;
    delay(800);
  }
  digitalWrite(Led, LOW);
  
  Set_DS3231();
  BLEDevice::deinit(); // Turn Off Bluetooth

  LinesDraw();   // Draw Lines Routine
  MONTH = myRTC.getMonth(century);
  if (century) {         // Year 2100
    YEAR = 21;
  }
  YEAR_2 = myRTC.getYear();
  L_Year = YEAR_2;
  TextDraw();            // Display All Screen Text
  tft.setTextSize(3);    // Time Text Size



}

void loop () {

  Sec = myRTC.getSecond();
  if (Sec != L_Sec) {
    Sec_Print();
  }
  Min = myRTC.getMinute();
  if (Min != L_Min) {
    Min_Print();
  }
  HOUR = myRTC.getHour(h12Flag, pmFlag);
  if (HOUR != L_Hour) {
    Hour_Print();
  }
  Dow = myRTC.getDoW();
  if (L_Dow != Dow) {
    tft.setTextSize(2);
    Dow_Print();
    tft.setTextSize(3);
  }




  Date = myRTC.getDate();
  if (L_Date != Date) {
    tft.setTextSize(2);
    Date_Print();


    MONTH = myRTC.getMonth(century);
    if (L_Month != MONTH) {
      Month_Print();

      YEAR_2 = myRTC.getYear();
      if (YEAR_2 != L_Year) {
        if (century) {
          YEAR = 21;
        }
        Year_Print();

      }
    }
    tft.setTextSize(3);
  }

  Temp = myRTC.getTemperature();
  if (L_Temp != Temp) {
    tft.setTextSize(2);
    Temp_Print();
    tft.setTextSize(3);
  }
  if ((Min == 59) && (Sec == 40)) {
    Hour2 = HOUR + 1;
    chime();
  }
}

void LinesDraw() {    //Draw The Screen Borders

  tft.drawLine(3, 54, 157, 54, RED);
  tft.drawLine(3, 55, 157, 55, RED);
  tft.drawLine(3, 80, 157, 80, RED);
  tft.drawLine(3, 81, 157, 81, RED);
  tft.drawLine(112, 56, 112, 79, RED);
  tft.drawLine(113, 56, 113, 79, RED);

  tft.drawRect(1, 26, 159, 80, RED);
  tft.drawRect(2, 27, 157, 78, RED);

  tft.fillRect(114, 55, 44, 25, BROWN); // Temperature Box
}
void TextDraw() {     //Set up Startup Screen
  tft.setTextSize(3);
  tft.setTextColor(WHITE);
  tft.setCursor(10, 30);
  tft.print(L_Hour);
  tft.print(":");
  tft.print(L_Min);
  tft.print(":");
  tft.print(L_Sec);

  tft.setTextSize(2);
  tft.setTextColor(GREEN);
  tft.setCursor(4 + ((108 - (DAYS_OF_WEEK [L_Dow].length()) * 12) / 2), 60);
  tft.print(DAYS_OF_WEEK [L_Dow]);

  tft.setTextColor(L_BLUE);
  tft.setCursor(20, 86);
  tft.print("11/11/");
  tft.print(YEAR);
  tft.print(L_Year);

  tft.setTextColor(YELLOW);
  tft.setCursor(120, 60);
  tft.print("28c");
}

void Sec_Print () {      // Print Seconds
  tft.setTextColor(BLACK);
  tft.setCursor(118, 30);
  if (L_Sec < 10) {
    tft.print("0");
  }
  tft.print(L_Sec);
  L_Sec = Sec;
  tft.setTextColor(WHITE);
  tft.setCursor(118, 30);
  if (L_Sec < 10) {
    tft.print("0");
  }
  tft.print(L_Sec);
}

void Min_Print () {    // Print Minutes
  tft.setTextColor(BLACK);
  tft.setCursor(64, 30);
  if (L_Min < 10) {
    tft.print("0");
  }
  tft.print(L_Min);
  L_Min = Min;
  tft.setTextColor(WHITE);
  tft.setCursor(64, 30);
  if (L_Min < 10) {
    tft.print("0");
  }
  tft.print(L_Min);
}

void Hour_Print () {   // Print Hours
  tft.setTextColor(BLACK);
  tft.setCursor(10, 30);
  if (L_Hour < 10) {
    tft.print("0");
  }
  tft.print(L_Hour);
  L_Hour = HOUR;
  tft.setTextColor(WHITE);
  tft.setCursor(10, 30);
  if (L_Hour < 10) {
    tft.print("0");
  }
  tft.print(L_Hour);
}

void Dow_Print() {     // Print Days Of The Week String
  tft.setTextColor(BLACK);
  tft.setCursor(4 + ((108 - (DAYS_OF_WEEK [L_Dow].length()) * 12) / 2), 60);
  tft.print(DAYS_OF_WEEK [L_Dow]);
  L_Dow = Dow;
  tft.setTextColor(GREEN);
  tft.setCursor(4 + ((108 - (DAYS_OF_WEEK [L_Dow].length()) * 12) / 2), 60);
  tft.print(DAYS_OF_WEEK[L_Dow]);
}

void Date_Print() {     // Print Date
  tft.setTextColor(BLACK);
  tft.setCursor(20, 86);
  if (L_Date < 10) {
    tft.print("0");
  }
  tft.print(L_Date);
  L_Date = Date;
  tft.setTextColor(L_BLUE);
  tft.setCursor(20, 86);
  if (L_Date < 10) {
    tft.print("0");
  }
  tft.print(L_Date);
}

void Month_Print() {    // Print Month
  // 56x  86y
  tft.setTextColor(BLACK);
  tft.setCursor(56, 86);
  if (L_Month < 10) {
    tft.print("0");
  }
  tft.print(L_Month);
  L_Month = MONTH;
  tft.setTextColor(L_BLUE);
  tft.setCursor(56, 86);
  if (L_Month < 10) {
    tft.print("0");
  }
  tft.print(L_Month);
}

void Temp_Print() {     // Print Temperature
  tft.setTextColor(BROWN);
  tft.setCursor(120, 60);
  if (L_Temp < 10) {
    tft.print("0");
  }
  tft.print(L_Temp);
  L_Temp = Temp;
  tft.setTextColor(YELLOW);
  tft.setCursor(120, 60);
  if (L_Temp < 10) {
    tft.print("0");
  }
  tft.print(L_Temp);
}

void Year_Print() {       // Print the Year
  tft.setTextColor(BLACK);
  tft.setCursor(91, 86);
  tft.print(YEAR);
  tft.print(L_Year);
  tft.setTextColor(L_BLUE);
  tft.setCursor(91, 86);
  tft.print(YEAR);
  L_Year = YEAR_2;
  tft.print(L_Year);
}

void chime() {
  myDFPlayer.volume(15);
  switch (Hour2) {
    case 1:
      myDFPlayer.play(13);
      break;
    case 2:
      myDFPlayer.play(14);
      break;
    case 3:
      myDFPlayer.play(15);
      break;
    case 4:
      myDFPlayer.play(16);
      break;
    case 5:
      myDFPlayer.play(17);
      break;
    case 6:
      myDFPlayer.play(6);
      break;
    case 7:
      myDFPlayer.play(7);
      break;
    case 8:
      myDFPlayer.play(8);
      break;
    case 9:
      myDFPlayer.play(9);
      break;
    case 10:
      myDFPlayer.play(10);
      break;
    case 11:
      myDFPlayer.play(11);
      break;
    case 12:
      myDFPlayer.play(12);
      break;
    case 13:
      myDFPlayer.play(1);
      break;
    case 14:
      myDFPlayer.play(2);
      break;
    case 15:
      myDFPlayer.play(3);
      break;
    case 16:
      myDFPlayer.play(4);
      break;
    case 17:
      myDFPlayer.play(5);
      break;
    case 18:
      myDFPlayer.play(6);
      break;
    case 19:
      myDFPlayer.play(7);
      break;
    case 20:
      myDFPlayer.play(8);
      break;
    case 21:
      myDFPlayer.play(9);
      break;
    case 22:
      myDFPlayer.play(22);
      break;
    case 23:
      myDFPlayer.play(23);
      break;
    case 24:
      myDFPlayer.play(24);
      break;
  }
}

Credits

stevie135s

stevie135s

22 projects • 10 followers

Comments