/*
 * LED matrix Clock
 * Author: Uncle Da
 * Bilibili: https://space.bilibili.com/328004983
 * Last Update is 2023-8-17, by uncle da
 */

#include <WiFi.h>      //ESP32用此行
//#include <ESP8266WiFi.h>  //ESP8266用此行
#include <MD_Parola.h>  //For MAX7219 Matrix LED
//#include <MD_MAX72xx.h> //For MAX7219 SPI LED Driver
#include <SPI.h>        //For SPI Communication
#include <time.h>       //For Time Based Application 
#include "Font.h"  

//**********  User Config Setting   ******************************/
const char *ssid = "Wokwi-GUEST";   //改成自家WIFI SSID
const char *password = "";        //密码 
const char *NTPServer = "id.pool.ntp.org";
const int gmtOffset_sec = 25200;  //7*3600
const int daylightOffset_sec = 0;  //夏令时

//=====MAX7219================================
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW   //实操中改成 FC16_HW
#define MAX_DEVICES 4 
#define CLK_PIN   18
#define DATA_PIN  23
#define CS_PIN    5
MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
#define SPEED_TIME  60  //数字越小越快,0最快
//=============================================
uint16_t  h, m, s;
char szTime[9];    // mm:ss\0
char szsecond[4];    // ss
//=============================================
void getsec(char *psz)
{
  sprintf(psz, "%02d", s);
}
//=============================================
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);
  Serial.println(p_tm,"%F %T %A");
}
// ============SmartConfig 一键配网/自动重连/微信扫码配网====================
void SmartConfig()   
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig...");
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    delay(500);                   // wait for a second
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      break;
    }
  }
}

bool AutoConfig()   //上电自动重连
{
    WiFi.begin();
    //如果觉得时间太长可改
    for (int i = 0; i < 20; i++)
    {
        int wstatus = WiFi.status();
        if (wstatus == WL_CONNECTED)
        {
	        Serial.println("WIFI SmartConfig Success");
	        Serial.printf("SSID:%s", WiFi.SSID().c_str());
	        Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
	        Serial.print("LocalIP:");
	        Serial.print(WiFi.localIP());
	        Serial.print(" ,GateIP:");
	        Serial.println(WiFi.gatewayIP());
	        return true;
        }
        else
        {
	        Serial.print("WIFI AutoConfig Waiting......");
	        Serial.println(wstatus);
	        delay(1000);
        }
    }
    Serial.println("WIFI AutoConfig Faild!" );
    return false;
}
//===================================================

void setup(void)
{
  Serial.begin(115200);
  delay(50);
  P.begin(2);   //分成2个区,不填默认1个
  P.setInvert(false); //显示屏阴阳显示(false=0=阳显;true=1=反转)
  Serial.println();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to ");
  Serial.println(ssid);
   while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  delay(2000);
  getTimeNTP();
   if (!AutoConfig())
  {
  	SmartConfig();
  }
 //=============================================
  P.setZone(0, 0, 0);   //一分区,0区右边第一个8*8;
  P.setZone(1, 1, 3);   //二分区,1区右边第2-4个8*8;
  P.setFont(0, GF3x5p);
  P.setFont(1, GF4x7p);
  P.displayZoneText(0, szsecond, PA_RIGHT, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayZoneText(1, szTime, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
   //(滚动效果:显示区域、显示字符串、对齐方式、动画速度、文本显示时间、动画进入效果、动画退出效果)
  getTime(szTime);
}
//=============================================
void loop(void) {
  
  static uint32_t lastTime = 0; // millis() memory
  static bool flasher = false;  // seconds passing flasher
  P.displayAnimate();

     if (millis() - lastTime >= 1000)
    {
    lastTime = millis();
    getTime(szTime, flasher);
    getsec(szsecond);
    flasher = !flasher; 
    P.displayReset(1);  
    P.displayReset(0); 

    if((h >= 0)&&(h < 7)){   //晚上 0~7 点亮度设置为1,其他时间亮度设置为(0~15);
      P.setIntensity(0,1); //0区域,亮度1
      P.setIntensity(1,1); //1区域,亮度1
    }
    else{
      P.setIntensity(0,3); //0区域,亮度3(3就足够亮了)
      P.setIntensity(1,3); //1区域,亮度3
    }

    if (h == 0 && m == 20 && s == 00)     //每天自动重启00:20:00
    {  
      P.displayClear();
      delay(1000);
      ESP.restart();
    }
  }
}
//=============================================
void getTimeNTP()
{
   configTime(gmtOffset_sec, daylightOffset_sec, NTPServer);
  
  while(!time(nullptr)){
        delay(500);
        Serial.print(".");
  }
  Serial.print("NTP Time Update");
}