/*=====================================================================================
Настрока дисплея: 1.8 TFT SPI 128x160  V1.1 на чипе ST7735
Эту конфигурацию необходимо внести в файл настроек /TFT_eSPI/User_Setup.h
#define ST7735_DRIVER
#define TFT_RGB_ORDER TFT_RGB
#define TFT_WIDTH  128
#define TFT_HEIGHT 160
#define TFT_MISO  PIN_D6
#define TFT_MOSI  PIN_D7
#define TFT_SCLK  PIN_D5
#define TFT_CS    PIN_D8
#define TFT_DC    PIN_D3
#define TFT_RST   PIN_D4
#define SMOOTH_FONT
#define SPI_FREQUENCY  40000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000
----------------------------------------------------------------------------------------
SDO/MISO       --> D6 (or leave disconnected if not reading TFT)       - не нужен
LED            --> VIN (or 5V, see below)                              +
SCK            --> D5                                                  +
SDI/MOSI/SDA   --> D7                                                  +
DC (RS/AO)     --> D3                                                  +
RESET          --> D4 (or RST, see below)                              +
CS             --> D8 (or GND, see below)                              +
GND            --> GND (0V)                                            +
VCC            --> 5V or 3.3V                                          +
=====================================================================================*/
#include <Arduino.h>
#include <TFT_eSPI.h>
#include <SPI.h>
// #include <ESP8266WiFi.h>
#include <WiFi.h>
//#include "NTPClient.h"
#include <WiFiUdp.h>
#include "GyverNTP.h"
//#include <PZEM004Tv30.h>
//#include <SoftwareSerial.h>
#include "Fonts.h"

#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 23
#define TFT_SCLK 18

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);

const char *ssid = "Wokwi-GUEST";
const char *password = "";

WiFiUDP ntpUDP;
GyverNTP timeClient(3);



const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 10800; // Часовой пояс * 3600 , Москва +3 GTM
const int daylightOffset_sec = 0;

// colors
unsigned short grays[24];
unsigned short back = TFT_MAGENTA;
unsigned short blue = 0x0250;

#define c1 0xBDD7 // white
#define c2 0x18C3 // gray
#define c3 0x9986 // red
#define c4 0x2CAB // green
#define c5 0xBDEF // gold

// Оттенки серого
uint16_t lines[11] = {0};
uint16_t gra[60] = {0};

// electrical
double KWH;
double todayKWH = 0;
double WH;
int dot = 0;
String lbl[3] = {"Напр.", "Ток", "Част."};
float data[3] = {220.80, 16.84, 49.90};

bool PZEM_online, MQTT_online, TIME_online, WiFi_online = false;

// счетчик
int fromTop = 93;
int left = 50;
int width = 60;
int heigth = 20;

//SoftwareSerial pzemSWSerial(D1, D2);
//PZEM004Tv30 pzem(pzemSWSerial);

// для показаний
float u1 = 0.0, i1 = 0.0, f1 = 0.0, p1 = 0.0, e1 = 0.0;
float p_max = 0, p_min = 99999999;
float u_avg = 0.0, i_avg = 0.0, f_avg = 0.0, p_avg = 0.0;
int u_count = 0, i_count = 0, f_count, p_count = 0;

// дни недели
String days[7] = {"Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"};

// для таймеров
uint32_t ms, ms1 = 0, ms2 = 0, ms3 = 0, ms4 = 0, ms_ok = 0;
uint32_t tm = 0;
uint32_t t_cur = 0;
long t_correct = 0;

//------------------------------------------------------------------------
void connectToWifi(void);
void define_level_of_gray();
void initSCREEN();
void setTime();
//------------------------------------------------------------------------

void setup()
{
  define_level_of_gray();

  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);
  tft.fillScreen(TFT_BLACK);

  spr.createSprite(160, 128);
  spr.setSwapBytes(1);

  connectToWifi();
 // timeClient.setTimeOffset(10800);
  timeClient.begin();
}

