# 1 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
/* 



--------------------------------------  

 Author .    : Ed Nieuwenhuys

 Changes V001: Derived from PocuterWordClockV052

 Changes V002: Stable version without ILI 9341 display / SD card

 Changes V003: Added ILI9341

 Changes V004: Screen layout. Displayprintln()

 Changes V005: BT connection on led blue, repait digitalprint. Turn off LEDs after 1 minute 

 Changes V006: LDR and Backlight regulation

 Changes V007: Debugging

 Changes V008: Added Light intensity S Slope T Min U Max

 Changes V009: 



// ESP32-C3-12F layout seen from top

// ADC   ----- I0 19

// IO 01 ----- I0 18

// NC    ----- I0 10

// IO 02 ----- I0 09

// IO 03 ----- I0 08

// IO 04 ----- 3V3  

// IO 05 ----- GND  

// NC    ----- NC   

// NC    ----- I0 06

// GND   ----- I0 07

// 3V3   ----- NC   

// EN    ----- RX   

// IO 00 ----- TX   

// GND   ----- GND  

// 5V    ----- 3V3  



ILI9341 connections

MISO  to GPIO 10

LED   to 3V3

SCK   to GPIO 09

MOSI  to GPIO 08  

DC/RS to GPIO 06

RESET to GPIO 07

CS    to GND

GND   to GND

3V3   to 3V3





  

Usage of:

1 Screen, colours and fonts

2 BLE nRF UART connection with phone

3 Buttons

4 RGB LED

5 RTC module for time

6 ??SD-card or SPIFFS storage of a struct with settings

7 Get timezone corrected time with daylight savings from a NTP server via WIFI

8 Menu driven with serial monitor, BLE and WIFI

9 Change connection settings of WIFI via BLE

10 Get time with NTP server via WIFI





How to compile: Install ESP32 boards

Set to:

Board: ESP32-C3 DEV module

Patition Scheme: Huge (4Mb, No OTA, 1MB SPIFFS)



                     

*/
# 65 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
// =============================================================================================================================
//--------------------------------------------
// ESP32-C3 Includes defines and initialisations
//--------------------------------------------

# 71 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 72 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 73 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 74 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 75 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 76 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 77 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 78 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2
# 106 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
//#define EDSOFT  ColorLeds("EdSoft", 132,132, LetterColor);
# 194 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
//--------------------------------------------
// SPIFFS storage
//--------------------------------------------
Preferences FLASHSTOR;

 //--------------------------------------------
// COLOURS
//--------------------------------------------   

const byte DEFAULTCOLOUR = 0;
const byte HOURLYCOLOUR = 1;
const byte WHITECOLOR = 2;
const byte OWNCOLOUR = 3;
const byte OWNHETISCLR = 4;
const byte WHEELCOLOR = 5;
const byte DIGITAL = 6;


// Pin Assignments
# 224 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
//--------------------------------------------
// ESP32-C3 initialysations
//--------------------------------------------
bool PrintDigital = false; // Show digital display 
bool IP_Printed = false; // The IP address will be printed on the display
bool Date_Printed = false; // The date will be printed on the display  
char Template[140]; // Contains the string with characters to be printed in the display
uint32_t LastButtonTime = 0; // Used to avoid debouncing the button

//------------------------------------------------------------------------------
// LDR PHOTOCELL
//------------------------------------------------------------------------------
//                                                                                            //
const byte SLOPEBRIGHTNESS = 80; // Steepness of with luminosity of the LED increases
const int MAXBRIGHTNESS = 255; // Maximun value in bits  for luminosity of the LEDs (1 - 255)
const byte LOWBRIGHTNESS = 5; // Lower limit in bits of Brightness ( 0 - 255)   
byte TestLDR = 0; // If true LDR inf0 is printed every second in serial monitor
int OutPhotocell; // stores reading of photocell;
int MinPhotocell = 999; // stores minimum reading of photocell;
int MaxPhotocell = 1; // stores maximum reading of photocell;
uint32_t SumLDRreadshour = 0;
uint32_t NoofLDRreadshour = 0;

//--------------------------------------------
// CLOCK initialysations
//--------------------------------------------                                 

static uint32_t msTick; // Number of millisecond ticks since we last incremented the second counter
byte lastminute = 0, lasthour = 0, lastday = 0, sayhour = 0;
bool Zelftest = false;
bool Is = true; // toggle of displaying Is or Was
bool ZegUur = true; // Say or not say Uur in NL clock
struct tm timeinfo; // storage of time 



//--------------------------------------------
// SCREEN Pixel initialysations
//--------------------------------------------
const byte MATRIX_WIDTH = 16;
const byte MATRIX_HEIGHT = 8;
const byte NUM_LEDS = MATRIX_WIDTH * MATRIX_HEIGHT ;
struct LEDPrintbuffer
         {
          char Character;
          uint32_t RGBColor;
         } Strippos[NUM_LEDS+1];
bool LEDsAreOff = false; // If true LEDs are off except time display
bool NoTextInColorLeds = false; // Flag to control printing of the text in function ColorLeds()
int Previous_LDR_read = 512; // The actual reading from the LDR + 4x this value /5  
uint32_t MINColor = 0xFFFF00; //C_RED;
uint32_t SECColor = 0xFFFF00; //C_GREEN;
uint32_t LetterColor = 0xFFFF00;
uint32_t HourColor[24] ={0xFFFFFF, 0xFF0000, 0xFFA500, 0xFFFF00, 0x9ACD32, 0x00FF00,
                         0x00FFFF, 0x1E90FF, 0x800080, 0xFF00FF, 0xFFD700, 0x00FF7F,
                         0xFFFFFF, 0xD2691E, 0xFFA500, 0xF0E68C, 0x9ACD32, 0xF5F5DC,
                         0x7FFFD4, 0x87CEEB, 0xFF69B4, 0xFF1493, 0xFF7F50, 0x7CFC00};
//--------------------------------------------
// SCREEN ILI9341
//--------------------------------------------







Adafruit_ILI9341 tft = Adafruit_ILI9341(-1 /*0  not used*/, 6, 8, 9, 7, -1 /*10  not used */);

//--------------------------------------------
// BLE   //#include <NimBLEDevice.h>
//--------------------------------------------
NimBLEServer *pServer = 
# 296 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 3 4
                    __null
# 296 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
                        ;
NimBLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
std::string ReceivedMessageBLE;





//----------------------------------------
// WEBSERVER
//----------------------------------------
int WIFIConnected = 0; // Is wIFI connected?

AsyncWebServer server(80);
# 313 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 2

//----------------------------------------
// Common
//----------------------------------------

char sptext[140]; // For common print use 
bool SerialConnected = true;
struct EEPROMstorage { // Data storage in EEPROM to maintain them after power loss
  byte DisplayChoice = 0;
  byte TurnOffLEDsAtHH = 0;
  byte TurnOnLEDsAtHH = 0;
  byte LanguageChoice = 0;
  byte LightReducer = 0;
  int LowerBrightness = 0;
  int UpperBrightness = 0;
  int NVRAMmem[24]; // LDR readings
  byte BLEOnOff = 1;
  byte NTPOnOff = 1;
  byte WIFIOnOff = 1;
  int TimeCorrection = 0; // Time correction in seconds
  byte UseSDcard = 0;
  byte UseBLELongString = 0; // Send strings longer than 20 bytes per message. Possible in IOS app BLEserial Pro 
  uint32_t OwnColour = 0; // Self defined colour for clock display
  uint32_t DimmedLetter = 0;
  uint32_t BackGround = 0;
  char Ssid[30];
  char Password[40];
  char BLEbroadcastName[30]; // Name of the BLE beacon
  char Timezone[50];
  int Checksum = 0;
} Mem;
//--------------------------------------------
// Menu
//0        1         2         3         4
//1234567890123456789012345678901234567890----  
 char menu[][40] = {
 "A SSID B Password C BLE beacon name",
 "D Date (D15012021) T Time (T132145)",
 "E Timezone  (E<-02>2 or E<+01>-1)",
 "  Make own colour of:  (Hex RRGGBB)",
 "F Font  G Dimmed font H Bkgnd",
 "I To print this Info menu",
 "K LDR reads/sec toggle On/Off",
 "L L0 = NL, L1 = UK, L2 = DE",
 "  L3 = FR, L4 = Wheel",
 "N Display off between Nhhhh (N2208)",
 "O Display toggle On/Off",
 "Q Display colour choice      (Q0-6)",
 "  Q0 Yellow  Q1 hourly",
 "  Q2 White   Q3 All Own",
 "  Q4 Own     Q5 Wheel",
 "  Q6 Digital display",
 "R Reset settings @ = Reset MCU",
 "Light intensity (1-250)",
 "S=Slope V=Min  U=Max  (S80 L5 M200)",
 "W=WIFI  X=NTP  Y=BLE  Z=Fast BLE",
 "Ed Nieuwenhuys Nov 2022" };

//  -------------------------------------   End Definitions  ---------------------------------------
//                                                                                            //

