// simple project using Arduino UNO and Matrix LED Display MAX7219 with u8g2 library
// to create a counter for example for counting youtube subscribers

// created by upir, 2023
// youtube channel: https://www.youtube.com/upir_upir

// Arduino + Matrix Display (The Proper Way)
// YOUTUBE VIDEO: https://youtu.be/jlhcDzS17vU

// links from the video:
// Photopea (online Photoshop-like tool): https://www.photopea.com/
// image2cpp (convert images into C code): https://javl.github.io/image2cpp/
// Starting sketch: https://github.com/olikraus/u8g2/blob/master/sys/arduino/u8g2_full_buffer/MAX7219_U8g2/MAX7219_U8g2.ino
// WOKWI display documentation: https://docs.wokwi.com/parts/wokwi-max7219-matrix
// U8g2 + Matrix display screenshot: https://github.com/olikraus/u8g2/wiki/gallery#28-may-2017-max7219-32x8-led-matrix
// U8g2 fonts: https://github.com/olikraus/u8g2/wiki/fntlist8#7-pixel-height
// Desmos online graphs: https://www.desmos.com/calculator?lang=en
// LCD Image converter: https://lcd-image-converter.riuson.com/en/about/

#include <WiFi.h>
#include <time.h>
#include <Arduino.h>
#include <U8g2lib.h>

// Turn on debug statements to the serial output
#define DEBUG  1
#define WIFICONNECT 1

#if DEBUG
  #define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
  #define PRINTS(x) Serial.print(F(x))
  #define PRINTD(x) Serial.println(x, DEC)
#else
  #define PRINT(s, x)
  #define PRINTS(x)
  #define PRINTD(x)
#endif

//For ESP32
U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18, /* data=*/ 13, /* cs=*/ 15, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);

//For ESP8266
// U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 12, /* data=*/ 15, /* cs=*/ 13, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);

// uint8_t is a byte 
byte digits[2] = {5, 5}; // individual digits to be displayed on the matrix display
byte digits_offset_perc[2] = {0, 0}; // y offset for the individual digits - percentage 0-100%

byte digitsHour[2] = {1, 2}; // individual digits to be displayed on the matrix display
byte digitsHour_offset_perc[2] = {0, 0}; // y offset for the individual digits - percentage 0-100%

//1 digit is int, 2 digit is for /n end of string
char digit_char[2]; // helper array for storing C-style string
char digit_char_next[2]; // helper array for storing C-style string

float y_offset; // y pixel offset for digit
// from upiir ------------------------------------------

#define MAX_MESG  20

/**********  User Config Setting   ******************************/
char* ssid = "Wokwi-GUEST";
char* password = "";
//calculate your timezone in seconds,1 hour = 3600 seconds and 5.30Hrs = 19800
const int timezoneinSeconds = 25200;
/***************************************************************/
int dst = 0;
uint16_t  h, m, s;
uint8_t  now;
int  day;
uint8_t month;
String  year;
// Global variables
// char szTime[9];    // mm:ss\0
// char szsecond[4];    // ss
char szMesg[MAX_MESG+1] = "";

char szTime[3];    // mm:ss\0
char szsecond[3];    // ss


#define NTP_SERVER1     "pool.ntp.org"
#define NTP_SERVER2     "time.nist.gov"
#define UTC_OFFSET     25200
#define UTC_OFFSET_DST 0

String myIPadd;
struct tm timeinfo;

// void getsec(char *psz) //char *str = 
// {
//   sprintf(psz, "%02d", s);  //sprintf(buffer,"%02d:%02d:%02d",hour,minute,second);
//     //sprintf = store print formatted
//     //printf = send to console formatted
//     //both return value = no. of characters stored/print
//     // e.g.  sprintf(str, "Result of substraction of values %f and %f is %f" , num1, num2, result);
// }
// void getTime(char *psz, bool f = true)
// {
//   time_t now = time(nullptr);
//   struct tm* p_tm = localtime(&now);
//       h = p_tm->tm_hour;
//       m = p_tm->tm_min;
//       s = p_tm->tm_sec;