void loop()
{

//timeClient.tick();
  ms = millis();

  // Опрос показаний электроэнергии
  if (ms1 == 0 || ms < ms1 || (ms - ms1) > 333)
  {
    ms1 = ms;
    t_cur = ms / 1000;
    tm = t_cur + t_correct;
    float u2, i2, f2, p2, e2;
    for (int i = 0; i < 3; i++)
    {
      u2 = 220; //pzem.voltage();
      if (u2 != NAN && u2 >= 0)
      {
        PZEM_online = true;
        u1 = u2;
        u_avg += u1;
        u_count++;
        break;
      }
      else
      {
        PZEM_online = false;
      };
    }
    for (int i = 0; i < 3; i++)
    {
      i2 = 16; //pzem.current();
      if (i2 != NAN && i2 >= 0)
      {
        PZEM_online = true;
        i1 = i2;
        i_avg += i1;
        i_count++;
        break;
      }
      else
      {
        PZEM_online = false;
      };
    }
    for (int i = 0; i < 3; i++)
    {
      p2 = 200; //pzem.power();
      if (p2 != NAN && p2 >= 0)
      {
        PZEM_online = true;
        p1 = p2;
        p_avg += p1;
        p_count++;
        break;
      }
      else
      {
        PZEM_online = false;
      };
    }
    for (int i = 0; i < 3; i++)
    {
      f2 = 49.9; //pzem.frequency();
      if (f2 != NAN && f2 >= 0)
      {
        PZEM_online = true;
        f1 = f2;
        f_avg += f1;
        f_count++;
        break;
      }
      else
      {
        PZEM_online = false;
      };
    }
    for (int i = 0; i < 3; i++)
    {
      e2 = 333; //pzem.energy();
      if (e2 != NAN && e2 >= 0)
      {
        PZEM_online = true;
        e1 = e2;
        break;
      }
      else
      {
        PZEM_online = false;
      };
    }
    if (p_max < p1)
      p_max = p1;
    if (p_min > p1)
      p_min = p1;
  }

  if (!timeClient.tick())
  {
    TIME_online = false;
    timeClient.updateNow();
  }
  else
  {
    TIME_online = true;
  }

  data[0] = u1;
  data[1] = i1;
  data[2] = f1;

  if (!WiFi.isConnected())
    WiFi_online = false;
  else
    WiFi_online = true;

  initSCREEN();
  delay(10);
}

//------------------------------------------------------------------------