//--------------------------------------------
// ARDUINO Setup
//--------------------------------------------
void setup()
{
 Serial.begin(115200); Tekstprintln("Serial started"); // Setup the serial port to 115200 baud //
 pinMode(3, 0x03);
 pinMode(4, 0x03);
 pinMode(5, 0x03);
 pinMode(18, 0x03);
 pinMode(19, 0x03);
 pinMode(1 /* the LED backlight display*/, 0x03); // ILI9341 backlight                          

//  adcAttachPin(PhotoCellPin);
//  adcStart(PhotoCellPin);
//  analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
//  analogSetAttenuation(ADC_6db); // Default is 11db which is very noisy. Recommended to use 2.5 or 6.

 // pinMode(PhotoCellPin, INPUT);
// pinMode(PhotoCellPin, INPUT);

 Previous_LDR_read = ReadLDR();
 InitScreen(); Tekstprintln("Screen started");
 InitStorage(); Tekstprintln("Setting loaded"); // Load settings from storage and check validity 
 if (Mem.BLEOnOff) StartBLEService(); Tekstprintln("BLE started"); // Start BLE service
 if(Mem.WIFIOnOff){ Tekstprintln("Starting WIFI"); StartWIFI_NTP(); } // Start WIFI and optional NTP if Mem.WIFIOnOff = 1

 Mem.DisplayChoice == DIGITAL?PrintDigital=true:PrintDigital=false;
 SWversion(); // Print the menu + version 
 GetTijd(0); // 
// Displaytime();                                                                               // Print the tekst time in the display
 Print_tijd();
 msTick = LastButtonTime = millis();
 ClearScreen();
}
//                                                                                            //
//--------------------------------------------
// ARDUINO Loop
//--------------------------------------------
void loop()
{
 EverySecondCheck();
 CheckDevices();
}
//--------------------------------------------
// Common Check connected input devices
//--------------------------------------------
void CheckDevices(void)
{
 CheckBLE(); // Something with BLE to do?
 SerialCheck(); // Check serial port every second 
// ButtonsCheck();                                                                              // Check if buttons pressed
}
//                                                                                            //
//--------------------------------------------
// CLOCK Update routine done every second
//--------------------------------------------
void EverySecondCheck(void)
{
 static int lumi=0;
 uint32_t msLeap;

 msLeap = millis() - msTick; // uint32_t msLeapButton = millis()- LastButtonTime;
 (msLeap>500?lumi=(1000-msLeap)/40:lumi=msLeap/40); // Turn ON/betwOFF the second on LED. 
 if (msLeap%100==0){ SetStatusLED(-1,-1,12-lumi,lumi*WIFIConnected,-1); } // Do not update the LED unnecessary often
 if (msLeap >999) // Every second enter the loop
  {
   GetTijd(0); // Update timeinfo.tm_sec, timeinfo.tm_min, timeinfo.tm_hour, timeinfo.tm_mday, timeinfo.tm_mon, timeinfo.tm_year
   if (timeinfo.tm_min != lastminute) EveryMinuteUpdate(); // Enter the every minute routine after one minute
   if (Mem.DisplayChoice == DIGITAL) PrintTimeInScreen(); // Show the digital time in the screen
   DimLeds(TestLDR); // Every second an intensitiy check and update from LDR reading 
   msTick = millis();
  }
 }
//--------------------------------------------
// CLOCK Update routine done every minute
//-------------------------------------------- 
void EveryMinuteUpdate(void)
{
 lastminute = timeinfo.tm_min;
 if(!LEDsAreOff) Displaytime(); // Turn the display on                 
// Print_tijd();                                                                              //  sprintf(sptext,"NTP:%s", NTP.getTimeDateString());   Tekstprintln(sptext);  
 if(timeinfo.tm_hour != lasthour) EveryHourUpdate();
}
//--------------------------------------------
// CLOCK Update routine done every hour
//--------------------------------------------
void EveryHourUpdate(void)
{
 lasthour = timeinfo.tm_hour;
 if(timeinfo.tm_hour == Mem.TurnOffLEDsAtHH){ LEDsAreOff = true; ClearScreen(); } // Is it time to turn off the LEDs?
 if(timeinfo.tm_hour == Mem.TurnOnLEDsAtHH) LEDsAreOff = false; // 
 Mem.NVRAMmem[lasthour] =(byte)((SumLDRreadshour / NoofLDRreadshour)); // Update the average LDR readings per hour
 SumLDRreadshour = 0;
 NoofLDRreadshour = 0;
 if (timeinfo.tm_mday != lastday) EveryDayUpdate();
}
//                                                                                            //
//------------------------------------------------------------------------------
// CLOCK Update routine done every day
//------------------------------------------------------------------------------
void EveryDayUpdate(void)
{
 if(timeinfo.tm_mday != lastday)
   {
    lastday = timeinfo.tm_mday;
    Previous_LDR_read = ReadLDR(); // to have a start value
    MinPhotocell = Previous_LDR_read; // Stores minimum reading of photocell;
    MaxPhotocell = Previous_LDR_read; // Stores maximum reading of photocell;
//    StoreStructInFlashMemory();                                                             // 
    }
}
//--------------------------------------------
// Common check for serial input
//--------------------------------------------
void SerialCheck(void)
{
 String SerialString;
 while (Serial.available())
    {
     char c = Serial.read(); // Serial.write(c);
     if (c>31 && c<128) SerialString += c; // Allow input from Space - Del
     else c = 0; // Delete a CR
    }
 if (SerialString.length()>0)
    {
     ReworkInputString(SerialString+"\n"); // Rework ReworkInputString();
     SerialString = "";
    }
}

//                                                                                            //
//------------------------------------------------------------------------------
// Common Reset to default settings
//------------------------------------------------------------------------------
void Reset(void)
{
 Mem.Checksum = 25065; //
 Mem.DisplayChoice = DEFAULTCOLOUR; // 
 Mem.OwnColour = 0x00FF00; // Own designed colour.
 Mem.DimmedLetter = 0X191919;
 Mem.BackGround = 0x000000;
 Mem.LanguageChoice = 4; // 0 = NL, 1 = UK, 2 = DE, 3 = FR, 4 = Wheel
 Mem.LightReducer = SLOPEBRIGHTNESS; // Factor to dim ledintensity with. Between 0.1 and 1 in steps of 0.05
 Mem.UpperBrightness = MAXBRIGHTNESS; // Upper limit of Brightness in bits ( 1 - 1023)
 Mem.LowerBrightness = LOWBRIGHTNESS; // Lower limit of Brightness in bits ( 0 - 255)
 Mem.TurnOffLEDsAtHH = 0; // Display Off at nn hour
 Mem.TurnOnLEDsAtHH = 0; // Display On at nn hour Not Used
 Mem.BLEOnOff = 1; // BLE On
 Mem.UseBLELongString= 0;
 Mem.NTPOnOff = 0; // NTP On
 Mem.WIFIOnOff = 0; // WIFI On  
 Mem.TimeCorrection = 0; // Correct time if necesaary in seconds
 Mem.UseSDcard = 0;
 Previous_LDR_read = ReadLDR(); // to have a start value. max = 4096/8 = 255
 MinPhotocell = Previous_LDR_read; // Stores minimum reading of photocell;
 MaxPhotocell = Previous_LDR_read; // Stores maximum reading of photocell;                                            
 TestLDR = 0; // If true LDR display is printed every second

 strcpy(Mem.Ssid,""); // Default SSID
 strcpy(Mem.Password,""); // Default password
 strcpy(Mem.BLEbroadcastName,"ESPWordClock");
 strcpy(Mem.Timezone,"CET-1CEST,M3.5.0,M10.5.0/3"); // Central Europe, Amsterdam, Berlin etc.
 // For debugging
// strcpy(Mem.Ssid,"Guest");
// strcpy(Mem.Password,"guest_001");
// Mem.NTPOnOff        = 1;                                                                     // NTP On
// Mem.WIFIOnOff       = 1;                                                                     // WIFI On  

 Tekstprintln("**** Reset of preferences ****");
 StoreStructInFlashMemory(); // Update Mem struct       
 GetTijd(0); // Get the time and store it in the proper variables
 SWversion(); // Display the version number of the software
 //Displaytime();
}
//--------------------------------------------
// Common common print routines
//--------------------------------------------
void Tekstprint(char const *tekst) { if(Serial) Serial.print(tekst); SendMessageBLE(tekst);sptext[0]=0; }
void Tekstprintln(char const *tekst) { sprintf(sptext,"%s\n",tekst); Tekstprint(sptext); }
void TekstSprint(char const *tekst) { printf(tekst); sptext[0]=0;} // printing for Debugging purposes in serial monitor 
void TekstSprintln(char const *tekst) { sprintf(sptext,"%s\n",tekst); TekstSprint(sptext); }
void Displayprint(const char *tekst) { tft.print(tekst); } // Print to an attached display
void Displayprintln(const char *tekst){ tft.println(tekst); }
//------------------------------------------------------------------------------
//  Common Constrain a string with integers
// The value between the first and last character in a string is returned between the low and up bounderies
//------------------------------------------------------------------------------
int SConstrainInt(String s,byte first,byte last,int low,int up){return ((s.substring(first, last).toInt())<(low)?(low):((s.substring(first, last).toInt())>(up)?(up):(s.substring(first, last).toInt())));}
int SConstrainInt(String s,byte first, int low,int up){return ((s.substring(first).toInt())<(low)?(low):((s.substring(first).toInt())>(up)?(up):(s.substring(first).toInt())));}
//                                                                                            //
//--------------------------------------------
// Common Init and check contents of EEPROM
//--------------------------------------------
void InitStorage(void)
{
 // if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ Tekstprintln("Card Mount Failed");   return;}
 // else Tekstprintln("SPIFFS mounted"); 

 GetStructFromFlashMemory();
 if( Mem.Checksum != 25065)
   {
    sprintf(sptext,"Checksum (25065) invalid: %d\n Resetting to default values",Mem.Checksum);
    Tekstprintln(sptext);
    Reset(); // If the checksum is NOK the Settings were not set
   }
 Mem.LanguageChoice = ((Mem.LanguageChoice)<(4)?(Mem.LanguageChoice):(4)); // Constrain the value to valid ranges 
 Mem.DisplayChoice = ((Mem.DisplayChoice)<(DIGITAL)?(Mem.DisplayChoice):(DIGITAL)); // Constrain the value to valid ranges 
 if(Mem.OwnColour == 0) Mem.OwnColour = 0x00FF00; // If memory is empty cq black colour then store default value, blue  
 Mem.LightReducer = ((Mem.LightReducer)<(1)?(1):((Mem.LightReducer)>(250)?(250):(Mem.LightReducer))); // 
 Mem.LowerBrightness = ((Mem.LowerBrightness)<(1)?(1):((Mem.LowerBrightness)>(250)?(250):(Mem.LowerBrightness))); // 
 Mem.UpperBrightness = ((Mem.UpperBrightness)<(255)?(Mem.UpperBrightness):(255));
 if(strlen(Mem.Password)<5 || strlen(Mem.Ssid)<3) Mem.WIFIOnOff = Mem.NTPOnOff = 0; // If ssid or password invalid turn WIFI/NTP off

 StoreStructInFlashMemory();
}
//--------------------------------------------
// COMMON Store mem.struct in FlashStorage or SD
// Preferences.h  
//--------------------------------------------
void StoreStructInFlashMemory(void)
{

// if (pocuter->SDCard->cardIsMounted())      
//  {
//   FILE * fp;
//   char fileName[64];
//   snprintf(fileName, 64, "%s%s", pocuter->SDCard->getMountPoint(), "/MemStore.txt");
//   fp = fopen (fileName, "wb");
//   if (! fp) { sprintf(sptext,"Could not open %s to write!\n", fileName); Tekstprintln(sptext); } 
//   else {
//         fwrite(& Mem , sizeof(Mem),1,fp);
//         fclose(fp); 
////       sprintf(sptext,"File written!: %s\n",fileName); Tekstprintln(sptext); 
//        }    
//   } 
// 
//                    
//  else  
  {
//  sprintf(sptext,"SDCard not Mounted!\n"); Tekstprintln(sptext);  
  FLASHSTOR.begin("Mem",false); //  delay(100);
  FLASHSTOR.putBytes("Mem", &Mem , sizeof(Mem) );
  FLASHSTOR.end();
  }

// Can be used as alternative
//  SPIFFS
//  File myFile = SPIFFS.open("/MemStore.txt", FILE_WRITE);
//  myFile.write((byte *)&Mem, sizeof(Mem));
//  myFile.close();



 }
