#include <Arduino.h>

// This is how many color levels the display shows - the more the slower the update
//#define PxMATRIX_COLOR_DEPTH 4

// Defines the speed of the SPI bus (reducing this may help if you experience noisy images)
//#define PxMATRIX_SPI_FREQUENCY 20000000

// Creates a second buffer for backround drawing (doubles the required RAM)
//#define PxMATRIX_double_buffer true

#include <Adafruit_GFX.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMono12pt7b.h>
#include <Fonts/FreeMono9pt7b.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/Picopixel.h>

#include <PxMatrix.h>
#include <Adafruit_HTU21DF.h>

#include <mess_BME280.h>
#include <mess_HTU21D.h>
#ifndef CO2Wert
  #include <CO2.h>
#endif

// Pins for LED MATRIX
#ifdef ESP32

//#define P_LAT 22
#define P_LAT 15
#define P_A 19
#define P_B 23
#define P_C 18
#define P_D 5
#define P_E -1
#define P_OE 16
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

#endif

#ifdef ESP8266

#include <Ticker.h>
Ticker display_ticker;
#define P_LAT 16
#define P_A 5
#define P_B 4
#define P_C 15
#define P_D 12
#define P_E 0
#define P_OE 2

#endif

/* #define SDA 21
#define SCL 22
#define RX1 9
#define TX1 10 */



#define CO2_WARN_1 800
#define CO2_WARN_2 1000
#define CO2_WARN_3 1400
#define CO2_WARN_4 1500
#define CO2_WARN_5 2000
#define CO2_CRITICAL_PPM 1850

#define MaxErrCount 30
unsigned long startTime;
unsigned long endTime;
#include <Wire.h>
#include <WiFi.h>
#include <PubSubClient.h>
#define mqtt_port MQTTPORT
WiFiClient espClient;
PubSubClient client(espClient);


#define matrix_width 64
#define matrix_height 32

// This defines the 'on' time of the display is us. The larger this number,
// the brighter the display. If too large the ESP will crash
uint8_t display_draw_time=10; //30-70 is usually fine

//PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
//PxMATRIX display(64,64,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);

// Some standard colors
uint16_t myRED = display.color565(255, 0, 0);
uint16_t myGREEN = display.color565(0, 255, 0);
uint16_t myBLUE = display.color565(0, 0, 255);
uint16_t myWHITE = display.color565(255, 255, 255);
uint16_t myYELLOW = display.color565(255, 255, 0);
uint16_t myCYAN = display.color565(0, 255, 255);
uint16_t myMAGENTA = display.color565(255, 0, 255);
uint16_t myBLACK = display.color565(0, 0, 0);
uint16_t myDATUM = display.color565(64, 64, 64);
uint16_t myCo = display.color565(0, 255, 0);
uint16_t myBraun = display.color565(165, 74, 55);
uint16_t myTEST = display.color565(30, 30, 0);
uint16_t myHimmelblau = display.color565(0, 191, 255);

uint16_t myCOLORS[8]={myRED,myGREEN,myBLUE,myWHITE,myYELLOW,myCYAN,myMAGENTA,myBLACK};

//------- Helligkeit des Display -------
uint8_t dunkel = 11;
uint8_t hell = 70;
//---- Zeitsteuerung der Helligkeit ----
u_int16_t StartderAbdunklung = 20;
u_int16_t EndederAbdunklung = 7;

//------ Speicher für Sekunden ------
uint8_t SekOld  = 99;
uint8_t SekError  = 0;
uint16_t ErrorOld  = 0;

// Wifi
// Wifi
char ssid[] = STASSID;      // your network SSID (name)
char pass[] = STAPSK;               // your network password
IPAddress ip;
IPAddress gateway;
IPAddress subnet;
IPAddress dns; // DNS-Server
IPAddress secondarDNS;


/* char ssid[] = "EasyBox-838169";          // your network SSID (name)
char pass[] = "RcZmua6Xv4R4V5Kf";               // your network password
IPAddress ip( 192, 168, 2, 80);
IPAddress gateway( 192, 168, 2, 1 );
IPAddress subnet( 255, 255, 255, 0 );
IPAddress dns1(192, 168, 2, 1); // DNS-Server 1
IPAddress dns2(192, 168, 2, 1); // DNS-Server 2 */
String hostname = "DISPLAY";
int status = WL_IDLE_STATUS;
const char* NTP_SERVER = "de.pool.ntp.org"; // Vodafone ???? (de.pool.ntp.arcor-ip.net)
const char* TZ_INFO    = "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00";  // enter your time zone (https://remotemonitoringsystems.ca/time-zone-abbreviations.php)

