#include "WiFi.h"
#include "time.h"
#include "TFT_eSPI.h"
#include "U8g2_for_TFT_eSPI.h"
// Objekt für Schriften von U8g2 (u8g2Schriften)
U8g2_for_TFT_eSPI u8g2Schriften;
TFT_eSPI tft = TFT_eSPI();
// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";
// Variablen des TFTs (Höhe, Breite, Radius)
const int MitteHoehe = 120;
const int MitteBreite = 120;
const int Radius = 120;
// Multiplikatoren für x- y-Positionen der Stunden, Minuten und Sekunden
float SekundePosX = 0, SekundePosY = 0, MinutePosX = 0, MinutePosY = 0, StundePosX = 0, StundePosY = 0;
float GradSekunden = 0, GradMinuten = 0, GradStunden = 0;
// x- y-Koordinaten für die Anzeige Stunden, Minuten und Sekunden
int SekundenZeigerX = MitteHoehe, SekundenZeigerY = MitteHoehe;
int MinutenZeigerX = MitteHoehe, MinutenZeigerY = MitteHoehe;
int StundenZeigerX = MitteHoehe, StundenZeigerY = MitteHoehe;
// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = 1;
// Variablen für die Markierungen und Punkte und Striche des Ziffernblatts
float PosX, PosY;
int PunktX, PunktY, PunktX1, PunktX2, PunktY1, PunktY2;
// Variablen für die Zeit
int Stunden, Minuten, Sekunden;
// Farben
#define SCHWARZ 0x0000
#define WEISS 0xFFFF
#define BLAU 0x001F
#define ROT 0xF800
#define GRUEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define GELB 0xFFE0
#define BRAUN 0x9A60
#define GRAU 0x7BEF
#define GRUENGELB 0xB7E0
#define DUNKELCYAN 0x03EF
#define ORANGE 0xFDA0
#define PINK 0xFE19
#define BORDEAUX 0xA000
#define HELLBLAU 0x867D
#define VIOLETT 0x915C
#define SILBER 0xC618
#define GOLD 0xFEA0
// Farben innerer Kreis, Randfarbe und Zeigerfarbe
// die Farben der Zeiger können aber auch individuell gesetzt werden
const int Kreisfarbe = SCHWARZ;
const int Zeigerfarbe = WEISS;
const int Randfarbe = BORDEAUX;
// true -> Datum anzeigen
// false -> Datum nicht anzeigen
bool DatumAnzeigen = true;
// Ziffern 12 3 6 9 anzeigen/nicht anzeigen
bool Ziffernanzeigen = true;
// true -> Sekundenzeiger nur als Kreis
bool SekundenzeigerKreis = false;
// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"
/*
Liste der Zeitzonen
https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
CEST = Central European SuMinutener Time von
M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"
// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;
/*
Struktur tm
tm_hour -> Stunde: 0 bis 23
tm_min -> Minuten: 0 bis 59
tm_sec -> Sekunden 0 bis 59
tm_mday -> Tag 1 bis 31
tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
tm_year -> Jahre seit 1900
tm_yday -> vergangene Tage seit 1. Januar des Jahres
tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
/*
Array
1. Eintrag: Datum, wenn < 10 -> 0 davor setzen
2. Eintrag: Name des Termins
DatenMax an die Anzahl der Einträge anpassen
*/
#define DatenMax 8
String Kalender[DatenMax] [2] =
{
{"10.07.", "Klaus"},
{"10.07.", "Maria"},
{"11.07.", "Thea"},
{"12.07.", "Josef"},
{"13.07.", "Magdalena"},
{"14.07.", "Thomas"},
{"15.07.", "Klara"},
{"15.07.", "Tobias"},
};
unsigned long Zeitmessung = 0;
void setup()
{
Serial.begin(9600);
// Schriften von u8g2 tft zuordnen
u8g2Schriften.begin(tft);
// Zeitzone: Parameter für die zu ermittelnde Zeit
configTzTime(Zeitzone, Zeitserver);
// WiFi starten
WiFi.mode(WIFI_STA);
WiFi.begin(Router, Passwort);
Serial.println("------------------------");
while (WiFi.status() != WL_CONNECTED)
{
delay(200);
Serial.print(".");
}
Serial.println();
Serial.print("Verbunden mit ");
Serial.println(Router);
Serial.print("IP über DHCP: ");
Serial.println(WiFi.localIP());
// Zeit holen
time(&aktuelleZeit);
// localtime_r -> Zeit in die lokale Zeitzone setzen
localtime_r(&aktuelleZeit, &Zeit);
// Zeit in Stunden, Minuten und Sekunden
Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
tft.begin();
tft.setRotation(0);
tft.fillScreen(SCHWARZ);
// 4 Pixel breiter äußerer Rand, Farbe au der Farbpalette wählen
tft.drawCircle(MitteHoehe, MitteBreite, Radius - 1, Randfarbe);
tft.drawCircle(MitteHoehe, MitteBreite, Radius - 2, Randfarbe);
tft.drawCircle(MitteHoehe, MitteBreite, Radius - 3, Randfarbe);
tft.drawCircle(MitteHoehe, MitteBreite, Radius - 4, Randfarbe);
// innere Fläche bis auf den Rand von 4 Pixeln vollständig löschen
// wenn andere Farbe als äußerer Rand gewählt wird ergibt sich ein schmaler Rand
tft.fillCircle(MitteHoehe, MitteBreite, Radius - 4, Kreisfarbe);
/*
alle 30° Linie am Rand als Stundenmarkierung zeichnen
DEG_TO_RAD (= PI/180 = 0.0174532925) -> Winkel in Bogenmaß umrechnen
sin/cos berechnen die x-/y-Kordinaten des Punktes auf der Kreislinie
*/
for (int i = 0; i < 360; i += 30)
{
PosX = cos((i - 90) * DEG_TO_RAD);
PosY = sin((i - 90) * DEG_TO_RAD);
// kurze Linien zeichnen, von 114 bis 100 vom äußeren Rand aus
// Farbe individuell wählbar
int PunktX1 = PosX * 110 + Radius;
int PunktY1 = PosY * 110 + Radius;
int PunktX2 = PosX * 100 + Radius;
int PunktY2 = PosY * 100 + Radius;
tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Zeigerfarbe);
// keine Striche an der Position der Zahlen
if (Ziffernanzeigen)
{
if (PunktX1 == 10 || PunktX1 == 120 || PunktX1 == 230)
{
tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Kreisfarbe);
}
}
}
// alle 6 Grad Punkte als Minutenmarkierung zeichnen
for (int i = 0; i < 360; i += 6)
{
PosX = cos((i - 90) * DEG_TO_RAD);
PosY = sin((i - 90) * DEG_TO_RAD);
// Positionen der Punkte
// 108 -> Abstand vom Mittelpunkt
PunktX = PosX * 108 + Radius;
PunktY = PosY * 108 + Radius;
tft.drawPixel(PunktX, PunktY, Zeigerfarbe);
}
// Markierung 12 3 6 9
if (Ziffernanzeigen)
{
tft.setTextSize(2);
tft.setTextColor(Zeigerfarbe);
tft.setCursor(110, 16);
tft.print("12");
tft.setCursor(10, 110);
tft.print("9");
tft.setCursor(220, 110);
tft.print("3");
tft.setCursor(113, 220);
tft.print("6");
}
if (DatumAnzeigen) ZeigeDatum();
Zeitmessung = millis() + 1000;
}
void loop()
{
// Sekunden weiter zählen
if (Zeitmessung < millis())
{
Zeitmessung += 1000;
Sekunden ++;
if (Sekunden == 60)
{
if (DatumAnzeigen) ZeigeDatum();
// Daten des Kalenders durchsuchen
KalenderDurchsuchen();
// Zeit jede Sekunde mit Zeitserver synchronisieren
// aktuelle Zeit holen
time(&aktuelleZeit);
// localtime_r -> Zeit in die lokale Zeitzone setzen
localtime_r(&aktuelleZeit, &Zeit);
// Zeit in Stunden, Minuten und Sekunden
Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
if (Minuten > 59)
{
Minuten = 0;
Stunden++;
if (Stunden > 23) Stunden = 0;
}
}
// Vorausberechnung der x- und y-Koordinaten
// 0-59 -> 0-354 = Faktor 6
GradSekunden = Sekunden * 6;
// Minuten+Sekunden in Relation zu 3600 setzen
// 60 / 3600 = 0.01666667
GradMinuten = Minuten * 6 + GradSekunden * 0.01666667;
// 30 / 3600 = 0.0833333
// Stunden+Minuten in Relation zu 360 setzen
// 0-11 -> 0-360
GradStunden = Stunden * 30 + GradMinuten * 0.0833333; // 0-11 -> 0-360
StundePosX = cos((GradStunden - 90) * DEG_TO_RAD);
StundePosY = sin((GradStunden - 90) * DEG_TO_RAD);
MinutePosX = cos((GradMinuten - 90) * DEG_TO_RAD) ;
MinutePosY = sin((GradMinuten - 90) * DEG_TO_RAD);
SekundePosX = cos((GradSekunden - 90) * DEG_TO_RAD);
SekundePosY = sin((GradSekunden - 90) * DEG_TO_RAD);
// nach jeder Minute Minuten-/Stundenzeiger löschen
// oder einmalig beim Start der Anzeige
if (Sekunden == 0 || Start)
{
Start = false;
tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);
// 62 Pixel -> Länge des Stundenzeigers
// Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
StundenZeigerX = StundePosX * 62 + MitteHoehe + 1;
StundenZeigerY = StundePosY * 62 + MitteHoehe + 1;
tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);
// 84 Pixel -> Länge des Minutenzeigers
// Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
MinutenZeigerX = MinutePosX * 84 + MitteHoehe;
MinutenZeigerY = MinutePosY * 84 + MitteHoehe + 1;
}
// Sekundenzeiger löschen
if (!SekundenzeigerKreis) tft.drawLine(SekundenZeigerX, SekundenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);
// Kreis am Sekundenzeiger löschen, Radius 5
tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, Kreisfarbe);
// 85 Pixel -> Länge des Sekundenzeigers
SekundenZeigerX = SekundePosX * 85 + MitteHoehe + 1;
SekundenZeigerY = SekundePosY * 85 + MitteHoehe + 1;
// Zeiger neu zeichnen
// Sekunden Linie nur anzeigen wenn SekundenzeigerKreis false
if (!SekundenzeigerKreis) tft.drawLine(SekundenZeigerX, SekundenZeigerY, MitteHoehe, MitteHoehe + 1, ROT);
// Minuten
tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);
// Stunden
tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);
// Kreis an der Spitze des Sekundenzeigers, Radius 5
tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, ROT);
// Mittelpunkt zeichnen
tft.fillCircle(MitteHoehe, MitteHoehe + 1, 3, Zeigerfarbe);
}
}
void ZeigeDatum()
{
tft.fillRect(10, 240, tft.width(), tft.height(), SCHWARZ);
u8g2Schriften.setForegroundColor(GRUEN);
u8g2Schriften.setBackgroundColor(SCHWARZ);
u8g2Schriften.setFont(u8g2_font_helvB14_tf);
u8g2Schriften.setCursor(1, 260);
// Wochentag anzeigen
switch (Zeit.tm_wday)
{
case 0:
u8g2Schriften.print("Sonntag");
break;
case 1:
u8g2Schriften.print("Montag");
break;
case 2:
u8g2Schriften.print("Dienstag");
break;
case 3:
u8g2Schriften.print("Mittwoch");
break;
case 4:
u8g2Schriften.print("Donnerstag");
break;
case 5:
u8g2Schriften.print("Freitag");
break;
case 6:
u8g2Schriften.print("Samstag");
break;
}
u8g2Schriften.print(", ");
if (Zeit.tm_mday < 10) u8g2Schriften.print("0");
u8g2Schriften.print(Zeit.tm_mday);
u8g2Schriften.print(".");
// Monat: führende 0 ergänzen
if (Zeit.tm_mon < 9) u8g2Schriften.print("0");
// Zählung beginnt mit 0 -> +1
u8g2Schriften.print(Zeit.tm_mon + 1);
u8g2Schriften.print(".");
// Anzahl Jahre seit 1900
u8g2Schriften.print(Zeit.tm_year + 1900);
}
void KalenderDurchsuchen()
{
String Datum;
bool Treffer = false;
String Eintrag = "";
// Datum zusammensetzen: TT.MM.
if (Zeit.tm_mday < 10) Datum = "0" + String(Zeit.tm_mday);
else Datum = String(Zeit.tm_mday);
Datum += ".";
if (Zeit.tm_mon < 10) Datum += "0" + String(Zeit.tm_mon + 1);
else Datum += String(Zeit.tm_mon + 1);
Datum += ".";
Serial.println(Datum);
for (int i = 0; i < 2; i++)
{
// Serial.println(Kalender[i] [0]);
if (Kalender[i] [0] == Datum)
{
Treffer = true;
Eintrag += Kalender[i] [1] + " ";
Serial.println(Kalender[i] [1]);
}
}
if (Treffer)
{
u8g2Schriften.setForegroundColor(BLAU);
u8g2Schriften.setBackgroundColor(SCHWARZ);
u8g2Schriften.setFont(u8g2_font_helvB14_tf);
u8g2Schriften.setCursor(1, 285);
u8g2Schriften.print("Geburtstage");
u8g2Schriften.setCursor(1, 310);
u8g2Schriften.print(Eintrag);
}
else
{
u8g2Schriften.setForegroundColor(BLAU);
u8g2Schriften.setBackgroundColor(SCHWARZ);
u8g2Schriften.setFont(u8g2_font_helvB14_tf);
u8g2Schriften.setCursor(1, 285);
u8g2Schriften.print("Keine Termine heute!");
}
}