//--------------------------------------------
// COMMON Get data from FlashStorage
// Preferences.h
//--------------------------------------------
void GetStructFromFlashMemory(void)
{
//                
// if (pocuter->SDCard->cardIsMounted()) 
//   {
//     FILE * fp;
//     char fileName[64];
//     snprintf(fileName, 64, "%s%s", pocuter->SDCard->getMountPoint(), "/MemStore.txt");
//     fp = fopen (fileName, "rb");
//     if (! fp) { sprintf(sptext,"Could not open %s to read!\n", fileName); Tekstprintln(sptext); } 
//     else {
//           fread(& Mem, sizeof(Mem),1,fp);
//           fclose(fp); 
//           sprintf(sptext,"Settings from SD-card read!: %s\n",fileName); Tekstprintln(sptext); 
//          }    
//   } 
//  else 
//           
   {
//    sprintf(sptext,"SDCard not Mounted!\n Using Flashstorage"); Tekstprintln(sptext);  
    FLASHSTOR.begin("Mem", false);
    FLASHSTOR.getBytes("Mem", &Mem, sizeof(Mem) );
    FLASHSTOR.end();
    }

  sprintf(sptext,"Mem.Checksum = %d",Mem.Checksum);Tekstprintln(sptext);

// Can be used as alternative
//  File myFile = SPIFFS.open("/MemStore.txt");  FILE_WRITE); myFile.read((byte *)&Mem, sizeof(Mem));  myFile.close();
}

