/*
    InkyDash

    An ESP8266 powered version of InkyCal like project
    for low power desktop dashboard

    Author: tobychui

*/

/* Pin Mappings */
//Wemos D1 mini
// BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V

// Generic ESP8266
// BUSY -> GPIO4, RST -> GPIO2, DC -> GPIO0, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V

/*
  Power Settings

  If your device is designed to be plugged in
  set LOW_POWER_MODE to false

  If your device is powered with battery and
  GPIO16 / D0 is connected to RST with a resistor
  (resistor value depends on development board)
  set LOW_POWER_MODE to true

  If yout are not sure, set it to false
*/
#define LOW_POWER_MODE true

/* 
  Display refresh interval
  
  Too frequent interval in low power mode might results getting ban by weather API / NTP servers 
  If you are not using low power mode, edit the high pwr mode interval instead
*/
#define REFRESH_INTERVAL 900e6 //900 seconds, aka 15 minutes
#define REFRESH_INTERVAL_HIGH_PWR_MODE 900000 //900 ms, aka 15 minutes

#define SHOW_PREVIOUS_NEXT_MONTH_DAYS true //Show previous & next months days as well

/* Display Libraries */
#include <GxEPD.h>

//#include <GxGDEW075T8/GxGDEW075T8.h>      // 7.5" b/w
//#include <GxGDEW075T7/GxGDEW075T7.h>      // 7.5" b/w 800x480
#include <GxGDEW075Z09/GxGDEW075Z09.h>      // 7.5" b/w/r
//#include <GxGDEW075Z08/GxGDEW075Z08.h>    // 7.5" b/w/r 800x480

/* Display SPI library */
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

/* Fonts */
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSans18pt7b.h>
#include <Fonts/FreeSans24pt7b.h>
#include <Fonts/FreeSansBold24pt7b.h>

/* WiFi and Connections */
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <ESP8266TrueRandom.h>
#include <NTPClient.h>
#include <ESP8266HTTPClient.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#include <TaskScheduler.h>




/* WiFi and Connections */
WiFiManager wifiManager;
WiFiUDP UDPconn;
NTPClient ntpClient(UDPconn, "pool.ntp.org");

/* SPI Settings */
GxIO_Class io(SPI, /*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2); // arbitrary selection of D3(=0), D4(=2), selected for default of GxEPD_Class
GxEPD_Class display(io, /*RST=D4*/ 2, /*BUSY=D2*/ 4); // default selection of D4(=2), D2(=4)

/* Time Const */
const String weekDays[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const String weeksDaysFull[7] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY" };
const String months[12] = {"JANUARY",  "FEBRUARY",  "MARCH",  "APRIL",  "MAY",  "JUNE",  "JULY",  "AUGUST",  "SEPTEMBER",  "OCTOBER",  "NOVEMBER",  "DECEMBER"};

/* NTP Servers*/
//Add more if you want to refresh more frequently in low power mode
const char* ntpServers[] = {
  "0.debian.pool.ntp.org",
  "1.debian.pool.ntp.org",
  "2.debian.pool.ntp.org",
  "3.debian.pool.ntp.org",
  "pool.ntp.org",
  "0.pool.ntp.org",
  "1.pool.ntp.org",
  "2.pool.ntp.org",
  "3.pool.ntp.org",
  "0.arch.pool.ntp.org",
  "1.arch.pool.ntp.org",
  "2.arch.pool.ntp.org",
  "3.arch.pool.ntp.org",
  "time.google.com",
  "time.cloudflare.com",
  "time.windows.com",
  "time.apple.com",
  "time-a-wwv.nist.gov",
  "time-b-wwv.nist.gov",
  "time-c-wwv.nist.gov"
};
const int ntpServerCounts = 20;

/* Global Variables */
const String deviceName = "InkyDash v1.0";
float currentTemp = 25.0;
float currentHumd = 50.0;
float currentRain = 0.0;
float maxTemp = 0.0;
float minTemp = 0.0;
int batRemain = 0; //In percentage

/* Schedulers */
void datetimeUpdateCallback();
Task t_dt(REFRESH_INTERVAL_HIGH_PWR_MODE, TASK_FOREVER, &datetimeUpdateCallback); //Frame update
Scheduler runner;

void setup() {
  //Start debug serial
  Serial.begin(115200);
  Serial.println();
  Serial.println("Starting up InkyDash");
  display.init(115200);

  //Set D0 to wakeup pin
  pinMode(D0,WAKEUP_PULLUP);
  
  //Draw starting frame
  display.setRotation(3);
  if (!LOW_POWER_MODE) {
    display.drawPaged(drawStartingFrame);
    delay(100);
  }

  // Connect to Wi-Fi
  /*
    //Hard code version
    WiFi.begin("SSID", "password");
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print('.');
    }
    Serial.println('\n');
    Serial.println("Connection established!");
    Serial.print("IP address:\t");
    Serial.println(WiFi.localIP());
  */

  wifiManager.setAPCallback(configModeCallback);
  wifiManager.autoConnect("InkyDash");

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi Connected");
  } else {
    Serial.println("Network error");
    display.drawPaged(drawNoNetwork);
    return;
  }

  delay(1000);

  //Randomly get one of the NTP server from the list and request time
  const char* randomNtpServer = getRandomNtpServer(ntpServers);
  Serial.println("Using NTP Server: " + String(randomNtpServer));
  NTPClient timeClient(UDPconn, randomNtpServer);
  ntpClient.begin();
  ntpClient.setTimeOffset(28800);

  //Draw home page
  if (LOW_POWER_MODE) {
    //Get weather information from API
    updateCurrentWeatherInfo();
    //Render the calender page
    display.drawPaged(drawHomeFrame);
    Serial.println("Display updated. Entering deep sleep mode");
    ESP.deepSleep(REFRESH_INTERVAL);
    delay(100);
    //After deep sleep mode, device will reset and not entering the loop() session
  } else {
    runner.init();
    Serial.println("Initialized scheduler");
    runner.addTask(t_dt); //Date-time update task
    t_dt.enable();
  }
}

void loop() {
  runner.execute();
}