//   sprintf(psz, "%02d%c%02d", h, ':', m); //%c = character, in this case ":"
//   // sprintf(psz, "%02d%c%02d", h, (f ? ':' : ' '), m);
//   // Serial.println(psz);
// }

void getMin(char *psz) {//char *str = 
sprintf(psz, "%02d", m); 
  // sprintf(psz, "%02d", s);  //sprintf(buffer,"%02d:%02d:%02d",hour,minute,second);
    //sprintf = store print formatted
    //printf = send to console formatted
    //both return value = no. of characters stored/print
    // e.g.  sprintf(str, "Result of substraction of values %f and %f is %f" , num1, num2, result);
}

void getHour(char *psz)
{
  time_t now = time(nullptr);
  struct tm* p_tm = localtime(&now);
      h = p_tm->tm_hour;
      m = p_tm->tm_min;
      s = p_tm->tm_sec;

  sprintf(psz, "%02d", h); //%c = character, in this case ":"
  // sprintf(psz, "%02d%s%02d", h, (f ? ":" : "."), m);
  // sprintf(psz, "%02d%c%02d", h, (f ? ':' : ' '), m);
  // Serial.println(psz);
  // if (f) {
  //   sprintf(psz, "%02d:02d", h, m);
  // }
  // else {

  // }
}



void setup() {
  Serial.begin(115200);

   #if WIFICONNECT
     Serial.print("Connecting to WiFi");
    WiFi.begin(ssid, password, 6);
    // WiFi.begin("Wokwi-GUEST", "", 6);
    while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.print(".");
    }
    Serial.println(" Connected!");
    Serial.println(WL_CONNECTED);
    Serial.println(WiFi.status());

    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    delay(3000);
    WiFi.mode(WIFI_STA);

    configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER1, NTP_SERVER2);
    while(!time(nullptr)){
          delay(500);
          Serial.print(".");
    }
    Serial.print("Time Update");

  #endif


  u8g2.begin(); // begin function is required for u8g2 library
  u8g2.setContrast(10*16); // set display contrast 0-255
  // getTime(szTime);
  getHour(szTime);
    // pinMode(7, INPUT_PULLUP);
}

