Digital clock with ESP32 RTC and LED Matrix

This is another ESP32 with RTC and LED matrix project. This time I have put a ping pong visualization just for fun.

About the Circuit

Still same as my last post. It uses an ESP32 module with RTC module and LED matrix module.

Code

Here is the modified code from my last post. The code is not optimize.

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>  tataylino.com  <<<<<<<<<<<<<<<<<<<<<<<<<
// Dot matrix clock using RTC module
// by: tataylino.com
// Reference:
// https://randomnerdtutorials.com/esp32-ds3231-real-time-clock-arduino/
// https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA


//------  Including the libraries ----------
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#include "time.h"
#include "RTClib.h"

RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

//----------------------------------------Defines the connected PIN between P5 and ESP32.
#define R1_PIN 19
#define G1_PIN 13
#define B1_PIN 18
#define R2_PIN 5
#define G2_PIN 12
#define B2_PIN 17

#define A_PIN 16
#define B_PIN 14
#define C_PIN 4
#define D_PIN 27
#define E_PIN 25  //--> required for 1/32 scan panels, like 64x64px. Any available pin would do, i.e. IO32.

#define LAT_PIN 26
#define OE_PIN 15
#define CLK_PIN 2
//----------------------------------------

//----------------------------------------Defines the P5 Panel configuration.
#define PANEL_RES_X 64  //--> Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 64  //--> Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_CHAIN 1   //--> Total number of panels chained one to another
//----------------------------------------

// Initialize MatrixPanel_I2S_DMA as "dma_display".
MatrixPanel_I2S_DMA *dma_display = nullptr;

//----------------------------------------Variable for color.
// color565(0, 0, 0); --> RGB color code. Use the "color picker" to use or find another color code.
uint16_t myBLACK = dma_display->color565(0, 0, 0);
uint16_t myWHITE = dma_display->color565(255, 255, 255);
uint16_t myRED = dma_display->color565(255, 0, 0);
uint16_t myGREEN = dma_display->color565(0, 255, 0);
uint16_t myBLUE = dma_display->color565(0, 0, 255);
uint16_t clock_bg = dma_display->color565(10, 10, 0);

// *************  Clock Colors ************
// Colors - value is from 0 to 15 only
uint8_t s_hand_rgb[] =  {12,1,1};   // Second Hand
uint8_t m_hand_rgb[] =  {1,1,12};   // Minute Hand
uint8_t h_hand_rgb[] =  {1,12,1};   // hour hand
uint8_t num_rgb[] =     {1,10,10};  // numbers
uint8_t dot_rgb[] =     {10,10,1};  // dots
// digital clock colors
uint8_t time_rgb[] =     {12,12,12};  // time
uint8_t days_rgb[] =     {14,8,1};  // days of the week
uint8_t date_rgb[] =     {1,10,10};  // date


// Screen Brightness
uint8_t led_brightness = 100; // 0 to 255

//----------------------------------------
#define clear()          matrix.fillScreen(0)
#define show()           matrix.swapBuffers(false)
#define WIDTH 64
#define HEIGHT 64
const byte CENTRE_X = 32;
const byte CENTRE_Y = 32;

uint8_t second;
uint8_t second_h;
uint8_t minute;
uint8_t minute_h;
uint8_t hour;
uint8_t hour_h;
uint8_t date_day;
uint8_t date_month;
uint16_t date_year;

DateTime now;

String day;

String yearStr ;
String monthStr ;
String dayStr;
String hourStr;
String minuteStr ;
String secondStr ;
String dayOfWeek ;

String datenowstr;
String timenowstr;


void drawclockNB() {
  // Draw clock Numbers
  dma_display->setTextColor(dma_display->color444(num_rgb[0], num_rgb[1], num_rgb[2]));
  dma_display->setTextSize(1); 
  dma_display->setCursor(43, 8);  dma_display->println("1");
  dma_display->setCursor(51, 15); dma_display->println("2");
  dma_display->setCursor(56, 29); dma_display->println("3");
  dma_display->setCursor(51, 40); dma_display->println("4");
  dma_display->setCursor(43, 49); dma_display->println("5");
  dma_display->setCursor(30, 54); dma_display->println("6");
  dma_display->setCursor(17, 49); dma_display->println("7");
  dma_display->setCursor(8, 40);  dma_display->println("8");
  dma_display->setCursor(4, 29);  dma_display->println("9");
  dma_display->setCursor(7, 17);  dma_display->println("10");
  dma_display->setCursor(14, 8);  dma_display->println("11");
  dma_display->setCursor(26, 4);  dma_display->println("12");
}