//--------------------------------------------
//  CLOCK Input from Bluetooth or Serial
//--------------------------------------------
void ReworkInputString(String InputString)
{
 char ff[50]; InputString.toCharArray(ff,InputString.length()); // Convert a String to char array
 sprintf(sptext,"Inputstring: %s  Lengte : %d\n", ff,InputString.length()-1);
 // Tekstprint(sptext);
 if(InputString.length()> 40){Serial.printf("Input string too long (max40)\n"); return;} // If garbage return
 sptext[0] = 0; // Empty the sptext string
 if(InputString[0] > 31 && InputString[0] <127) // Does the string start with a letter?
  {
  switch (InputString[0])
   {
    case 'A':
    case 'a':
            if (InputString.length() >5 )
            {
             InputString.substring(1).toCharArray(Mem.Ssid,InputString.length()-1);
             sprintf(sptext,"SSID set: %s", Mem.Ssid);
            }
            else sprintf(sptext,"**** Length fault. Use between 4 and 30 characters ****");
            break;
    case 'B':
    case 'b':
           if (InputString.length() >5 )
            {
             InputString.substring(1).toCharArray(Mem.Password,InputString.length()-1);
             sprintf(sptext,"Password set: %s\n Enter @ to reset ESP32 and connect to WIFI and NTP", Mem.Password);
             Mem.NTPOnOff = 1; // NTP On
             Mem.WIFIOnOff = 1; // WIFI On  
            }
            else sprintf(sptext,"%s,**** Length fault. Use between 4 and 40 characters ****",Mem.Password);
            break;
    case 'C':
    case 'c':
           if (InputString.length() >5 )
            {
             InputString.substring(1).toCharArray(Mem.BLEbroadcastName,InputString.length()-1);
             sprintf(sptext,"BLE broadcast name set: %s", Mem.BLEbroadcastName);
             Mem.BLEOnOff = 1; // BLE On
            }
            else sprintf(sptext,"**** Length fault. Use between 4 and 30 characters ****");
            break;
    case 'D':
    case 'd':
            if (InputString.length() == 10 )
              {
               timeinfo.tm_mday = (int) SConstrainInt(InputString,1,3,0,31);
               timeinfo.tm_mon = (int) SConstrainInt(InputString,3,5,0,12) - 1;
               timeinfo.tm_year = (int) SConstrainInt(InputString,5,9,2000,9999) - 1900;
               Date_Printed = false; // Date will be printed in Digital display mode
               SetRTCTime();
               Print_tijd(); //Tekstprintln(sptext);                                           // Print_Tijd() fills sptext with time string
              }
            else sprintf(sptext,"****\nLength fault. Enter Dddmmyyyy\n****");
            break;
    case 'F':
    case 'f':
             if (InputString.length() == 8 )
               {
                LetterColor = Mem.OwnColour = HexToDec(InputString.substring(1,7)); // Display letter color 
                sprintf(sptext,"Font colour stored0X%X", Mem.OwnColour);
                Tekstprintln("**** Own colour changed ****");
                Displaytime();
               }
             else sprintf(sptext,"****\nLength fault. Enter Frrggbb hexadecimal (0 - F)\n****");
             break;
    case 'G':
    case 'g':
             if (InputString.length() == 8 )
               {
                Mem.DimmedLetter = HexToDec(InputString.substring(1,7)); // Display letter color 
                sprintf(sptext,"Dimmed colour stored0X%X", Mem.DimmedLetter);
                Tekstprintln("**** Dimmed font colour changed ****");
                Displaytime();
               }
             else sprintf(sptext,"****\nLength fault. Enter Grrggbb hexadecimal (0 - F)\n****");
             break;
    case 'H':
    case 'h':
             if (InputString.length() == 8 )
               {
                Mem.BackGround = HexToDec(InputString.substring(1,7)); // Display letter color 
                sprintf(sptext,"Own colour stored0X%X", Mem.BackGround);
                Tekstprintln("**** BackGround colour changed ****");
                Displaytime();
               }
             else sprintf(sptext,"****\nLength fault. Enter Hrrggbb hexadecimal (0 - F)\n****");
             break;
    case 'I':
    case 'i':
            SWversion();
            break;
    case 'K':
    case 'k':
             TestLDR = 1 - TestLDR; // If TestLDR = 1 LDR reading is printed every second instead every 30s
             sprintf(sptext,"TestLDR: %s",TestLDR? "On" : "Off");
             break;
    case 'L': // Language to choose
    case 'l':
             if (InputString.length() == 3 )
               {
                byte res = (byte) InputString.substring(1,2).toInt();
                Mem.LanguageChoice = res%5; // Result between 0 and 4
                byte ch = Mem.LanguageChoice;
                sprintf(sptext,"Language choice:%s",ch==0?"NL":ch==1?"UK":ch==2?"DE":ch==3?"FR":ch==4?"Rotate language":"NOP");
//                Tekstprintln(sptext);
                lastminute = 99; // Force a minute update
               }
             else sprintf(sptext,"****\nDisplay choice length fault. Enter L0 - L4\n****");
            break;

    case 'N':
    case 'n':
             if (InputString.length() == 2 ) Mem.TurnOffLEDsAtHH = Mem.TurnOnLEDsAtHH = 0;
             if (InputString.length() == 6 )
              {
               Mem.TurnOffLEDsAtHH =(byte) InputString.substring(1,3).toInt();
               Mem.TurnOnLEDsAtHH = (byte) InputString.substring(3,5).toInt();
              }
             Mem.TurnOffLEDsAtHH = ((Mem.TurnOffLEDsAtHH)<(23)?(Mem.TurnOffLEDsAtHH):(23));
             Mem.TurnOnLEDsAtHH = ((Mem.TurnOnLEDsAtHH)<(23)?(Mem.TurnOnLEDsAtHH):(23));
             sprintf(sptext,"Display is OFF between %2d:00 and %2d:00", Mem.TurnOffLEDsAtHH,Mem.TurnOnLEDsAtHH );
 //            Tekstprintln(sptext); 
             break;
    case 'O':
    case 'o':
             if(InputString.length() == 2)
               {
                LEDsAreOff = !LEDsAreOff;
                sprintf(sptext,"Display is %s", LEDsAreOff?"OFF":"ON" );
                if(LEDsAreOff) { ClearScreen();} // Turn the display off
                else Displaytime(); // Turn the display on                
               }
             break;

    case 'q':
    case 'Q':
             if (InputString.length() == 3 )
               {
   //             byte OldDC = Mem.DisplayChoice;
                Mem.DisplayChoice = (byte) InputString.substring(1,2).toInt();
                sprintf(sptext,"Display choice: Q%d", Mem.DisplayChoice);
                lastminute = 99; // Force a minute update
 //               Mem.DisplayChoice == DIGITAL?PrintDigital=true:PrintDigital=false;               // if DIGITAL display PrintDigital is true
                ClearScreen();
   //             OldDC = Mem.DisplayChoice; ClearScreen();  ------------- nog uitzoeken
               }
             else sprintf(sptext,"**** Display choice length fault. Enter Q0 - Q6");
         //    Displaytime();                                             // Turn on the display with proper time 
            break;
    case 'R':
    case 'r':
             if (InputString.length() == 2)
               {
                Reset();
                sprintf(sptext,"\nReset to default values: Done");
                Displaytime(); // Turn on the display with proper time
               }
             else sprintf(sptext,"**** Length fault. Enter R ****");
             break;
    case 'S': // factor ( 0 - 1) to multiply brighness (0 - 255) with 
    case 's':
            if (InputString.length() < 6)
               {
                Mem.LightReducer = (byte) SConstrainInt(InputString,1,1,255);
                sprintf(sptext,"Slope brightness changed to: %d%%",Mem.LightReducer);
               }
              break;
    case 'T':
    case 't':
//                                                                                            //
             if(InputString.length() == 8) // T125500
               {
                timeinfo.tm_hour = (int) SConstrainInt(InputString,1,3,0,23);
                timeinfo.tm_min = (int) SConstrainInt(InputString,3,5,0,59);
                timeinfo.tm_sec = (int) SConstrainInt(InputString,5,7,0,59);
                SetRTCTime();
                Print_tijd();
               }
             else sprintf(sptext,"**** Length fault. Enter Thhmmss ****");
             break;
    case 'U': // factor to multiply brighness (0 - 255) with 
    case 'u':
            if (InputString.length() < 6)
               {
                Mem.UpperBrightness = SConstrainInt(InputString,1,1,255);
                sprintf(sptext,"Upper brightness changed to: %d bits",Mem.UpperBrightness);
               }
              break;
    case 'V':
    case 'v':
             if (InputString.length() < 6)
               {
                Mem.LowerBrightness = (byte) SConstrainInt(InputString,1,0,255);
                sprintf(sptext,"Lower brightness: %d bits",Mem.LowerBrightness);
               }
             break;
    case 'W':
    case 'w':
             if (InputString.length() == 2)
               {
                Mem.WIFIOnOff = 1 - Mem.WIFIOnOff;
                sprintf(sptext,"WIFI is %s after restart", Mem.WIFIOnOff?"ON":"OFF" );
               }
             else sprintf(sptext,"**** Length fault. Enter W ****");
             break;
    case 'X':
    case 'x':
             if (InputString.length() == 2)
               {
                Mem.NTPOnOff = 1 - Mem.NTPOnOff;
                sprintf(sptext,"NTP is %s after restart", Mem.NTPOnOff?"ON":"OFF" );
               }
             else sprintf(sptext,"**** Length fault. Enter X ****");
             break;
    case 'Y':
    case 'y':
             if (InputString.length() == 2)
               {
                Mem.BLEOnOff = 1 - Mem.BLEOnOff;
                sprintf(sptext,"BLE is %s after restart", Mem.BLEOnOff?"ON":"OFF" );
               }
             else sprintf(sptext,"**** Length fault. Enter Y ****");
             break;
    case 'Z':
    case 'z':
             if (InputString.length() == 2)
               {
                Mem.UseBLELongString = 1 - Mem.UseBLELongString;
                sprintf(sptext,"Fast BLE is %s", Mem.UseBLELongString?"ON":"OFF" );
               }
             else sprintf(sptext,"**** Length fault. Enter U ****");
             break;

    case '@':
             if (InputString.length() == 2)
               {
               Tekstprintln("\n*********\n ESP restarting\n*********\n");
                ESP.restart();
               }
             else sprintf(sptext,"**** Length fault. Enter @ ****");
             break;
    case '#':
             if (InputString.length() == 2)
               {
                Zelftest = 1 - Zelftest;
                sprintf(sptext,"Zelftest: %d",Zelftest);
                Displaytime(); // Turn on the display with proper time
               }
             else sprintf(sptext,"**** Length fault. Enter S ****");
             break;
    case '$':
             if (InputString.length() == 2)
               {
                Mem.UseSDcard = 1 - Mem.UseSDcard;
                sprintf(sptext,"SD is %s after restart", Mem.UseSDcard?"used":"NOT used" );
                sprintf(sptext,"This function is not working, .... yet" );
               }
             else sprintf(sptext,"**** Length fault. Enter Z ****");
             break;
    case '0':
    case '1':
    case '2':
             if (InputString.length() == 7 ) // For compatibility input with only the time digits
              {
               timeinfo.tm_hour = (int) SConstrainInt(InputString,0,2,0,23);
               timeinfo.tm_min = (int) SConstrainInt(InputString,2,4,0,59);
               timeinfo.tm_sec = (int) SConstrainInt(InputString,4,6,0,59);
               sprintf(sptext,"Time set");
               SetRTCTime();
               Print_tijd();
               }
    default: break;
    }
  }
 Tekstprintln(sptext);
 StoreStructInFlashMemory(); // Update EEPROM                                     
 InputString = "";
}
//--------------------------------------------
// LDR reading are between 0 and 255. 
// ESP32 analogue read is between 0 - 4096 --   is: 4096 / 8
//--------------------------------------------
int ReadLDR(void)
{
  return analogRead(2)/16;
}
//--------------------------------------------
// CLOCK Control the LEDs on the ESP32
// -1 leaves intensity untouched
//--------------------------------------------
void SetStatusLED(int WW, int CW, int Re, int Gr, int Bl)
{
 if(Re >=0 ) analogWrite(3, Re);
 if(Gr >=0 ) analogWrite(4, Gr);
 if(Bl >=0 ) analogWrite(5, Bl);
 if(CW >=0 ) analogWrite(18, CW);
 if(WW >=0 ) analogWrite(19, WW);
}

//--------------------------------------------
//  LED Dim the leds measured by the LDR and print values
// LDR reading are between 0 and 255. The Brightness send to the LEDs is between 0 and 255
//--------------------------------------------
void DimLeds(bool print)
{
  int LDRread = ReadLDR(); // ESP32 analoge read is between 0 - 4096, reduce it to 0-1024                                                                                                   
  int LDRavgread = (4 * Previous_LDR_read + LDRread ) / 5; // Read lightsensor and avoid rapid light intensity changes
  Previous_LDR_read = LDRavgread; // by using the previous reads
  OutPhotocell = (uint32_t)((Mem.LightReducer * sqrt(255*LDRavgread))/100); // Linear --> hyperbolic with sqrt. Result is between 0-255
  MinPhotocell = min(MinPhotocell, LDRavgread); // Lowest LDR measurement
  MaxPhotocell = max(MaxPhotocell, LDRavgread); // Highest LDR measurement
  OutPhotocell = ((OutPhotocell)<(Mem.LowerBrightness)?(Mem.LowerBrightness):((OutPhotocell)>(Mem.UpperBrightness)?(Mem.UpperBrightness):(OutPhotocell))); // Keep result between lower and upper boundery en calc percentage
  SumLDRreadshour += LDRavgread; NoofLDRreadshour++; // For statistics LDR readings per hour
  if(print)
  {
   sprintf(sptext,"LDR:%3d Avg:%3d",LDRread,LDRavgread); Tekstprint(sptext);
   sprintf(sptext," (%3d-%3d)",MinPhotocell,MaxPhotocell); Tekstprint(sptext);
   sprintf(sptext," Out:%3d", OutPhotocell); Tekstprint(sptext);
   sprintf(sptext,"=%2d%% ",(int)(OutPhotocell/2.55) ); Tekstprint(sptext);
   Print_tijd();
  }
 if(LEDsAreOff) OutPhotocell = 0;
 SetBrightnessLeds(OutPhotocell); // values between 0 and 255
}