void loop() {

  static uint32_t lastTimeText = 0; // millis() memory
  static uint32_t lastTime = 0; // millis() memory
  static uint8_t  display = 0;  // current display mode
  static bool flasher = false;  // seconds passing flasher

  //  // button is pressed
  // if (digitalRead(7) == LOW) { 
  //   if (digits_offset_perc[1] == 0) { // no animation is currently playing for the last digit
  //     digits_offset_perc[1] = 2; // in that case, animate the last digit (increment the last digit)
  //   }
  // }

 if (millis() - lastTime >= 1000)
  {
    
    // getsec(szsecond);
    // getTime(szTime, flasher);
    
    getMin(szsecond);
    getHour(szTime);

    u8g2.clearBuffer();	// clear the internal u8g2 memory
    u8g2.setFont(u8g2_font_minuteconsole_tr);	// choose a suitable font with digits 3px wide
    //  u8g2.setFont(u8g2_font_micro_tr);
        
    if (flasher) {
      u8g2.drawStr(9, 7, ":");
    }
    
    u8g2.drawStr(1, 7, szTime);
    u8g2.drawStr(11, 7, szsecond);

    // u8g2.drawBitmap(0, 0, 1, 7, youtube_logo_bitmap); // draw youtube logo on top left corner
    // u8g2.drawStr(0,7,"Yeah!!!");
    // u8g2.drawBitmap(0, 0, 4, 8, preview_time); 
    //  u8g2.drawStr(1,7,"12:59");


  // for (int i=1; i>=0; i--) { // go from the last digit to the first digit

  //   if (digits_offset_perc[i] > 0) { // animate the digit
  //     digits_offset_perc[i] = digits_offset_perc[i] + 2; // increase the percentage offset

  //     if ((digits[i] == 9) && (digits_offset_perc[i-1] == 0) && (digits_offset_perc[i] > 20)) {
  //       digits_offset_perc[i-1] = 2; // digit is 9 turning to 0 = increase digit on the left side
  //     }

  //     if (digits_offset_perc[i] >= 100) { // animation is complete, switch to the next digit
  //       digits_offset_perc[i] = 0; // stop the animation
  //       digits[i] = digits[i] + 1; // switch to the next digit

  //       if (digits[i] == 6) { // if the digit goes over 9, go back to 0
  //         digits[i] = 0;
  //       }
  //     }
  //   }

    // linear movement of digits - looks boring
    //y_offset = round((digits_offset_perc[i] / 100.0) * 8.0); // calculate the Y pixel offset
    // easing using the power function - looks strange for continuous animation
    //y_offset = round(pow((digits_offset_perc[i] / 100.0), 0.4) * 8.0);
    // easing using the cosine function - looks great
    // y_offset = round((1-((cos(digits_offset_perc[i] / 100.0 * 3.141592654) / 2.0)+0.5)) * 8.0);

    // itoa(digits[i], digit_char, 10); // convert digit number to helper C-style string array
    // itoa((digits[i]+1) % 10, digit_char_next, 10); // convert next digit number to helper C-style string array

    //minutes
    // u8g2.drawStr(11 + i*4, 7 - y_offset, digit_char);	// draw the current character to the display
    // u8g2.drawStr(11 + i*4, 7 - y_offset + 8, digit_char_next);	// draw the next character to the display
    // u8g2.drawStr(11, 7, szsecond);	// draw the current character to the display
  
    //Enf of minutes ---------------------------------------------------------------------

  // for (int i=1; i>=0; i--) { // go from the last digit to the first digit

  //   if (digitsHour_offset_perc[i] > 0) { // animate the digit
  //     digitsHour_offset_perc[i] = digitsHour_offset_perc[i] + 2; // increase the percentage offset

  //     if ((digitsHour[i] == 9) && (digitsHour_offset_perc[i-1] == 0) && (digitsHour_offset_perc[i] > 20)) {
  //       digitsHour_offset_perc[i-1] = 2; // digit is 9 turning to 0 = increase digit on the left side
  //     }

  //     if (digitsHour_offset_perc[i] >= 100) { // animation is complete, switch to the next digit
  //       digitsHour_offset_perc[i] = 0; // stop the animation
  //       digitsHour[i] = digitsHour[i] + 1; // switch to the next digit

  //       if (digitsHour[i] == 10) { // if the digit goes over 9, go back to 0
  //         digitsHour[i] = 0;
  //       }
  //     }
  //   }

    // linear movement of digits - looks boring
    //y_offset = round((digits_offset_perc[i] / 100.0) * 8.0); // calculate the Y pixel offset
    // easing using the power function - looks strange for continuous animation
    //y_offset = round(pow((digits_offset_perc[i] / 100.0), 0.4) * 8.0);
    // easing using the cosine function - looks great
    // y_offset = round((1-((cos(digitsHour_offset_perc[i] / 100.0 * 3.141592654) / 2.0)+0.5)) * 8.0);

    // itoa(digitsHour[i], digit_char, 10); // convert digit number to helper C-style string array
    // itoa((digitsHour[i]+1) % 10, digit_char_next, 10); // convert next digit number to helper C-style string array

    //hours
    // u8g2.drawStr(1 + i*4, 7 - y_offset, digit_char);	// draw the current character to the display
    // u8g2.drawStr(1 + i*4, 7 - y_offset + 8, digit_char_next);	// draw the next character to the display

    // u8g2.drawStr(9, 7, ":");

  u8g2.setFont(u8g2_font_tom_thumb_4x6_tr);
  if (millis()/3000 % 2 == 0 ){     // Every 2 seconds timer
    u8g2.drawStr(21,5,"69%");
  }
  else {
    u8g2.drawStr(21,5,"25c");
  }

  u8g2.sendBuffer(); // transfer internal memory to the display

  flasher = !flasher;
  lastTime = millis();

  }
}