tm timeinfo;
time_t now;
long unsigned lastNTPtime;
unsigned long lastEntryTime;

const int TimeY = 20;
const int TimeX = 1;

const int WetterY = 32;
const int WetterX = 18;

const int CoY = 43;



int Co2Messwert = 0.00;
float Covid19 = 0.00;
float Aussentemp = -99.90;
int Pressure = 0;
float FlurTemp = -99.90;
float Luftfeuchtigkeit = 0.00;
float FeuchteInnen = 0.00;
float TemparaturInnen = 0.00;
bool NOHTU = false;
bool readHtuFlag = true;
float akku = 5.00;
int Helligkeit = 255;
bool MQTT_Error_Flag = false;



const char* const PROGMEM DAY_NAMES[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"};
const char* const PROGMEM DAY_SHORT[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"};

char topic_0[50];
char msg[20];
char clientName[30];
#ifdef Covid
const char* topic_Covid = "hjk/devices/Covid19/telemetry/Covid19"; 
#endif
const char* topic_Wetter = WETTER; 
const char* topic_Pressure = LUFTDRUCK;
const char* topic_Luftfeuchtigkeit = FEUCHTIGKEIT; 
const char* topic_Akku = AKKU;
#ifdef CO2Wert
  const char* topic_Co2 = CO2Wert;
#endif

const char* topic_Helligkeit = HELL; 

void callback(char* topic1, byte* payload, unsigned int length);
void ZeigeZeit(tm localTime,int xPos, int yPos);
void scroll_text(uint8_t ypos, unsigned long scroll_delay, String text, uint8_t colorR, uint8_t colorG, uint8_t colorB, boolean blink);
void scroll_text2(uint8_t ypos, unsigned long scroll_delay, String text, uint8_t colorR, uint8_t colorG, uint8_t colorB, boolean blink);
void scroll_Grad(uint8_t ypos, unsigned long scroll_delay, String text, uint8_t colorR, uint8_t colorG, uint8_t colorB, boolean blink);
bool getNTPtime(int sec);
void showTime(tm localTime);
void BlinkSec(bool blink);
static uint32_t lastTime = 0; // millis() memory
static uint32_t oldsec = 99;
static void setup_wifi();
void ZeigeTestTime(tm localTime);
void ZeigeInnenTemp(float Aussentemp);
void ZeigeTemperatur(float Temperatur, uint16_t Color);

void ZeigeInnenFeuchtigkeit(float Luftfeuchtigkeit);
void ZeigeLuftdruck(float Pressure);
void AkkuAlarm();

#ifdef ESP8266
// ISR for display refresh
void display_updater()
{
  display.display(display_draw_time);
}
#endif

#ifdef ESP32
void IRAM_ATTR display_updater(){
  // Increment the counter and set the time of ISR
  portENTER_CRITICAL_ISR(&timerMux);
  display.display(display_draw_time);
  portEXIT_CRITICAL_ISR(&timerMux);
}
#endif

void print_wifi_status() {
  // SSID des WiFi Netzwerkes ausgeben:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  // WiFi IP Adresse des ESP32 ausgeben:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  // WiFi Signalstärke ausgeben:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  display.clearDisplay();
  scroll_text(32-16,40,"IP Adress: " + WiFi.localIP().toString()+ "   signal strength (RSSI):  " + String(rssi, DEC) + " dBm", 96,96,0, false);
  //delay(2000);
}

void display_update_enable(bool is_enable)
{

#ifdef ESP8266
  if (is_enable)
    display_ticker.attach(0.004, display_updater);
  else
    display_ticker.detach();
#endif

#ifdef ESP32
  if (is_enable)
  {
    timer = timerBegin(0, 80, true);
    timerAttachInterrupt(timer, &display_updater, true);
    timerAlarmWrite(timer, 4000, true);
    timerAlarmEnable(timer);
  }
  else
  {
    timerDetachInterrupt(timer);
    timerAlarmDisable(timer);
  }
#endif
}

String TimeOld = "";
int MinuteOld = 99;
static bool blinkSek = false;  // seconds passing flasher

void callback(char* topic1, byte* payload, unsigned int length) {
  #ifdef DEBUG
  Serial.print("Message arrived [");
  Serial.print(topic1);
  Serial.print("] ");
  #endif
  for (int i = 0; i < length; i++) {
    msg[i] = (char)payload[i];
  }
  msg[length] = '\0';

  if(strcmp(topic1, topic_Wetter)== 0){ 
    #ifdef DEBUG
    Serial.print("Aussentemperatur: ");
    Serial.print(msg);
    Serial.println();
    #endif
    Aussentemp = atof(msg);
  }

  if(strcmp(topic1, topic_Pressure)== 0){ 
    #ifdef DEBUG
    Serial.print("Luftdruck: ");
    Serial.print(msg);
    Serial.println();
    #endif
    Pressure = atoi(msg);
  }

  if(strcmp(topic1, topic_Luftfeuchtigkeit)== 0){ 
    #ifdef DEBUG
    Serial.print("Luftfeuchtigkeit: ");
    Serial.print(msg);
    Serial.println();
    #endif
    Luftfeuchtigkeit = atof(msg);
  }

  if(strcmp(topic1, topic_Helligkeit)== 0){ 
    Serial.print("Helligkeit: ");
    Serial.print(msg);
    Serial.println(" Lux");
    Helligkeit = atoi(msg);
    if (Helligkeit > 255) Helligkeit = 255;
    if (Helligkeit < 0) Helligkeit = 0;
    display.setBrightness(Helligkeit);
  }

  if(strcmp(topic1, topic_Akku)== 0){ 
    #ifdef DEBUG
    Serial.print("AKKU: ");
    Serial.print(msg);
    Serial.println();
    #endif
    akku = atof(msg);
   }

   #ifdef CO2Wert
  // CO2 Wert vom Sensor
  if(strcmp(topic1, topic_Co2)== 0){ 
    Serial.print("Co2 Sensor !!!: ");
    Serial.print(msg);
    Serial.println();
    Co2Messwert = atoi(msg);
  }
  #endif
}
void reconnect() {
  sprintf(clientName, "%s%s", "TEST", "_DISPLAY" );
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(clientName)) {
      /* MQTTStatus.setPic(3); */
      Serial.println("connected");
      #ifdef CO2Wert
        client.subscribe(topic_Co2);
      #endif 
      //client.subscribe(topic_Covid);
      client.subscribe(topic_Wetter);
      client.subscribe(topic_Pressure);
      client.subscribe(topic_Luftfeuchtigkeit);
      client.subscribe(topic_Helligkeit);
      client.subscribe(topic_Akku);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      scroll_text(32-7,80, "MQTT Error", 127,82,0, true);
      ErrorOld ++;
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void ZeigeZeit(tm localTime, int xPos = 2, int yPos = 8)
{
  if (xPos < 4) xPos = 4;
  if (yPos < 4) yPos = 4;
  //Serial.print(timeClient.getFormattedTime()); Serial.println();
  char szTime[4]; 
  sprintf(szTime, "%02d", localTime.tm_hour);
  display.setCursor(xPos-1, yPos); 
  display.setFont(&FreeMonoBold12pt7b);
  display.setTextColor(myWHITE);
  display.fillRect(xPos, yPos - 8, 27, 15, myBLACK);
  display.print(szTime);
  display.setFont();
  // Doppelpunkt zeichnen
  display.fillRect(xPos + 27, yPos -8, 2, 15, myBLACK);
  if (blinkSek == true) {
    display.fillRect(xPos + 27, yPos - 3, 2, 2, myWHITE);
    display.fillRect(xPos + 27, yPos + 1, 2, 2, myWHITE);
  }
  /* display.fillRect(xPos + 27, yPos - 3, 2, 2, myMAGENTA);
  display.fillRect(xPos + 27, yPos + 1, 2, 2, myMAGENTA); */
  sprintf(szTime, "%02d", localTime.tm_min); 
  display.setCursor(xPos + 29, yPos); 
  display.setFont(&FreeMonoBold12pt7b);
  display.setTextColor(myWHITE);
  display.fillRect(xPos + 29, yPos - 8, 27, 15, myBLACK);
  display.print(szTime);
  display.setFont();
}

void ZeigeTestTime(tm localTime)
{
  char szTime[15]; 
  if (blinkSek == true){
    sprintf(szTime, "%02d:%02d", localTime.tm_hour, localTime.tm_min);
  }
  else{
    sprintf(szTime, "%02d %02d", localTime.tm_hour, localTime.tm_min);
  }
  display.setFont(&FreeMonoBold9pt7b);
  display.setCursor(6, 11); 
  display.setTextColor(myMAGENTA);
  display.fillRect(0, 0, 64, 12, myBLACK);
  display.print(szTime);
  display.setFont(0);
}

void ZeigeCO(int Co2, int xPos = 1, int yPos = 19)
{
  if (xPos < 1) xPos = 1;
  if (yPos < 19) yPos = 19;
  display.fillRect(0, 34-10, 64, 8, myBLACK);
  if (Co2 > 300){
    char szCO[10]; 
    sprintf(szCO, "%4d", Co2);
    display.setFont();
    switch (Co2){
      case 0 ... CO2_WARN_1 -1: {
        display.setTextColor(myCo); // green
        break;
      }
      case CO2_WARN_1 ... CO2_WARN_4 -1: {
        display.setTextColor(myYELLOW);
        break;
      }
      case CO2_WARN_4 ... CO2_CRITICAL_PPM: {
        display.setTextColor(myRED);
        break;
      }
      default: {
        display.setTextColor(myBLUE);
        break;
      }

    }
    display.setCursor(0, 25);
    display.print("CO");
    display.setFont(&Picopixel);
    display.setCursor(13, 28);
    display.print("2");
    display.setCursor(25, 31); 
    display.setFont(0);
    display.print(szCO);
    display.setFont(&Picopixel);
    display.setCursor(50, 30); 
    display.print("ppm");
    display.setFont(0);

  }
}

void ZeigeDatum(tm localTime, int xPos = 2, int yPos = 1)
{
  if (xPos < 2) xPos = 2;
  if (yPos < 0) yPos = 0;
  char szDATUM[20]; 
  sprintf(szDATUM, "%s%2d.%02d.%02d", DAY_SHORT[(localTime.tm_wday > 0 ? localTime.tm_wday : 7 )],
    localTime.tm_mday,
    localTime.tm_mon + 1,
    (localTime.tm_year+1900)-2000);
  display.setCursor(xPos, yPos); 
  display.fillRect(xPos, yPos-2, 64-xPos, 8+2, (myBLACK));
  // display.setFont(&Picopixel);
  display.setTextColor(myDATUM);
  display.print(szDATUM);
  display.setFont();
  
}

void ZeigeWetter(double Wetter1, int yPos = 2, int xPos = 1)
{
  if (xPos < 2) xPos = 2;
  if (yPos < 0) yPos = 0;
  if (Wetter1 > -99.9){
    char szWetter[10]; 
    dtostrf(Wetter1, 4, 1, szWetter);
    display.setCursor(xPos, yPos); 
    display.fillRect(xPos, yPos-2, 64-xPos, 8+2, (myBLACK));
    display.setTextColor(myDATUM);
    display.print(szWetter);
    // Erzeuge Grad Zeichen ......
    display.setCursor(xPos+24, yPos-5); 
    display.setFont(&Picopixel);
    display.print("o");
    display.setCursor(xPos+28, yPos+6); 
    display.setFont();
    // ...........
    display.print("C");
  }
}
void ZeigeInnenTemp(float Aussentemp){
  char szWetter[15]; 
  if (Aussentemp > -99)
  {
    dtostrf(Aussentemp, 5, 1, szWetter);
    display.setFont();
    display.setCursor(1, 14); 
    display.setTextColor(myGREEN);
    display.fillRect(0, 13, 40, 9, myRED);
    display.print(szWetter);
    display.setCursor(30, 9); 
    display.setFont(&Picopixel);
    display.print("o");
    display.setCursor(34, 20); 
    display.setFont();
    display.print("C");
    display.setFont(0);
  }
}
void ZeigeTemperatur(float temperatur, uint16_t Color){
  char szWetter[15]; 
  if (Aussentemp > -99)
  {
    dtostrf(temperatur, 5, 1, szWetter);
    display.setFont();
    display.setCursor(1, 16); 
    display.setTextColor(Color);
    display.fillRect(0, 15, 45, 9, myBLACK);
    display.print(szWetter);
    display.setCursor(31, 11); 
    display.setFont(&Picopixel);
    display.print("o");
    display.setCursor(34, 22); 
    display.setFont();
    display.print("C");
    display.setFont(0);
  }
}

void ZeigeInnenFeuchtigkeit(float Luftfeuchtigkeit){
  char szWetter[15]; 
  if (Aussentemp > -99)
  {
    dtostrf(Luftfeuchtigkeit, 2, 0, szWetter);
    display.setFont();
    display.setCursor(45, 16); 
    display.setTextColor(myGREEN);
    display.fillRect(45, 16, 64, 7, myBLACK);
    display.print(szWetter);
    display.print("%");
    display.setFont(0);
  }
}

void ZeigeAussenTemp(float Aussentemp){
  char szWetter[15]; 
  if (Aussentemp > -99)
  {
    dtostrf(Aussentemp, 4, 1, szWetter);
    display.setFont();
    display.setCursor(1, 14); 
    display.setTextColor(myHimmelblau);
    display.fillRect(0, 14, 33, 7, myBLACK);
    display.print(szWetter);
    display.setCursor(24, 9); 
    display.setFont(&Picopixel);
    display.print("o");
    display.setCursor(28, 20); 
    display.setFont();
    display.print("C");
    display.setFont(0);
  }
}

void ZeigeAussenFeuchtigkeit(float Luftfeuchtigkeit){
  char szWetter[15]; 
  if (Aussentemp > -99)
  {
    dtostrf(Luftfeuchtigkeit, 2, 0, szWetter);
    display.setFont();
    display.setCursor(45, 16); 
    display.setTextColor(myHimmelblau);
    display.fillRect(45, 16, 64, 7, myBLACK);
    display.print(szWetter);
    display.print("%");
    display.setFont(0);
  }
}

void ZeigeLuftdruck(float Pressure){
  char szWetter[15]; 
  dtostrf(Pressure, 4, 0, szWetter);
  display.setFont();
  display.fillRect(0, 33-10, 64, 10, myBLACK);
  display.setCursor(10, 33-8); 
  display.setTextColor(myHimmelblau);
  display.print(szWetter);
  display.print(" hPa");
  display.setFont(0);
  
}
void BlinkSec(bool blink){
  if (blink) {
          display.fillRect(31, 5, 2, 2, myWHITE);
          display.fillRect(31, 9, 2, 2, myWHITE);
          
        }else{
          display.fillRect(31, 5, 2, 6, myBLACK);
        }
}

void Test()
{
  display.setCursor(1, 40);
  display.print("Hallo");
  display.setFont(&Picopixel);
  display.print("0o");
  display.setFont();
}

void setup() {
  startTime = millis();
  Serial.begin(115200);
 /*  if (!htu.begin()) {
    Serial.println("Couldn't find sensor!");
    NOHTU = true;
    delay(500);

  } */
 init_HTU21();
  if (htu21Data.Status == true){
    read_HTU21D();
  }

  Init_BME280();
  #ifndef CO2Wert
    beginC02();
  #endif
  delay(5000);
  WiFi.mode( WIFI_OFF );
  // WiFi.forceSleepBegin();
  delay( 10 );
  Serial.println("Start");
  // initialise_wifi();
  setup_wifi();

  // Define your display layout here, e.g. 1/8 step, and optional SPI pins begin(row_pattern, CLK, MOSI, MISO, SS)
  display.begin(16);  // Rows-scan pattern 1/32
  
  // Set the color order {RRGGBB, RRBBGG, GGRRBB, GGBBRR, BBRRGG, BBGGRR} (default is RRGGBB)
  display.setColorOrder(RRBBGG);

  // Set the brightness of the panels (default is 255)
  //display.setBrightness(50);
  display.setBrightness(hell);
  display.clearDisplay();
  display_update_enable(true);
//--------------------------------------------------


//------- TEST -----------
  display.fillRect(31, 5, 2, 6, myRED);
  delay(2000);
  display.fillRect(31, 5, 2, 6, myGREEN);
  delay(2000);
  display.fillRect(31, 5, 2, 6, myBLUE);
  delay(2000);
  display.fillRect(31, 5, 2, 6, myBLACK);
  delay(2000);
  //----------------------
  print_wifi_status();
  configTime(0, 0, NTP_SERVER);
  // See https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv for Timezone codes for your region
  setenv("TZ", TZ_INFO, 1);

  if (getNTPtime(100)) {  // wait up to 10sec to sync
  } else {
    Serial.println("Time not set");
    delay(5000);
    ESP.restart();
  }
  showTime(timeinfo);
  lastNTPtime = time(&now);
  lastEntryTime = millis();


  }
union single_double{
  uint8_t two[2];
  uint16_t one;
} this_single_double;

unsigned long last_draw=0;

void scroll_text(uint8_t ypos, unsigned long scroll_delay, String text, uint8_t colorR, uint8_t colorG, uint8_t colorB, boolean blink)
{
    uint16_t text_length = text.length();
    display.setTextWrap(false);  // we don't wrap text so it scrolls nicely
    display.setTextSize(1);
    display.setRotation(0);
    display.setTextColor(display.color565(colorR,colorG,colorB));

    // Asuming 5 pixel average character width
    for (int xpos=matrix_width; xpos>-(matrix_width+text_length*5); xpos--)
    {
      if (millis() - lastTime >= (1000 - scroll_delay))
      {
        lastTime = millis();
        blinkSek = !blinkSek;
      }
      if (blink){
        BlinkSec(blinkSek);
      }
      
      display.setTextColor(display.color565(colorR,colorG,colorB));
      display.fillRect(xpos, ypos-2, 64-xpos, 10, (myBLACK));
      display.setCursor(xpos,ypos);
      display.println(text);
      delay(scroll_delay);
      yield();

      // This might smooth the transition a bit if we go slow
      // Dies könnte den Übergang etwas glätten, wenn wir langsam vorgehen
      /* display.setTextColor(display.color565(colorR/4,colorG/4,colorB/4));
      display.setCursor(xpos-1,ypos);
      display.println(text);

      delay(scroll_delay/5);
      yield(); */

    }
}

void scroll_Grad(uint8_t ypos, unsigned long scroll_delay, String text, uint8_t colorR, uint8_t colorG, uint8_t colorB, boolean blink)
{
    uint16_t text_length = text.length() +2;
    display.setTextWrap(false);  // we don't wrap text so it scrolls nicely
    display.setTextSize(1);
    display.setRotation(0);
    display.setTextColor(display.color565(colorR,colorG,colorB));

    // Asuming 5 pixel average character width
    for (int xpos=matrix_width; xpos>-(matrix_width+text_length*5); xpos--)
    {
      if (SekOld !=  timeinfo.tm_sec){
        SekOld =  timeinfo.tm_sec;
        blinkSek = !blinkSek;
      }
      if (blink){
        BlinkSec(blinkSek);
      }
      
      display.setTextColor(display.color565(colorR,colorG,colorB));
      display.fillRect(xpos, ypos-1, 64-xpos, 9, (myBLACK));
      display.setCursor(xpos,ypos);
      display.print(text);
      display.setCursor(xpos+132, ypos-5); 
      display.setFont(&Picopixel);
      display.print("o");
      display.setCursor(xpos+136, ypos+6); 
      display.setFont();
     // ...........
      display.println("C");
      delay(scroll_delay);
      yield();

    }
}
uint8_t icon_index=0;

static void setup_wifi() {
  
  long ErrCount = 0;

  if (!ip.fromString(MYIP)) { // try to parse into the IPAddress
    Serial.println("UnParsable IP");
    }
  if (!dns.fromString(DNS)) { // try to parse into the IPAddress
    Serial.println("UnParsable DNS");
    }
  if (!gateway.fromString(GATEWAY)) { // try to parse into the IPAddress
    Serial.println("UnParsable GATEWAY");
    }
  if (!secondarDNS.fromString(SECONDARDNS)) { // try to parse into the IPAddress
    Serial.println("UnParsable GATEWAY");
    }
  if (!subnet.fromString(SUBNET)) { // try to parse into the IPAddress
    Serial.println("UnParsable GATEWAY");
    }


  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.print(" ");

  //WiFi.forceSleepWake();
  delay( 1 );

  #ifndef DHCP
    WiFi.config( ip, gateway, subnet, dns, secondarDNS);
  #endif
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    ErrCount ++;
    if (ErrCount >= MaxErrCount){
      delay(500);
      ESP.restart();
      }
    }
  //Serial.println(" WiFi connected");
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  Serial.print("IP address: \t");
  Serial.println(WiFi.localIP());

}


void loop() {
 
  /* if (MQTT_Error_Flag == true){
    if (ErrorOld !=  timeinfo.tm_sec){
      ErrorOld =  timeinfo.tm_sec;
      if (SekError <= 10){
        SekError ++ ;
        Serial.printf("MQTT ERROR: %5d \n",SekError);
      }
      else{
        SekError = 0;
        MQTT_Error_Flag = false;
      }      
    }

  }
  
  if (MQTT_Error_Flag == false) {
    if (!client.connected()) {
      reconnect();
    }
  } */

  if (!client.connected()) {
      reconnect();
      Serial.printf("\n\n\t\tBis jetzt konnte %3d mal kein Kontakt zum MQTT-Server hergestellt werden.\n\n", ErrorOld);
  }
  getNTPtime(10);
  client.loop(); 
  
  if (SekOld !=  timeinfo.tm_sec)
  {
    SekOld =  timeinfo.tm_sec;
    blinkSek = !blinkSek;
    ZeigeZeit(timeinfo,1,8);
    
    if (akku < AKKU_GREZWERT)
    {
      AkkuAlarm();
    }
    
    #ifndef CO2Wert
      if ((timeinfo.tm_sec % 30) == 0)
      {
        if (readCo2Flag == true)  //eadCo2Flag
        {
          Co2Messwert = readCO2();
          Serial.print("CO = \t"); Serial.println(Co2Messwert);
          readCo2Flag = false;
        }
      }else{
        readCo2Flag = true;
      }
    #endif

    if ((timeinfo.tm_min % 2) == 0)
    {
      if (readHtuFlag == true)
      {
        if (htu21Data.Status == true){
          read_HTU21D();
        }
        if (BME280Data.Status == true) {
          Read_BME280();
        }
        readHtuFlag = false;
        Serial.printf(" HTU: %3.2f\t\tBME280: %3.2f\n\n", htu21Data.Temp, BME280Data.Temp);
      }
    }else{
      readHtuFlag = true;
    }
    
    switch (timeinfo.tm_sec)
    {
      case 0 ... 14:
      {
        ZeigeTemperatur(htu21Data.Temp, myGREEN);
        ZeigeInnenFeuchtigkeit(htu21Data.Feuchte);
        ZeigeCO(Co2Messwert);
        break;
      }
      case 15 ... 29:
      {
        ZeigeTemperatur(Aussentemp, myHimmelblau);
        ZeigeAussenFeuchtigkeit(Luftfeuchtigkeit);
        ZeigeLuftdruck(Pressure);
        break;
      }
      case 30 ... 44:
      {
        ZeigeTemperatur(htu21Data.Temp, myGREEN);
        ZeigeInnenFeuchtigkeit(htu21Data.Feuchte);
        ZeigeCO(Co2Messwert);
        break;
      }
      case 45 ... 59:
      {
        ZeigeTemperatur(Aussentemp, myHimmelblau);
        ZeigeAussenFeuchtigkeit(Luftfeuchtigkeit);
        ZeigeLuftdruck(Pressure);
        break;
      }
    }
  
  }
}

bool getNTPtime(int sec) {

  {
    uint32_t start = millis();
    do {
      time(&now);
      localtime_r(&now, &timeinfo);
      delay(10);
    } while (((millis() - start) <= (1000 * sec)) && (timeinfo.tm_year < (2016 - 1900)));
    if (timeinfo.tm_year <= (2016 - 1900)) return false;  // the NTP call was not successful  }
  return true;
  }
}

void showTime(tm localTime) {
  Serial.printf(
    "%04d-%02d-%02d %02d:%02d:%02d, day %d, %s time\n",
    localTime.tm_year + 1900,
    localTime.tm_mon + 1,
    localTime.tm_mday,
    localTime.tm_hour,
    localTime.tm_min,
    localTime.tm_sec,
    (localTime.tm_wday > 0 ? localTime.tm_wday : 7 ),
    (localTime.tm_isdst == 1 ? "summer" : "standard")
  );
  }


void AkkuAlarm()
{
  if (((timeinfo.tm_min % 5) == 0))
  {
    char szAkku[10];
    dtostrf(akku, 5, 2, szAkku);
    String myAkku = "ACHTUNG!! Akku : " + String(szAkku) + " V. Bitte aufladen!";
    scroll_text(32-7,40, myAkku, 255,0,0, true);
  }
}