//--------------------------------------------
//  LED Set color for LED. 
// Fill the struct Strippos with the proper character and its colour
//--------------------------------------------
void ColorLeds(char const *Texkst, int FirstLed, int LastLed, uint32_t RGBColor)
{
 int n, i=0;
 char Tekst[135];
  if (!NoTextInColorLeds && (strlen(Texkst) > 0 && strlen(Texkst) <10) )
     {sprintf(sptext,"%s ",Texkst); Tekstprint(sptext); } // Print the text  
                                                                                              // sprintf(sptext," %s, F:%d, L:%d F-L:%d ",Texkst, FirstLed,LastLed,1+LastLed-FirstLed );  Tekstprint(sptext);
 strcpy(Tekst,Texkst);
 to_upper(Tekst);
 for (n=FirstLed; n<=FirstLed + (LastLed-FirstLed); n++)
 {
  Strippos[n].Character = Tekst[i++];
  Strippos[n].RGBColor = RGBColor; // Every character has its color stored here
//  sprintf(sptext,"-Strippos[%d].Character=:%c",n, Strippos[n].Character); Tekstprint(sptext);   
 }
}
//                                                                                            //
//--------------------------------------------
//  COMMON String upper
//--------------------------------------------
void to_upper(char* string)
{
 const char OFFSET = 'a' - 'A';
 while (*string)
  {
   (*string >= 'a' && *string <= 'z') ? *string -= OFFSET : *string;
   string++;
  }
}

//------------------------------------------------------------------------------
//  LED Set brighness of backlight
//------------------------------------------------------------------------------  
void SetBrightnessLeds(byte Bright)
{
 SetBackLight(Bright); // Set brightness of LEDs   
}
//--------------------------------------------
//  LED Clear the character string
//--------------------------------------------
void LedsOff(void)
{
 for (int n=0; n<NUM_LEDS; n++)
     Strippos[n].Character = Strippos[n].RGBColor = 0; // Erase the struct Strippos
}

//--------------------------------------------
//  LED Set second color
//  Set the colour per second of 'IS' and 'WAS'
//--------------------------------------------
void SetSecondColour(void)
{
 switch (Mem.DisplayChoice)
  {
   case DEFAULTCOLOUR: LetterColor = 0xFFFF00;
                       MINColor = 0xFFFF00; // C_GREEN + ((timeinfo.tm_min/2)<<19);
                       SECColor= 0xFFFF00; //C_GREEN + ((timeinfo.tm_hour/2)<<19);         // (30 << 19 = 0XF00000         
                                                                                    break;
   case HOURLYCOLOUR : LetterColor = MINColor = SECColor = HourColor[timeinfo.tm_hour]; break; // A colour every hour
   case WHITECOLOR : LetterColor = MINColor = SECColor = 0xFFFFFF; break; // All white
   case OWNCOLOUR : LetterColor = MINColor = SECColor = Mem.OwnColour; break; // Own colour
   case OWNHETISCLR : LetterColor = Mem.OwnColour;
                       MINColor = 0xFFFF00;
                       SECColor = 0xFFFF00; break; // Own colour except HET IS WAS  
   case WHEELCOLOR : LetterColor = MINColor = SECColor = (17*(timeinfo.tm_min*60)); break; // Colour of all letters changes per minute
   case DIGITAL : LetterColor = 0xFFFFFF; MINColor = SECColor = 0x000000; break; // Digital display of time. No IS WAS turn color off in display
  }
}
//                                                                                            //
//--------------------------------------------
// CLOCK Version info
//--------------------------------------------
void SWversion(void)
{

 PrintLine(35);
 for (uint8_t i = 0; i < sizeof(menu) / sizeof(menu[0]); Tekstprintln(menu[i++]));
 PrintLine(35);
 byte ch = Mem.LanguageChoice;
 byte dp = Mem.DisplayChoice;
 sprintf(sptext,"     Display off: %02dh - %02dh",Mem.TurnOffLEDsAtHH, Mem.TurnOnLEDsAtHH); Tekstprintln(sptext);
 sprintf(sptext,"  Display choice: %s",dp==0?"Yellow":dp==1?"Hourly":dp==2?"White":
                      dp==3?"All Own":dp==4?"Own":dp==5?"Wheel":dp==6?"Digital":"NOP"); Tekstprintln(sptext);
 sprintf(sptext,"            SSID: %s", Mem.Ssid); Tekstprintln(sptext);

// sprintf(sptext,"        Password: %s", Mem.Password);                                       Tekstprintln(sptext);
 sprintf(sptext,"        BLE name: %s", Mem.BLEbroadcastName); Tekstprintln(sptext);
 sprintf(sptext,"      IP-address: %d.%d.%d.%d",
              WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3] ); Tekstprintln(sptext);
 sprintf(sptext,"Timezone:%s", Mem.Timezone); Tekstprintln(sptext);
 sprintf(sptext," %s %s %s %s", Mem.WIFIOnOff?"WIFI=On":"WIFI=Off",
                             Mem.NTPOnOff? "NTP=On":"NTP=Off",
                             Mem.BLEOnOff? "BLE=On":"BLE=Off",
                             Mem.UseBLELongString? "FastBLE=On":"FastBLE=Off" ); Tekstprintln(sptext);
 sprintf(sptext," Language choice: %s",
         ch==0?"NL":ch==1?"UK":ch==2?"DE":ch==3?"FR":ch==4?"Rotate language":"NOP"); Tekstprintln(sptext);
 sprintf(sptext,"Software: %s",(strrchr("C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino", '\\') ? strrchr("C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino", '\\') + 1 : "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino")); Tekstprintln(sptext); //VERSION); 
 Print_tijd();
 PrintLine(35);
}
void PrintLine(byte Lengte)
{
 for(int n=0; n<Lengte; n++) sptext[n]='_';
 sptext[Lengte] = 0;
 Tekstprintln(sptext);
}
//                                                                                            //
//--------------------------------------------
// CLOCK Say the time and load the LEDs 
// with the proper colour and intensity
//--------------------------------------------
void Displaytime(void)
{
 if (Mem.DisplayChoice == DIGITAL) //PrintDigital) 
  {
//   ClearScreen();
   PrintTimeInScreen();
  }
 else
  {
   byte Language; // Start by clearing the display to a known state 
   SetSecondColour();
   if(Mem.LanguageChoice == 4) Language = random(4);
   else Language = Mem.LanguageChoice;
   switch(Language) //
     {
      case 0:
      strncpy(Template,"HETVISOWASOVIJFQPRECIESZSTIENKPFKWARTSVOORSOVERAHALFSMIDDERTVIJFATWEESOEENOXVIERELFQTIENKTWAALFBHDRIECNEGENACHTFZESVZEVENOENVUUR",129);
              ColorLeds(Template,0,127, Mem.DimmedLetter);
              Dutch(); Print_tijd(); break;
      case 1:
      strncpy(Template,"HITVISOWASOEXACTHALFITWENTYEFIVEQUARTERTENZPASTATOLFSMIDKSIXVTWOFIVEETWELVEXTENRELEVENENFOURAONETEIGHTHREENIGHTFNINESEVENROCLOCK",129);
              ColorLeds(Template,0,127, Mem.DimmedLetter);
              English(); Print_tijd(); break;
      case 2:
      strncpy(Template,"ESTISTWARSGENAUTZEHNFUNFVIERTELQZWANZIGTKURZAVORNACHYHALBKFUNFBOEINSEVIERZWOLFARMITTERNACHTNDREISECHHNSIEBENEUNBZWEIZEHNELFMKUHR",129);
              ColorLeds(Template,0,127, Mem.DimmedLetter);
              German(); Print_tijd(); break;
      case 3:
      strncpy(Template,"ILWESTETAITEXACTSIXDEUXTROISONZEQUATRERMINUITDIXCINQNEUFKMIDISWOHUITESEPTUNEDOSRHEURESYETOMOINSELETDEMIENEQUARTNDIXEVINGTOCINQKR",129);
              ColorLeds(Template,0,127, Mem.DimmedLetter);
              French(); Print_tijd(); break;
     }
//      ClearScreen();
      ShowChars();
   }
}
//--------------------------- Time functions --------------------------
//                                                                                            //
//--------------------------------------------
// RTC Get time from NTP cq RTC 
// and store it in timeinfo struct
//--------------------------------------------
void GetTijd(byte printit)
{
 if(Mem.NTPOnOff) getLocalTime(&timeinfo); // if NTP is running get the loacal time
else {

time_t now = time(
# 1154 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 3 4
                 __null
# 1154 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
                     );
//struct tm *tinfo = 
localtime_r(&now, &timeinfo);
    }

 if (printit) Print_RTC_tijd(); // otherwise time in OK struct timeonfo
}
//--------------------------------------------
// RTC prints time to serial
//--------------------------------------------
void Print_RTC_tijd(void)
{
 sprintf(sptext,"%02d:%02d:%02d %02d-%02d-%04d  ",
     timeinfo.tm_hour,timeinfo.tm_min,timeinfo.tm_sec,
     timeinfo.tm_mday,timeinfo.tm_mon,timeinfo.tm_year+1900);
 Tekstprint(sptext);
}
//--------------------------------------------
// NTP print the NTP time for the timezone set 
//--------------------------------------------
void PrintNTP_tijd(void)
{
 sprintf(sptext,"%s  ", NTP.getTimeDateString());
 Tekstprint(sptext); // 17/10/2022 16:08:15

// int dd,mo,yy,hh,mm,ss=0;      // nice method to extract the values from a string into vaiabeles
// if (sscanf(sptext, "%2d/%2d/%4d %2d:%2d:%2d", &dd, &mo, &yy, &hh, &mm, &ss) == 6) 
//     {      sprintf(sptext,"%02d:%02d:%02d %02d-%02d-%04d", hh,mm,ss,dd,mo,yy);      Tekstprintln(sptext); }
}