void drawclockDot() {
  // Draw clock dots
      float radians, angle;
      for (int i = 0; i < 60; i+=5) {
        //uint16_t color = MyColor[(co0+i*5)%92];
        angle =  360 - i * 6;
        radians = radians(angle);
        int x0 = CENTRE_X + 30 * sin(radians);
        int y0 = CENTRE_Y + 30 * cos(radians);
        //matrix.fillCircle(x0, y0, 1, color);
        dma_display->drawCircle(x0, y0, 1, dma_display->color444(dot_rgb[0], dot_rgb[1], dot_rgb[2]));
     }
}

void draw_hand(uint8_t val, uint8_t lenght, uint8_t r, uint8_t g, uint8_t b ){
  float radians, angle;
  val = val + 30; // offset
  angle =  360 - val * 6;
  radians = radians(angle);
  int x0 = CENTRE_X + lenght * sin(radians);
  int y0 = CENTRE_Y + lenght * cos(radians);
  dma_display->drawLine(CENTRE_X, CENTRE_Y, x0, y0, dma_display->color444(r, g, b));
}


void draw_analog_clock(void){
    //compute hands position
  second_h = second;
  minute_h = minute;
  if(hour>12){
    hour_h = ((hour - 12) * 5) + (minute/12);
  } else {
    hour_h = (hour * 5) + (minute/12);
  }
  dma_display->clearScreen();
  dma_display->fillScreen(clock_bg);
  drawclockNB();
  drawclockDot();
  //draw_minute(minute);
  draw_hand(second_h, 22, s_hand_rgb[0], s_hand_rgb[1], s_hand_rgb[2]);  // Second Hand
  draw_hand(minute_h, 18, m_hand_rgb[0], m_hand_rgb[1], m_hand_rgb[2]);  // Minute Hand
  draw_hand(hour_h,   12, h_hand_rgb[0], h_hand_rgb[1], h_hand_rgb[2]);  // Hour Hand
  dma_display->drawCircle(CENTRE_X, CENTRE_Y, 33, dma_display->color444(10, 0, 0)); // outer circle
  dma_display->drawCircle(CENTRE_X, CENTRE_Y, 1, dma_display->color444(10, 0, 0));  // center circle
}

void draw_digital_clock(void){
  static uint8_t min_prev = 0;

  if(hour > 12){ hour = hour - 12; }
  if(hour == 0){ hour = 12;}
    // Getting each time field in individual variables
  // And adding a leading zero when needed;
   yearStr = String(now.year(), DEC);
   monthStr = (now.month() < 10 ? "0" : "") + String(now.month(), DEC);
   dayStr = (now.day() < 10 ? "0" : "") + String(now.day(), DEC);
   hourStr = (hour < 10 ? "0" : "") + String(hour, DEC); 
   minuteStr = (now.minute() < 10 ? "0" : "") + String(now.minute(), DEC);
   secondStr = (now.second() < 10 ? "0" : "") + String(now.second(), DEC);
   dayOfWeek = daysOfTheWeek[now.dayOfTheWeek()];

  datenowstr = monthStr + "/" + dayStr + "/" + yearStr;
  timenowstr = hourStr + ":" + minuteStr;

  if(min_prev != now.minute()){ // clear screen only when minute changes
    min_prev = now.minute();
    //dma_display->clearScreen();
  }
  dma_display->clearScreen();
  
  
  dma_display->setTextSize(2); 
  dma_display->setCursor(3, 2); 
  dma_display->setTextColor(dma_display->color444(time_rgb[0], time_rgb[1], time_rgb[2]));
  dma_display->println(timenowstr);

  dma_display->setTextSize(1); 
  dma_display->setCursor(3, 18); 
  dma_display->setTextColor(dma_display->color444(days_rgb[0], days_rgb[1], days_rgb[2]));
  dma_display->println(day);

  dma_display->setCursor(2, 27); 
  dma_display->setTextColor(dma_display->color444(date_rgb[0], date_rgb[1], date_rgb[2]));
  dma_display->println(datenowstr);

  //dma_display->drawCircle(now.second(), 50, 1, dma_display->color444(dot_rgb[0], dot_rgb[1], dot_rgb[2]));
  pingpong_show();

}