void initSCREEN()
{
  // Центр --- нагрузка
  spr.setTextDatum(0);
  spr.fillSprite(blue);
  spr.fillSmoothRoundRect(2, 2, 156, 124, 2, TFT_BLACK, blue);
  spr.fillSmoothRoundRect(40, 4, 115, 120, 2, grays[19], TFT_BLACK);
  spr.loadFont(UbuntuCondensed_Regular_10);
  spr.setTextColor(grays[8], grays[19]);
  spr.drawString("Нагрузка", 57, 48);
  spr.setTextColor(TFT_BLACK, TFT_ORANGE);
  spr.fillSmoothRoundRect(93, 64, 9, 12, 2, TFT_ORANGE, grays[19]); // подложка под Watt букву
  spr.drawString("W", 94, 66);
  spr.setTextColor(grays[8], grays[22]);

  // Окошки --- напряжение -- ток -- частота
  for (int i = 0; i < 3; i++)
  {
    spr.fillSmoothRoundRect(47 + (i * 36), 19, 30, 28, 2, grays[22], grays[19]);
    spr.drawString(lbl[i], 47 + (i * 36) + 3, 20);
  }
  spr.unloadFont();
  spr.loadFont(AndersonSupercar1);
  spr.setTextColor(grays[4], grays[22]);
  for (int i = 0; i < 3; i++)
  {
    spr.drawFloat(data[i], 1, 47 + (i * 36) + 3, 34);
  }
  spr.unloadFont();

  // Название титул
  spr.loadFont(ComputerPixel7);
  spr.setTextColor(TFT_ORANGE, grays[19]);
  spr.drawString("ЭНЕРГОМЕРА", 47, 6);
  spr.unloadFont();
  // Середина
  spr.fillRect(49, 51, 1, 26, grays[7]);
  spr.fillRect(49, 58, 50, 1, grays[7]);
  spr.fillSmoothCircle(49, 51, 2, grays[7], grays[19]);
  spr.fillSmoothCircle(49, 51 + 26, 2, grays[7], grays[19]);
  spr.fillSmoothCircle(49 + 50, 58, 2, grays[7], grays[19]);
  // Сетка графика
  spr.fillSmoothRoundRect(107, 50, 43, 30, 2, grays[22], grays[19]);
  for (int i = 0; i < 5; i++)
    spr.drawFastHLine(109, 58 + (i * 4), 40, grays[16]);
  spr.drawFastHLine(108, 78, 41, grays[7]);
  spr.drawFastVLine(108, 57, 21, grays[7]);
  spr.setTextColor(grays[10], grays[19]);
  spr.loadFont(UbuntuCondensed_Regular_10);
  spr.drawString("За 24 ч.", 115, 49);
  spr.setTextColor(grays[10], grays[19]);
  spr.drawString("Сег:", 130, 83);
  spr.drawLine(130, 92, 151, 92, grays[5]);
  spr.setTextColor(grays[4], grays[19]);
  spr.drawFloat(e1, 1, 131, 95); // ---------------- ЗНАЧЕНИЕ -----------------
  spr.setTextColor(grays[10], grays[19]);
  spr.drawString("Макс:", 130, 103);
  spr.drawLine(130, 112, 151, 112, grays[5]);
  spr.setTextColor(grays[4], grays[19]);
  spr.drawFloat(378, 1, 131, 114); // -------------- ЗНАЧЕНИЕ -----------------
  spr.unloadFont();

  // Текущая мощность
  spr.loadFont(AndersonSupercar2);
  spr.setTextColor(grays[2], grays[22]);
  spr.drawFloat(p1, 1, 54, 65);
  spr.unloadFont();

  // "Железный" циферблат
  spr.setTextDatum(4);
  spr.fillSmoothRoundRect(47, 83, 80, 39, 3, c1, grays[19]);
  spr.fillSmoothRoundRect(left + 7, fromTop - 4, width - 5, heigth, 3, c2, c1);
  spr.fillSmoothRoundRect(left + 8, fromTop - 3, width - 6, heigth, 3, c1, c2);
  spr.fillRect(left + 6, fromTop - 1, width - 10, 3, c1);
  spr.fillRect(left + 25, fromTop - 4, width - 40, 3, c1);
  spr.fillSmoothRoundRect(left, fromTop, width, heigth, 3, blue, c1);
  spr.fillSmoothRoundRect(left + 54, fromTop, 21, heigth, 3, c3, c1);
  spr.fillRect(left + 54, fromTop, 2, heigth, c1);
  spr.fillSmoothCircle(left + 55, fromTop + heigth, 3, c1);
  spr.fillSmoothCircle(left + 55, fromTop + heigth, 2, c2);
  spr.loadFont(UbuntuCondensed_Regular_10);
  spr.setTextColor(c2, c1);
  spr.drawString("kWh", left + 36, fromTop - 4);
  for (int i = 0; i < 5; i++)
  {
    spr.fillRectHGradient(left + (3) + (i * 10), fromTop + 4, 8, 12, TFT_BLACK, gra[2]);
    for (int j = 0; j < 6; j++)
      if (j == 3)
        spr.drawLine(left + (9) + (i * 10), fromTop + 4 + (j * 2), left + (10) + (i * 10), fromTop + 4 + (j * 2), lines[j]);
      else
        spr.drawLine(left + (10) + (i * 10), fromTop + 4 + (j * 2), left + (10) + (i * 10), fromTop + 4 + (j * 2), lines[j]);
  }
  spr.fillRectHGradient(left + 59, fromTop + 4, 14, 12, TFT_BLACK, gra[2]);
  for (int j = 0; j < 6; j++)
    if (j == 3)
      spr.drawLine(left + 70, fromTop + 4 + (j * 2), left + 71, fromTop + 4 + (j * 2), lines[j]);
    else
      spr.drawLine(left + 71, fromTop + 4 + (j * 2), left + 71, fromTop + 4 + (j * 2), lines[j]);
  spr.drawLine(left + 6, fromTop + 21, left + 6, fromTop + 23, blue);
  spr.drawLine(left + 6, fromTop + 23, left + 13, fromTop + 23, blue);
  spr.drawLine(left + 47, fromTop + 21, left + 47, fromTop + 23, blue);
  spr.drawLine(left + 47, fromTop + 23, left + 40, fromTop + 23, blue);
  spr.setTextColor(c2, c1);
  spr.drawString("X1", left + 67, fromTop + 25);
  spr.setTextColor(blue, c1);
  spr.drawString("TOTAL", left + 28, fromTop + 25);
  spr.setTextColor(c2, c1);
  // Цыфры на табло счётчика
  spr.setTextColor(c1, TFT_BLACK);
  spr.drawString("0", left + 6, fromTop + 11);
  spr.drawString("0", left + 16, fromTop + 11);
  spr.drawString("0", left + 26, fromTop + 11);
  spr.drawString("0", left + 36, fromTop + 11);
  spr.drawString("0", left + 46, fromTop + 11);
  spr.drawString("00", left + 64, fromTop + 11);
  spr.unloadFont();

  // Левая часть ---- время --- дата --- день --- индикаторы
  spr.loadFont(AndersonSupercar2);
  spr.setTextColor(grays[6], TFT_BLACK);
  spr.setTextDatum(0);
  spr.drawString(timeClient.timeString().substring(0, 5), 6, 8);
  spr.unloadFont();
  spr.fillRect(8, 22, 1, 20, grays[13]);
  spr.fillRect(8, 32, 26, 1, grays[13]);
  spr.loadFont(UbuntuCondensed_Regular_10);
  spr.setTextColor(grays[10], TFT_BLACK);
  spr.drawString(String(timeClient.dateString().substring(8, 10)) + "." + String(timeClient.dateString().substring(5, 7)), 12, 23);
  spr.drawString(days[timeClient.dayWeek()], 12, 33);
  spr.drawString("PZEM", 5, 80);
  if (PZEM_online)
    spr.fillSmoothRoundRect(33, 81, 5, 5, 0, TFT_DARKGREEN);
  else
    spr.fillSmoothRoundRect(33, 81, 5, 5, 0, grays[10]);
  spr.drawString("MQTT", 5, 89);
  if (MQTT_online)
    spr.fillSmoothRoundRect(33, 90, 5, 5, 0, TFT_DARKGREEN);
  else
    spr.fillSmoothRoundRect(33, 90, 5, 5, 0, grays[10]);
  spr.drawString("Время", 5, 98);
  if (TIME_online)
    spr.fillSmoothRoundRect(33, 99, 5, 5, 0, TFT_DARKGREEN);
  else
    spr.fillSmoothRoundRect(33, 99, 5, 5, 0, grays[10]);
  spr.drawString("WiFi", 5, 107);
  if (WiFi_online)
    spr.fillSmoothRoundRect(33, 108, 5, 5, 0, TFT_DARKGREEN);
  else
    spr.fillSmoothRoundRect(33, 108, 5, 5, 0, grays[10]);
  spr.unloadFont();

  spr.pushSprite(0, 0);
}

void connectToWifi()
{
  tft.loadFont(UbuntuCondensed_Regular_10);
  tft.setTextColor(grays[10], TFT_BLACK);
  tft.print("Connecting..");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(300);
    tft.print(".");
  }
  tft.println("");
  tft.println("  WiFi connected.");
  tft.println("  IP address:     ");
  tft.println(WiFi.localIP());
  delay(3200);
  tft.fillScreen(TFT_BLACK);
  tft.unloadFont();
}

void define_level_of_gray()
{
  // Определим оттенки серого
  int co = 240;
  for (int i = 0; i < 24; i++)
  {
    grays[i] = tft.color565(co, co, co);
    co = co - 10;
  }
  for (int i = 0; i < 50; i++)
    gra[i] = tft.color565(i * 5, i * 5, i * 5);

  lines[0] = gra[10];
  lines[1] = gra[20];
  lines[2] = gra[30];
  lines[3] = gra[40];
  lines[4] = gra[30];
  lines[5] = gra[20];
  lines[6] = gra[10];
}