//--------------------------------------------
// NTP print the NTP UTC time 
//--------------------------------------------
void PrintUTCtijd(void)
{
 time_t rawtime;
 struct tm *UTCtime;
 time(&rawtime);
 gmtime_r(&rawtime, UTCtime ); // obsolete function.  UTCtime = gmtime(&rawtime );
 sprintf(sptext,"%02d:%02d:%02d %02d-%02d-%04d  ",
     UTCtime->tm_hour,UTCtime->tm_min,UTCtime->tm_sec,
     UTCtime->tm_mday,UTCtime->tm_mon,UTCtime->tm_year+1900);
 Tekstprint(sptext);
}
//--------------------------------------------
// RTC Fill sptext with time
//--------------------------------------------
void Print_tijd(){ Print_tijd(2);} // print with linefeed
void Print_tijd(byte format)
{
 sprintf(sptext,"%02d:%02d:%02d",timeinfo.tm_hour,timeinfo.tm_min,timeinfo.tm_sec);
 switch (format)
 {
  case 0: break;
  case 1: Tekstprint(sptext); break;
  case 2: Tekstprintln(sptext); break;
 }

}

//--------------------------------------------
// RTC Set time from global timeinfo struct
// Check if values are within range
//--------------------------------------------
void SetRTCTime(void)
{
 time_t t = mktime(&timeinfo);
 sprintf(sptext, "Setting time: %s", asctime(&timeinfo)); Tekstprintln(sptext);
 struct timeval now = { .tv_sec = t };
 settimeofday(&now, 
# 1224 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino" 3 4
                   __null
# 1224 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
                       );
// GetTijd(0);                                                                                  // Synchronize time with RTC clock
 Displaytime();
 Print_tijd();
}

//                                                                                            //
// ------------------- End  Time functions 