void pingpong_show(void){
  static uint8_t x_dir = 0;
  static uint8_t y_dir = 0;
  static uint8_t x = 2;
  static uint8_t y = 40;
  static uint8_t y_lim = 37;
  static uint8_t bar_x_pos = 4;

  if(x_dir == 0){
    x++;
    if(x>60){ x_dir = 1;}
  } else {
    x--;
    if(x<3){x_dir=0;}
  }

  if(y_dir == 0){
    y++;
    if(y>59){ y_dir = 1;}
    // bar tracking
    if(bar_x_pos > x-3){
      if((bar_x_pos - x) > 1) bar_x_pos-=3; else bar_x_pos-=1;
    } else {
      if((x - bar_x_pos) > 4)bar_x_pos+=3; else bar_x_pos+=1;
    }
    //limit bar x position
    if(bar_x_pos>54) bar_x_pos = 54;
  } else {
    y--;
    if(y<y_lim) y_dir=0;  
  }

  if(x_dir == 1 && y_dir == 1){
    dot_rgb[0] = 15;
    dot_rgb[2] = 15;
  }
    if(x_dir == 0 && y_dir == 1){
    dot_rgb[0] = 15;
    dot_rgb[2] = 0;
  }
    if(x_dir == 1 && y_dir == 0){
    dot_rgb[0] = 0;
    dot_rgb[2] = 15;
  }
    if(x_dir == 0 && y_dir == 0){
    dot_rgb[0] = 0;
    dot_rgb[2] = 0;
  }

  dma_display->drawCircle(x, y, 2, dma_display->color444(dot_rgb[0], dot_rgb[1], dot_rgb[2]));

  dma_display->drawLine(bar_x_pos, 63, bar_x_pos +8, 63, dma_display->color444(15, 15, 0));

}

//________________________________________________________________________________VOID SETUP()
void setup() {
  Serial.begin(115200);
  Serial.println("tataylino.com - Starting clock");
  delay(1000);

  // Initialize the connected PIN between Panel P5 and ESP32.
  HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
  delay(10);

  //----------------------------------------Module configuration.
  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X,   //--> module width.
    PANEL_RES_Y,   //--> module height.
    PANEL_CHAIN,   //--> Chain length.
    _pins          //--> pin mapping.
  );
  delay(10);
  //----------------------------------------

  // Set I2S clock speed.
  mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M;  // I2S clock speed, better leave as-is unless you want to experiment.
  delay(10);

  //----------------------------------------Display Setup.
  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
  dma_display->setBrightness8(led_brightness); //--> 0-255.
  //----------------------------------------
  
  dma_display->clearScreen();
  dma_display->fillScreen(myGREEN);
  delay(500);
  dma_display->fillScreen(myBLUE);
  delay(500);
  
  dma_display->clearScreen();
  delay(100);

    if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  // When time needs to be re-set on a previously configured device, the
  // following line sets the RTC to the date & time this sketch was compiled
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  //rtc.adjust(DateTime(2025, 6, 22, 20, 20, 0));

  Serial.println("Initialization done!");


}
//________________________________________________________________________________

//________________________________________________________________________________VOID LOOP()
void loop() {
  // Get the current time from the RTC
  now = rtc.now();
  
  // Complete time string
  //String formattedTime = dayOfWeek + ", " + yearStr + "-" + monthStr + "-" + dayStr + " " + hourStr + ":" + minuteStr + ":" + secondStr;

  // Print the complete formatted time
  //Serial.println(formattedTime);
  //Serial.println(now.hour());
  //Serial.println(now.minute());
  //Serial.println(now.second());

  // initial settings
  second = now.second();
  minute = now.minute();
  hour = now.hour();
  day = daysOfTheWeek[now.dayOfTheWeek()];
  date_day = now.day();
  date_year = now.year();
  date_month = now.month();

// change face at night
if(hour > 18 || hour < 12){
  draw_digital_clock();
} else {
  //draw_analog_clock();
  draw_digital_clock();
}

  // Getting temperature
  //Serial.print(rtc.getTemperature());
  //Serial.println("ÂșC");

  //Serial.println();
  delay(250);

}
//________________________________________________________________________________
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<