//--------------------------------------------
//  CLOCK Convert Hex to uint32
//--------------------------------------------
uint32_t HexToDec(String hexString)
{
 uint32_t decValue = 0;
 int nextInt;
 for (uint8_t i = 0; i < hexString.length(); i++)
  {
   nextInt = int(hexString.charAt(i));
   if (nextInt >= 48 && nextInt <= 57) nextInt = map(nextInt, 48, 57, 0, 9);
   if (nextInt >= 65 && nextInt <= 70) nextInt = map(nextInt, 65, 70, 10, 15);
   if (nextInt >= 97 && nextInt <= 102) nextInt = map(nextInt, 97, 102, 10, 15);
   nextInt = ((nextInt)<(0)?(0):((nextInt)>(15)?(15):(nextInt)));
   decValue = (decValue * 16) + nextInt;
  }
 return decValue;
}
//                                                                                            //
//--------------------------------------------
//  CLOCK Dutch clock display
//--------------------------------------------
void Dutch(void)
{
ColorLeds("Het", 0, 2, MINColor);; // HET  is always on
 if (timeinfo.tm_hour == 12 && timeinfo.tm_min == 0 && random(2)==0) { ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("noen", 120,123, LetterColor);; return; }
 if (timeinfo.tm_hour == 00 && timeinfo.tm_min == 0 && random(2)==0) { ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("midder", 53, 58, LetterColor);; ColorLeds("nacht", 114,118, LetterColor);; return; }
switch (timeinfo.tm_min)
 {
  case 0: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("precies", 16, 22, LetterColor);; break;
  case 1: ColorLeds("is", 4, 5, SECColor); Is = true;; break;
  case 2:
  case 3: ColorLeds("was", 7, 9, SECColor); Is = false;; break;
  case 4:
  case 5:
  case 6: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 7:
  case 8: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 9:
  case 10:
  case 11: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 12:
  case 13: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 14:
  case 15:
  case 16: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("kwart", 32, 36, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 17:
  case 18: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("kwart", 32, 36, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; break;
  case 19:
  case 20:
  case 21: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 22:
  case 23: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 24:
  case 25:
  case 26: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 27:
  case 28: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 29: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("half", 48, 51, LetterColor);; break;
  case 30: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("precies", 16, 22, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 31: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("half", 48, 51, LetterColor);; break;
  case 32:
  case 33: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("half", 48, 51, LetterColor);; break;
  case 34:
  case 35:
  case 36: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 37:
  case 38: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 39:
  case 40:
  case 41: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 42:
  case 43: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("over", 43, 46, LetterColor);; ColorLeds("half", 48, 51, LetterColor);; break;
  case 44:
  case 45:
  case 46: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("kwart", 32, 36, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 47:
  case 48: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("kwart", 32, 36, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 49:
  case 50:
  case 51: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 52:
  case 53: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("tien", 25, 28, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 54:
  case 55:
  case 56: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 57:
  case 58: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("vijf", 11, 14, LetterColor);; ColorLeds("voor", 38, 41, LetterColor);; break;
  case 59: ColorLeds("is", 4, 5, SECColor); Is = true;; break;
}
//if (timeinfo.tm_hour >=0 && hour <12) digitalWrite(AMPMpin,0); else digitalWrite(AMPMpin,1);

 sayhour = timeinfo.tm_hour;
 if (timeinfo.tm_min > 18 ) sayhour = timeinfo.tm_hour+1;
 if (sayhour == 24) sayhour = 0;

switch (sayhour)
 {
  case 13:
  case 1: ColorLeds("een", 71, 73, LetterColor);; break;
  case 14:
  case 2: ColorLeds("twee", 65, 68, LetterColor);; break;
  case 15:
  case 3: ColorLeds("drie", 97,100, LetterColor);; break;
  case 16:
  case 4: ColorLeds("vier", 76, 79, LetterColor);; break;
  case 17:
  case 5: ColorLeds("vijf", 60, 63, LetterColor);; break;
  case 18:
  case 6: ColorLeds("zes", 112,114, LetterColor);; break;
  case 19:
  case 7: ColorLeds("zeven", 116,120, LetterColor);; break;
  case 20:
  case 8: ColorLeds("acht", 107,110, LetterColor);; break;
  case 21:
  case 9: ColorLeds("negen", 102,106, LetterColor);; break;
  case 22:
  case 10: ColorLeds("tien", 84, 87, LetterColor);; break;
  case 23:
  case 11: ColorLeds("elf", 80, 82, LetterColor);; break;
  case 0:
  case 12: ColorLeds("twaalf", 89, 94, LetterColor);; break;
 }
 switch (timeinfo.tm_min)
 {
  case 59:
  case 0:
  case 1:
  case 2:
  case 3: ColorLeds("uur", 125,127, LetterColor);; break;
 }
}

//--------------------------------------------
//  CLOCK English clock display
//--------------------------------------------
void English(void)
{
 ColorLeds("It", 1, 2, MINColor);; // IT is always on
 if (timeinfo.tm_hour == 00 && timeinfo.tm_min == 0 && random(2)==0) { ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("mid", 53, 55, LetterColor);; ColorLeds("night", 106, 110, LetterColor);; return; }
 switch (timeinfo.tm_min)
 {
  case 0: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("exact", 11, 15, LetterColor);; break;
  case 1: ColorLeds("is", 4, 5, SECColor); Is = true;; break;
  case 2:
  case 3: ColorLeds("was", 7, 9, SECColor); Is = false;; break;
  case 4:
  case 5:
  case 6: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 7:
  case 8: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 9:
  case 10:
  case 11: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("ten", 39, 41, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 12:
  case 13: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("ten", 39, 41, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 14:
  case 15:
  case 16: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("quarter", 32, 38, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 17:
  case 18: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("quarter", 32, 38, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 19:
  case 20:
  case 21: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 22:
  case 23: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 24:
  case 25:
  case 26: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 27:
  case 28: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 29: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("half", 16, 19, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 30: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("exact", 11, 15, LetterColor);; ColorLeds("half", 16, 19, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 31: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("half", 16, 19, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 32:
  case 33: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("half", 16, 19, LetterColor);; ColorLeds("past", 43, 46, LetterColor);; break;
  case 34:
  case 35:
  case 36: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 37:
  case 38: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 39:
  case 40:
  case 41: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 42:
  case 43: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("twenty", 21, 26, LetterColor);; ColorLeds("to", 48, 49, LetterColor); break;
  case 44:
  case 45:
  case 46: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("quarter", 32, 38, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 47:
  case 48: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("quarter", 32, 38, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 49:
  case 50:
  case 51: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("ten", 39, 41, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 52:
  case 53: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("ten", 39, 41, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 54:
  case 55:
  case 56: ColorLeds("is", 4, 5, SECColor); Is = true;; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 57:
  case 58: ColorLeds("was", 7, 9, SECColor); Is = false;; ColorLeds("five", 28, 31, LetterColor);; ColorLeds("to", 48, 49, LetterColor);; break;
  case 59: ColorLeds("is", 4, 5, SECColor); Is = true;; break;
}
//if (timeinfo.tm_hour >=0 && hour <12) digitalWrite(AMPMpin,0); else digitalWrite(AMPMpin,1);

 sayhour = timeinfo.tm_hour;
 if (timeinfo.tm_min > 33 ) sayhour = timeinfo.tm_hour+1;
 if (sayhour == 24) sayhour = 0;

switch (sayhour)
 {
  case 13:
  case 1: ColorLeds("one", 93, 95, LetterColor);; break;
  case 14:
  case 2: ColorLeds("two", 61, 63, LetterColor);; break;
  case 15:
  case 3: ColorLeds("three", 101, 105, LetterColor);; break;
  case 16:
  case 4: ColorLeds("four", 88, 91, LetterColor);; break;
  case 17:
  case 5: ColorLeds("five", 64, 67, LetterColor);; break;
  case 18:
  case 6: ColorLeds("six", 57, 59, LetterColor);; break;
  case 19:
  case 7: ColorLeds("seven", 116, 120, LetterColor);; break;
  case 20:
  case 8: ColorLeds("eight", 97, 101, LetterColor);; break;
  case 21:
  case 9: ColorLeds("nine", 112, 115, LetterColor);; break;
  case 22:
  case 10: ColorLeds("ten", 76, 78, LetterColor);; break;
  case 23:
  case 11: ColorLeds("eleven", 80, 85, LetterColor);; break;
  case 0:
  case 12: ColorLeds("twelve", 69, 74, LetterColor);; break;
 }
 switch (timeinfo.tm_min)
 {
  case 59:
  case 0:
  case 1:
  case 2:
  case 3: ColorLeds("Oclock", 122, 127, LetterColor);; break;
 }
}
//--------------------------------------------
//  CLOCK German clock display
//--------------------------------------------
void German(void)
{
  ColorLeds("Es", 0, 1, MINColor);; // ES is always on
 if (timeinfo.tm_hour == 00 && timeinfo.tm_min == 0 && random(2)==0) {ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("mitter", 80, 85, LetterColor);; ColorLeds("nacht", 86, 90, LetterColor);; return; }
 switch (timeinfo.tm_min)
 {
  case 0: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("genau", 10, 14, LetterColor);; break;
  case 1: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("kurz", 40, 43, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 2:
  case 3: ColorLeds("war", 6, 8, SECColor); Is = false;; break;
  case 4:
  case 5:
  case 6: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 7:
  case 8: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 9:
  case 10:
  case 11: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 12:
  case 13: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 14:
  case 15:
  case 16: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("viertel", 24, 30, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 17:
  case 18: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("viertel", 24, 30, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; break;
  case 19:
  case 20:
  case 21: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 22:
  case 23: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 24:
  case 25:
  case 26: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 27:
  case 28: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 29: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("kurz", 40, 43, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 30: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("genau", 10, 14, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 31: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("kurz", 40, 43, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 32:
  case 33: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 34:
  case 35:
  case 36: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 37:
  case 38: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 39:
  case 40:
  case 41: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 42:
  case 43: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("nach", 48, 51, LetterColor);; ColorLeds("halb", 53, 56, LetterColor);; break;
  case 44:
  case 45:
  case 46: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("viertel", 24, 30, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 47:
  case 48: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("viertel", 24, 30, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 49:
  case 50:
  case 51: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 52:
  case 53: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("zehn", 16, 19, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 54:
  case 55:
  case 56: ColorLeds("ist", 3, 5, SECColor); Is = true;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 57:
  case 58: ColorLeds("war", 6, 8, SECColor); Is = false;; ColorLeds("funf", 20, 23, LetterColor);; ColorLeds("vor", 45, 47, LetterColor);; break;
  case 59: ColorLeds("ist", 3, 5, SECColor); Is = true;; break;
}
//if (timeinfo.tm_hour >=0 && hour <12) digitalWrite(AMPMpin,0); else digitalWrite(AMPMpin,1);

 sayhour = timeinfo.tm_hour;
 if (timeinfo.tm_min > 18 ) sayhour = timeinfo.tm_hour+1;
 if (sayhour == 24) sayhour = 0;

switch (sayhour)
 {
  case 13:
  case 1: ColorLeds("eins", 64, 67, LetterColor);; break;
  case 14:
  case 2: ColorLeds("zwei", 112, 115, LetterColor);; break;
  case 15:
  case 3: ColorLeds("drei", 92, 95, LetterColor);; break;
  case 16:
  case 4: ColorLeds("vier", 69, 72, LetterColor);; break;
  case 17:
  case 5: ColorLeds("funf", 58, 61, LetterColor);; break;
  case 18:
  case 6: ColorLeds("sechs", 96, 100, LetterColor);; break;
  case 19:
  case 7: ColorLeds("sieben", 102, 107, LetterColor);; break;
  case 20:
  case 8: ColorLeds("acht", 87, 90, LetterColor);; break;
  case 21:
  case 9: ColorLeds("neun", 107, 110, LetterColor);; break;
  case 22:
  case 10: ColorLeds("zehn", 116, 119, LetterColor);; break;
  case 23:
  case 11: ColorLeds("elf", 120, 122, LetterColor);; break;
  case 0:
  case 12: ColorLeds("zwolf", 73, 77, LetterColor);; break;
 }
 switch (timeinfo.tm_min)
 {
  case 59:
  case 0:
  case 1:
  case 2:
  case 3: ColorLeds("uhr", 125, 127, LetterColor);; break;
 }
}
//--------------------------------------------
//  CLOCK French clock display
//--------------------------------------------
void French(void)
{
 ColorLeds("Il", 0, 1, MINColor);; // IL is always on
 switch (timeinfo.tm_min)
 {
  case 0: ColorLeds("est", 3, 5, SECColor); Is = true;; ColorLeds("exact", 11, 15, LetterColor);; DitLeHeure();; break;
  case 1: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; break;
  case 2:
  case 3: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; break;
  case 4:
  case 5:
  case 6: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 7:
  case 8: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 9:
  case 10:
  case 11: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("dix", 112, 114, LetterColor);; break;
  case 12:
  case 13: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("dix", 112, 114, LetterColor);; break;
  case 14:
  case 15:
  case 16: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("quart", 106, 110, LetterColor);; break;
  case 17:
  case 18: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("quart", 106, 110, LetterColor);; break;
  case 19:
  case 20:
  case 21: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("vingt", 116, 120, LetterColor);; break;
  case 22:
  case 23: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("vingt", 116, 120, LetterColor);; break;
  case 24:
  case 25:
  case 26: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("vingt", 116, 120, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 27:
  case 28: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("vingt", 116, 120, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 29: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("demie", 99, 103, LetterColor);; break;
  case 30: ColorLeds("est", 3, 5, SECColor); Is = true;; ColorLeds("exact", 11, 15, LetterColor);; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("demie", 99, 103, LetterColor);; break;
  case 31: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("demie", 99, 103, LetterColor);; break;
  case 32:
  case 33: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("et", 87, 88, LetterColor);; ColorLeds("demie", 99, 103, LetterColor);; break;
  case 34:
  case 35:
  case 36: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("vingt", 116, 120, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 37:
  case 38: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("vingt", 116, 120, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 39:
  case 40:
  case 41: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("vingt", 116, 120, LetterColor);; break;
  case 42:
  case 43: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("vingt", 116, 120, LetterColor);; break;
  case 44:
  case 45:
  case 46: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("le", 96, 97, LetterColor);; ColorLeds("quart", 106, 110, LetterColor);; break;
  case 47:
  case 48: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("le", 96, 97, LetterColor);; ColorLeds("quart", 106, 110, LetterColor);; break;
  case 49:
  case 50:
  case 51: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("dix", 112, 114, LetterColor);; break;
  case 52:
  case 53: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("dix", 112, 114, LetterColor);; break;
  case 54:
  case 55:
  case 56: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 57:
  case 58: ColorLeds("etait", 6, 10, SECColor); Is = false;; DitLeHeure();; ColorLeds("moins", 90, 94, LetterColor);; ColorLeds("cinq", 122, 125, LetterColor);; break;
  case 59: ColorLeds("est", 3, 5, SECColor); Is = true;; DitLeHeure();; break;
 }
}

void DitLeHeure(void)
{
 byte sayhour = timeinfo.tm_hour;
 if (timeinfo.tm_min > 33 ) sayhour = timeinfo.tm_hour+1;
 if (sayhour == 24) sayhour = 0;

switch (sayhour)
 {
  case 13:
  case 1: ColorLeds("une", 73, 75, LetterColor);; ColorLeds("heure", 80, 84, LetterColor);; break;
  case 14:
  case 2: ColorLeds("deux", 19, 22, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 15:
  case 3: ColorLeds("trois", 23, 27, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 16:
  case 4: ColorLeds("quatre", 32, 37, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 17:
  case 5: ColorLeds("cinq", 48, 51, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 18:
  case 6: ColorLeds("six", 16, 18, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 19:
  case 7: ColorLeds("sept", 69, 72, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 20:
  case 8: ColorLeds("huit", 64, 67, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 21:
  case 9: ColorLeds("neuf", 52, 55, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 22:
  case 10: ColorLeds("dix", 45, 47, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 23:
  case 11: ColorLeds("onze", 28, 31, LetterColor);; ColorLeds("heures", 80, 85, LetterColor);; break;
  case 0: ColorLeds("minuit", 39, 44, LetterColor);; break;
  case 12: ColorLeds("midi", 57, 60, LetterColor);; break;
 }
}
//                                                                                            //

//-----------------------------
// BLE 
// SendMessage by BLE Slow in packets of 20 chars
// or fast in one long string.
// Fast can be used in IOS app BLESerial Pro
//------------------------------
void SendMessageBLE(std::string Message)
{
 if(deviceConnected)
   {
    if (Mem.UseBLELongString) // If Fast transmission is possible
     {
      pTxCharacteristic->setValue(Message);
      pTxCharacteristic->notify();
      delay(10); // Bluetooth stack will go into congestion, if too many packets are sent
     }
   else // Packets of max 20 bytes
     {
      int parts = (Message.length()/20) + 1;
      for(int n=0;n<parts;n++)
        {
         pTxCharacteristic->setValue(Message.substr(n*20, 20));
         pTxCharacteristic->notify();
         delay(40); // Bluetooth stack will go into congestion, if too many packets are sent
        }
     }
   }
}

//-----------------------------
// BLE Start BLE Classes
//------------------------------
class MyServerCallbacks: public NimBLEServerCallbacks
{
 void onConnect(NimBLEServer* pServer) {deviceConnected = true; };
 void onDisconnect(NimBLEServer* pServer) {deviceConnected = false;}
};

class MyCallbacks: public NimBLECharacteristicCallbacks
{
 void onWrite(NimBLECharacteristic *pCharacteristic)
  {
   std::string rxValue = pCharacteristic->getValue();
   ReceivedMessageBLE = rxValue + "\n";
//   if (rxValue.length() > 0) {for (int i = 0; i < rxValue.length(); i++) printf("%c",rxValue[i]); }
//   printf("\n");
  }
};

//-----------------------------
// BLE Start BLE Service
//------------------------------
void StartBLEService(void)
{
 NimBLEDevice::init(Mem.BLEbroadcastName); // Create the BLE Device
 pServer = NimBLEDevice::createServer(); // Create the BLE Server
 pServer->setCallbacks(new MyServerCallbacks());
 NimBLEService *pService = pServer->createService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E" /* UART service UUID*/); // Create the BLE Service
 pTxCharacteristic = // Create a BLE Characteristic 
     pService->createCharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", NIMBLE_PROPERTY::NOTIFY);
 NimBLECharacteristic * pRxCharacteristic =
     pService->createCharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", NIMBLE_PROPERTY::WRITE);
 pRxCharacteristic->setCallbacks(new MyCallbacks());
 pService->start();
 NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
 pAdvertising->addServiceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E" /* UART service UUID*/);
 pServer->start(); // Start the server  Nodig??
 pServer->getAdvertising()->start(); // Start advertising
 TekstSprint("BLE Waiting a client connection to notify ...\n");
}
//                                                                                            //
//-----------------------------
// BLE  CheckBLE
//------------------------------
void CheckBLE(void)
{
 if(!deviceConnected && oldDeviceConnected) // Disconnecting
   {
    delay(500); // Give the bluetooth stack the chance to get things ready
    pServer->startAdvertising(); // Restart advertising
    TekstSprint("Start advertising\n");
    SetStatusLED(-1,-1,-1,-1, 0); // Turn off blue LED
    oldDeviceConnected = deviceConnected;
   }
 if(deviceConnected && !oldDeviceConnected) // Connecting
   {
    SetStatusLED(-1,-1,-1,-1, 8); // Turn on blue LED
    oldDeviceConnected = deviceConnected;
    SWversion();
   }
 if(ReceivedMessageBLE.length()>0)
   {
    SendMessageBLE(ReceivedMessageBLE);
    String BLEtext = ReceivedMessageBLE.c_str();
    ReceivedMessageBLE = "";
    ReworkInputString(BLEtext);
   }
}
//                                                                                            //


// -------------------------------------------                                                //
/* Avaiable functions for the ILI9341 display

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

 void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);

 void fillScreen(uint16_t color);

 void setTextSize(uint8_t s);

 void setTextSize(uint8_t sx, uint8_t sy);

 void setFont(const GFXfont *f = NULL);

 void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size);

 void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y);

 virtual void setRotation(uint8_t r);

 virtual void invertDisplay(bool i);



 void setCursor(int16_t x, int16_t y)

 void setTextColor(uint16_t c, uint16_t bg)

 void setTextWrap(bool w) { wrap = w; }

 int16_t width(void) const { return _width; };

 int16_t height(void) const { return _height; }

 uint8_t getRotation(void) const { return rotation; }

 int16_t getCursorX(void) const { return cursor_x; }

 int16_t getCursorY(void) const { return cursor_y; };

*/
# 1820 "C:\\Users\\ednie\\Documents\\Files\\Arduino\\ESP32-C3-Wordclock\\ESP32C3-WordClockV009\\ESP32C3-WordClockV009.ino"
//--------------------------------------------
//  SCREEN Init screen
//--------------------------------------------
void InitScreen(void)
{
 tft.begin();
 SetBackLight(0XA0); // Turn on the backlight 0 - 0xFF
 tft.setRotation(3);
 tft.fillScreen(ConvertRGB32toRGB16(0xFFA500)); // Convert colors to RGB16, except C_BLACK (=0x000000)
 tft.setTextColor(0x000000, ConvertRGB32toRGB16(0xFFA500)); // Convert colors to RGB16, except C_BLACK (=0x000000)
 tft.setCursor(20, tft.height()/3);
 tft.setTextSize(2);
 tft.println("Starting");
}

//--------------------------------------------
//  SCREEN Cobvert 32 bit RGBW to 16 bit RGB
//--------------------------------------------
unsigned short ConvertRGB32toRGB16(uint32_t sourceColor)
{
  uint32_t red = (sourceColor & 0x00FF0000) >> 16;
  uint32_t green = (sourceColor & 0x0000FF00) >> 8;
  uint32_t blue = sourceColor & 0x000000FF;
  return (red >> 3 << 11) + (green >> 2 << 5) + (blue >> 3);
}

//--------------------------------------------
//  SCREEN Make the the screen black
//--------------------------------------------
void ClearScreen(void)
{
  tft.fillScreen(Mem.BackGround);
}
//--------------------------------------------
//  SCREEN Set intensity backlight (0 -255)
//--------------------------------------------
void SetBackLight(byte intensity)
{
 analogWrite(1 /* the LED backlight display*/, intensity);
}
//                                                                                            //
//--------------------------------------------
//  SCREEN 
//  Print characters on the display with black background
//--------------------------------------------
void ShowChars(void)
{
 int LEDnr = 0;
 for(int y = 0; y < MATRIX_HEIGHT; y++)
    for(int x = 0; x < MATRIX_WIDTH; x++, LEDnr++)
       {
        tft.drawChar(20 * x, 10 + 27 * y, Strippos[LEDnr].Character,
                      ConvertRGB32toRGB16(Strippos[LEDnr].RGBColor),
                            ConvertRGB32toRGB16(Mem.BackGround), 2);
        CheckDevices(); // printing is slow, we need a check here too
       }
}
//--------------------------------------------
//  SCREEN Print the digital time in screen
//--------------------------------------------
void PrintTimeInScreen(void)
{
 tft.setTextColor(ConvertRGB32toRGB16(0xFFFFFF), 0x000000); // Convert colors to RGB16, except C_BLACK (=0x000000)
 GetTijd(0);
// ClearScreen(); 
 tft.setCursor(20, 20);
 if(Mem.WIFIOnOff && !IP_Printed) { PrintIPaddressInScreen(); IP_Printed = true; } // If WIFI is on print the IP-address
 sprintf(sptext,"%02d:%02d:%02d",timeinfo.tm_hour,timeinfo.tm_min,timeinfo.tm_sec);
  tft.setCursor(20, 60);
 Displayprint(sptext);
 if (Date_Printed) return;
 sprintf(sptext,"%02d-%02d-%04d",timeinfo.tm_mday,timeinfo.tm_mon,timeinfo.tm_year+1900);
 tft.setCursor(20, 100);
 Displayprint(sptext);
 Date_Printed = true;
}
//--------------------------------------------
//  SCREEN 
// Print Web server IP address in screen
//--------------------------------------------
void PrintIPaddressInScreen()
{
 sprintf(sptext, "%d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3] );
 Displayprintln(sptext);
}
//                                                                                            //
//--------------------------------------------
// WIFI WEBPAGE 
//--------------------------------------------
void StartWIFI_NTP(void)
{
 WiFi.mode(WIFI_MODE_STA);
 WiFi.begin (Mem.Ssid, Mem.Password);
 if (WiFi.waitForConnectResult() != WL_CONNECTED)
      {
       Displayprintln("WiFi Failed!"); // Print the text on the display
       Tekstprintln("WiFi Failed!");
       WIFIConnected = 0;
       return;
      }
 else {
       Tekstprint("Web page started\n");
       sprintf(sptext, "IP Address: %d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3] );
       Displayprintln(sptext);
       Tekstprintln(sptext);

       WIFIConnected = 1;
       Displayprintln("WIFI is On");
       if(Mem.NTPOnOff)
          {
           NTP.setTimeZone(Mem.Timezone); // TZ_Europe_Amsterdam); //\TZ_Etc_GMTp1); // TZ_Etc_UTC 
           NTP.begin (); // https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
           Tekstprintln("NTP On");
           Displayprintln("NTP is On"); // Print the text on the display
          }
       PrintIPaddressInScreen();
      }
 if(Mem.WIFIOnOff) WebPage(); // Show the web page if WIFI is on
}

//--------------------------------------------
// WIFI WEBPAGE 
//--------------------------------------------
void WebPage(void)
{
 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) // Send web page with input fields to client
          { request->send_P(200, "text/html", index_html); } );
 server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
       {
        String inputMessage; String inputParam;
        if (request->hasParam(PARAM_INPUT_1)) // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
           {
            inputMessage = request->getParam(PARAM_INPUT_1)->value();
            inputParam = PARAM_INPUT_1;
           }
        else
           {
            inputMessage = ""; //inputMessage = "No message sent";
            inputParam = "none";
           }
        sprintf(sptext,"%s",inputMessage); Tekstprintln(sptext);
        ReworkInputString(inputMessage+"\n");
        request->send_P(200, "text/html", index_html);
       } );
 server.onNotFound(notFound);
 server.begin();
}


void notFound(AsyncWebServerRequest *request)
{
  request->send(404, "text/plain", "Not found");
}
//                                                                                            //
