Jo das wars dann wohl auch...
Mittels einer Codezeile
u8g2.enableUTF8Print();
erscheint dann:
Darauf hatte ich Dich bereits in #137 hin gewiesen.
Gruß Tommy
Sorry… Hab ich wohl übersehen…
(Zwischendurch kam mal meine Frau mit tu mal hier & mach mal da…
)
Bitte ersetze u8g2.clear(); durch u8g2.clearBuffer();, dann flackert es nicht mehr.
In der Fontliste steht der Unicode, also z. B. "E218" als Hexwert. Diesen Unicode muß man dann in UTF-8 wandeln, was dann zu \xEE\x88\x98 führt.
u8g2.clearBuffer();
u8g2.setCursor(1, 35);
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.printf( "%2u:%02u:", stunden, minuten );
u8g2.setFont(u8g2_font_logisoso16_tn);
u8g2.printf( "%02u", sekunden );
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.setCursor(1, 60);
u8g2.print("\xEE\x88\x98 \xEE\x88\x99 \xEE\x88\x9A \xEE\x88\x9f \xEE\x88\xa0 \xEE\x88\xA1 \xEE\x88\xA2");
// Rahmen um die ganze geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1-_LCDML_DISP_box_x0), (_LCDML_DISP_box_y1-_LCDML_DISP_box_y0));
u8g2.sendBuffer();
Ich habe UTF-8-Codetabelle mit Unicode-Zeichen verwendet.
![]()
![]()
![]()
Ich hab festgestellt, dass die Steuerung von Output Pins über den Encoder ab und an nicht hinhaut..
Hat vielleicht mit der Menüstruktur zu tun…
Die ist aktuell (schematisch gesehen) so aufgebaut
Ebene 0 —- Ebene 1 —- Ebene 2 --- Aktion
Gruppe1 —- Gerät1 —- Aktivieren --- digitalWrite(pin1, HIGH);
—- Deaktivieren --- digitalWrite(pin1, LOW);
—- Gerät2 —- aktivieren --- digitalWrite(pin2, HIGH);
—- deaktivieren --- digitalWrite(pin2, LOW);
Gruppe2 —- Gerät1 —- Aktivieren --- digitalWrite(pin3, HIGH);
—- Deaktivieren --- digitalWrite(pin3, LOW);
—- Gerät2 —- aktivieren --- digitalWrite(pin4, HIGH);
—- deaktivieren --- digitalWrite(pin4, LOW);
usw..
Etc… Hoffentlich einigermaßen verständlich?
Jedenfalls „frisst“ er ab und an das „Enter“ (Encoder Taste drücken) beim aktivieren oder deaktivieren nicht…
Um jetzt sicher zu erfahren ob das entsprechende Gerät jetzt tatsächlich eingeschaltet / angesteuert wurde, würde ich gern den entsprechenden Output pin zurücklesen…
Soweit ich weiß soll das mit digitalRead(pin) gehen..
Das ganze würd ich das dann gern mit weiteren icons auf dem Display anzeigen wollen…
Als Beispiel: Anhänger Ladeleitung
Wenn die aktiv ist soll idealerweise eine Animation aus diesen Icons erfolgen:
EE 89 82 bis EE 89 8B (Batterie mit verschiedenen Ladezuständen - in der Animation dann eine von leer auf voll ladende Batterie)
Der Loop der LCDML funtion ist auf 200ms „gebremst“ wäre also durchaus denkbar das mit jedem Durchlauf ein Icon weiter geschaltet wird und nach der EE 89 8B wieder zurück zur EE 89 82 und immer so weiter…
Ist das realisierbar?
Meine Idee dazu wäre eigentlich im setup der aktiven LCDML Funktion (in dem Fall der Screensaver mit der Uhr) eine Zähler Variable zu definieren..
Z.B. int zaehler=0;
Und im funktions Loop den Zähler dann jeweils um 1 zu erhöhen…
Dann mittels ner Latte an if abfragen den Zählerstand mit dem entsprechenden Icon zu verknüpfen und in der letzten Abfrage den Zähler wieder auf null zu setzen…
Das Problem dabei ist allerdings, das er im funktions setup erstellte Variablen im folgenden funktions Loop nicht mehr kennt und mir nen Compiler Fehler raus schmeißt..
Außerdem geht das bestimmt auch eleganter, oder?
<Update 09:03
Mir ist noch eingefallen, dass es ja auch noch arrays gibt...
Also war mein neuer plan, die Symbole in ein Array zu schreiben und dann via for schleife über die Array index Nummer das entsprechende Symbol zu laden...
String ladeltg[] = {"\xEE\x89\x82", "\xEE\x89\x83", "\xEE\x89\x84", "\xEE\x89\x85", "\xEE\x89\x86", "\xEE\x89\x87", "\xEE\x89\x88", "\xEE\x89\x89", "\xEE\x89\x8A", "\xEE\x89\x8B"};
for(int i=0; i<=9; i++)
{
u8g2.setCursor(2, 48);
u8g2.print(ladeltg[i]);
}
Ich hab jetzt noch das Problem, das die Animation nicht wie geplant abläuft...
Ich bekomm direkt die "Volle Batterie" angezeigt...
des Weiteren hab ich das Problem das ich i nicht zurück auf null setzen kann ohne den ESP in einer Endlosschleife zu fesseln... Was dann dazu führt, das ich den ESP nicht mehr über OTA neu flashen kann...
Ja!
Im Beispiel habe ich mFunc_timer_info() gefunden, ein sekündlich runterzählender Zähler, den man dafür als Vorbild nutzen könnte.
Jomelo verwendet globale Variablen, um vorherige Zeit und Zähler zu speichern, mir sind statische lokale Variablen lieber.
Deine Idee mit dem Feld ist gut, ich ändere nur das letzte Zeichen durch Berechnung, weil die Zeichen vom Zahlenwert aufeinander folgen.
Ich habe dann noch "timer" in "load" geändert.
// *********************************************************************
void mFunc_load_info(uint8_t param)
// *********************************************************************
{
static uint8_t g_func_load_info = 1; // counter (global variable)
static unsigned long g_timer_1 = 0; // timer variable (global variable)
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// remmove compiler warnings when the param variable is not used:
LCDML_UNUSED(param);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.drawUTF8( 1, 15, "Laden: \xEE\x89\x82");
// Rahmen um die ganze Geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1 - _LCDML_DISP_box_x0), (_LCDML_DISP_box_y1 - _LCDML_DISP_box_y0));
u8g2.sendBuffer();
LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds
LCDML.TIMER_msReset(g_timer_1);
}
if (LCDML.FUNC_loop()) // ****** LOOP ********* this function is called every 100 milliseconds
{
LCDML.SCREEN_resetTimer(); // reset screensaver timer
if (LCDML.TIMER_ms(g_timer_1, 200)) // this method checks every 200 milliseconds if it is called
{
g_timer_1 = millis();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.setCursor(1, 15);
const char laden = '\x82' + g_func_load_info;
u8g2.print("Laden: \xEE\x89");
u8g2.print(laden);
// Rahmen um die ganze Geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1 - _LCDML_DISP_box_x0), (_LCDML_DISP_box_y1 - _LCDML_DISP_box_y0));
u8g2.sendBuffer();
if (laden <= 0x8B)
{
g_func_load_info++;
} else {
g_func_load_info = 0;
}
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
Was meinst Du, ist das eleganter?
Auf jeden fall...
Die Animation ist schick ![]()
Wie bekomm ich das jetzt in den Screensaver ohne die darin befindliche Uhr oder andere Icons zu beeinflussen?
Die Icons sind aktuell nur zum "Pixelschubsen" alle aktiv...
Jedes einzelne soll halt nur dann angezeigt werden, wenn das dahinter befindliche Gerät auch aktiv ist...
Animiert werden sollen stand jetzt "nur" 2 davon...
Das ganze soll halt in den Screensaver, weil das wohl der am meisten angezeigte Displayinhalt ist.. ![]()
Indem Du das richtig programmierst ![]()
Verstehst Du, was ich Dir durch die Blume mitteilen möchte?
Ja klar... Lerne, verstehe & bau den scheiss selber... ![]()
![]()
Lerne: sehr gern, täglich, stündlich
Verstehe: daran scheitert es meistens
Bau selber: auch sehr gern...
Nee, Du bist zu minimalistisch, zeige mir void mFunc_screensaver, dann kann ich da was dran machen!
Inzwischen hab Ichs hinbekommen, das die Ladeanzeige an entsprechender Stelle ist und auch "lädt"...
Allerdings Blinkt das Teil im 200ms Takt... Das bekomm ich aktuell noch nicht weg...
die screensaver Geschichte...
// *********************************************************************
void mFunc_screensaver(uint8_t param)
// *********************************************************************
{
static uint8_t g_func_load_info = 1; // counter (global variable)
static unsigned long g_timer_1 = 0; // timer variable (global variable)
if(LCDML.FUNC_setup()) // ****** SETUP *********
{
// remmove compiler warnings when the param variable is not used:
LCDML_UNUSED(param);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.drawUTF8( 11, 60, "\xEE\x89\x82"); // Leeren Akku im Setup laden? Aber nur wenn PIN auch aktiv!
u8g2.sendBuffer();
// setup function
#ifdef _LCDML_DISP_font_clock
u8g2.setFont(_LCDML_DISP_font_clock);
#endif
#ifndef _LCDML_DISP_font_clock
u8g2.setFont(_LCDML_DISP_font);
#endif
#ifdef _LCDML_DISP_font_clock2
u8g2.setFont(_LCDML_DISP_font_clock);
#endif
#ifndef _LCDML_DISP_font_clock2
u8g2.setFont(_LCDML_DISP_font);
#endif
LCDML.TIMER_msReset(g_timer_1);
LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds
}
if(LCDML.FUNC_loop()) // ****** LOOP *********
{
LCDML.SCREEN_resetTimer(); // reset screensaver timer
if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right)
{
LCDML.FUNC_goBackToMenu(); // leave this function
}
uint8_t stunden = rtc.getHour(true); //5;
uint8_t minuten = rtc.getMinute(); //8;
uint8_t sekunden = rtc.getSecond(); //millis() / 1000 % 60;
// rtc.getTime(); // (String) 15:24:38
// rtc.getDate(); // (String) Sun, Jan 17 2021
// rtc.getDate(true)); // (String) Sunday, January 17 2021
// rtc.getDateTime()); // (String) Sun, Jan 17 2021 15:24:38
// rtc.getDateTime(true)); // (String) Sunday, January 17 2021 15:24:38
// rtc.getTimeDate()); // (String) 15:24:38 Sun, Jan 17 2021
// rtc.getTimeDate(true)); // (String) 15:24:38 Sunday, January 17 2021
//
// rtc.getMicros(); // (long) 723546
// rtc.getMillis(); // (long) 723
// rtc.getEpoch(); // (long) 1609459200
// rtc.getSecond(); // (int) 38 (0-59)
// rtc.getMinute(); // (int) 24 (0-59)
// rtc.getHour(); // (int) 3 (0-12)
// rtc.getHour(true); // (int) 15 (0-23)
// rtc.getAmPm(); // (String) pm
// rtc.getAmPm(true); // (String) PM
// rtc.getDay(); // (int) 17 (1-31)
// rtc.getDayofWeek(); // (int) 0 (0-6)
// rtc.getDayofYear(); // (int) 16 (0-365)
// rtc.getMonth(); // (int) 0 (0-11)
// rtc.getYear(); // (int) 2022
//u8g2.firstPage();
//do {
u8g2.clearBuffer();
u8g2.setCursor(1, 35);
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.printf( "%2u:%02u", stunden, minuten );
u8g2.setFont(u8g2_font_logisoso16_tn);
u8g2.printf( ":%02u", sekunden );
//Wlan Daten
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.enableUTF8Print();
// 0=
// 1= no ssid available
// 2= scan network completed
// 3= connected
// 4= connection failed
// 5= connection lost
// 6= disconnected from Network
if(WiFi.status() == 3);
{
u8g2.setCursor(91, 10);
if(WiFi.SSID() == "FBI_Survillance_Van#4") // Heim WLAN
{
u8g2.printf("\xEE\x84\x8E"); // Symbol: Haus
}
if(WiFi.SSID() == "") // mein iPhone Hotspot muss noch gesetzt werden...
{
u8g2.printf("\xEE\x86\x87"); // Symbol: 1
}
u8g2.setCursor(102, 10);
if(digitalRead(5) == HIGH) // Selbsthaltung aktiv?
{
u8g2.printf("\xEE\x84\x8D"); // Power Symbol
}
u8g2.setCursor(114, 10);
//-30 dBm am besten
//-50 dBm Ausgezeichnet
//-65 dBm Sehr gut
//-70 dBm akzeptabel
//-80 dBm schlecht
//-90 dBm sehr schlecht
//-100 dBm am schlechtesten
if((WiFi.RSSI()*(-1)) <= 50) // am besten (mit positiven werten lässt sich besser rechnen daher *(-1)
{
u8g2.printf("\xEE\x89\xA1");
}
if(((WiFi.RSSI()*(-1)) > 50) && ((WiFi.RSSI()*(-1)) <= 65)) // Ausgezeichnet
{
u8g2.printf("\xEE\x89\xA0");
}
if(((WiFi.RSSI()*(-1)) > 65) && ((WiFi.RSSI()*(-1)) <= 70)) // Sehr gut
{
u8g2.printf("\xEE\x89\x9F");
}
if(((WiFi.RSSI()*(-1)) > 70) && ((WiFi.RSSI()*(-1)) <= 80)) // akzeptabel
{
u8g2.printf("\xEE\x89\x9E");
}
if(((WiFi.RSSI()*(-1)) > 80) && ((WiFi.RSSI()*(-1)) <= 90)) // schlecht
{
u8g2.printf("\xEE\x89\x9D");
}
if(((WiFi.RSSI()*(-1)) > 90) && ((WiFi.RSSI()*(-1)) <= 100)) // sehr schlecht
{
u8g2.printf("\xEE\x88\x9B");
}
if(((WiFi.RSSI()*(-1)) > 100)) // absolut beschissen
{
u8g2.printf("\xEE\x88\x97");
}
}
//u8g2.setFont(_LCDML_DISP_font);
// Infoboxen...
// Draw Infobox lines
u8g2.drawLine(2,37, 125, 37); // Horizontal oben
u8g2.drawLine(2,50, 125, 50); // Horizontal mitte
u8g2.drawLine(64,39, 64, 61); // vertikal mittig
//if(display == aktiv) // abfrage später bauen
// {
u8g2.setCursor(1, 48);
u8g2.printf("\xEE\x85\x8A"); // Display
// }
//if(Armlehne == aktiv)
// {
u8g2.setCursor(10, 48);
u8g2.printf("\xEE\x80\x8C"); // USB Symbol
// }
//if(inverter == aktiv)
// {
u8g2.setCursor(20, 48);
u8g2.printf("\xEE\x81\x81"); // Steckersymbol
// }
//if(ladeports == aktiv)
// {
u8g2.setCursor(29, 48);
u8g2.printf("\xEE\x80\x8C"); // USB Symbol
// }
//if(wireless Video == aktiv)
// {
u8g2.setCursor(40, 48);
u8g2.printf("\xEE\x87\xB5"); // Kamera Symbol
// }
//if(blinkerueberwachung == aktiv)
// {
// Array für Blinkerüberwachung
String blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
//Array für Dauerplus
for (int a=0; a<=1; a++)
{
u8g2.setCursor(52, 48);
u8g2.print(blinkerueb[a]); // Animierter Blinker
}
// }
//if(dauerplus == aktiv)
// {
u8g2.setCursor(1, 60);
u8g2.printf("\xEE\x88\x95"); // Blitz Symbol
// }
if (LCDML.TIMER_ms(g_timer_1, 200)) // this method checks every 200 milliseconds if it is called
{
g_timer_1 = millis();
//u8g2.clearBuffer();
//u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.setCursor(11, 60);
const char laden = '\x82' + g_func_load_info;
u8g2.print("\xEE\x89");
u8g2.print(laden);
// u8g2.sendBuffer();
if (laden <= 0x8A)
{
g_func_load_info++;
}
else
{
g_func_load_info = 0;
}
}
u8g2.setCursor(66, 48);
//u8g2.printf("Infobox 2");
u8g2.printf("\xEE\x83\x92""\xEE\x81\xA2"); // Symbole testen
u8g2.setCursor(66, 60);
//u8g2.printf("Infobox 3");
u8g2.printf("Out""\xEE\x83\x8F"":23.7"); //temperaturanzeige über 1Wire DS18B20 im 5s wechsel: in, out
// Rahmen um die ganze geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1-_LCDML_DISP_box_x0), (_LCDML_DISP_box_y1-_LCDML_DISP_box_y0));
//} while( u8g2.nextPage() );
u8g2.sendBuffer();
}
if(LCDML.FUNC_close()) // ****** STABLE END *********
{
// The screensaver go to the root menu
LCDML.MENU_goRoot();
}
}
Mit der Zeitschleife solltest Du nur die Variable hochzählen. Die Anzeige dann zusammen mit den anderen Anzeigen. Ich hatte schon mit meinem Bildschirmschoner angefangen:
// *********************************************************************
void mFunc_screensaver(uint8_t param)
// *********************************************************************
{
static uint8_t g_func_load_info = 0; // counter
static unsigned long g_timer_1 = 0; // timer variable
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// remmove compiler warnings when the param variable is not used:
LCDML_UNUSED(param);
LCDML.TIMER_msReset(g_timer_1);
LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right)
{
LCDML.FUNC_goBackToMenu(); // leave this function
}
uint8_t stunden = 5;
uint8_t minuten = 8;
uint8_t sekunden = millis() / 1000 % 60;
const char laden = '\x82' + g_func_load_info;
u8g2.clearBuffer();
u8g2.setCursor(1, 35);
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.printf( "%2u:%02u:", stunden, minuten );
u8g2.setFont(u8g2_font_logisoso16_tn);
u8g2.printf( "%02u", sekunden );
u8g2.setFont(u8g2_font_siji_t_6x10);
u8g2.setCursor(2, 60);
u8g2.print("Laden: \xEE\x89");
u8g2.print(laden);
// Rahmen um die ganze Geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1 - _LCDML_DISP_box_x0), (_LCDML_DISP_box_y1 - _LCDML_DISP_box_y0));
u8g2.sendBuffer();
if (LCDML.TIMER_ms(g_timer_1, 200)) // this method checks every 200 milliseconds if it is called
{
g_timer_1 = millis();
if (laden <= 0x8B)
{
g_func_load_info++;
} else {
g_func_load_info = 0;
}
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// The screensaver go to the root menu
LCDML.MENU_goRoot();
}
}
Dein Bildschirmschoner:
// *********************************************************************
void mFunc_screensaver(uint8_t param)
// *********************************************************************
{
static uint8_t g_func_load_info = 0; // counter
static unsigned long g_timer_load = 0; // timer variable Ladezustand
static unsigned long g_timer_temp = 0; // timer variable Temperatur In/Out
static bool inout = false; // Merker Innen- oder Außentemperatur
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// remmove compiler warnings when the param variable is not used:
LCDML_UNUSED(param);
const char * NTP_SERVER = "fritz.box";
//const char * NTP_SERVER = "de.pool.ntp.org";
const char * TZ_INFO = "WEST-1DWEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"; // Western European Time
setenv("TZ", TZ_INFO, 1);
tzset();
configTzTime(TZ_INFO, NTP_SERVER); // ESP32 Systemzeit mit NTP Synchronisieren
u8g2.clearBuffer();
// Draw Infobox lines
u8g2.drawLine(2, 37, 125, 37); // Horizontal oben
u8g2.drawLine(2, 50, 125, 50); // Horizontal mitte
u8g2.drawLine(64, 39, 64, 61); // vertikal mittig
// Rahmen um die ganze geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1 - _LCDML_DISP_box_x0), (_LCDML_DISP_box_y1 - _LCDML_DISP_box_y0));
u8g2.sendBuffer();
// setup function
#ifdef _LCDML_DISP_font_clock
u8g2.setFont(_LCDML_DISP_font_clock);
#endif
#ifndef _LCDML_DISP_font_clock
u8g2.setFont(_LCDML_DISP_font);
#endif
#ifdef _LCDML_DISP_font_clock2
u8g2.setFont(_LCDML_DISP_font_clock);
#endif
#ifndef _LCDML_DISP_font_clock2
u8g2.setFont(_LCDML_DISP_font);
#endif
LCDML.TIMER_msReset(g_timer_load);
LCDML.TIMER_msReset(g_timer_temp);
LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
LCDML.SCREEN_resetTimer(); // reset screensaver timer
if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right)
{
LCDML.FUNC_goBackToMenu(); // leave this function
}
uint8_t stunden = rtc.getHour(true);
uint8_t minuten = rtc.getMinute();
uint8_t sekunden = rtc.getSecond();
// rtc.getTime(); // (String) 15:24:38
// rtc.getDate(); // (String) Sun, Jan 17 2021
// rtc.getDate(true)); // (String) Sunday, January 17 2021
// rtc.getDateTime()); // (String) Sun, Jan 17 2021 15:24:38
// rtc.getDateTime(true)); // (String) Sunday, January 17 2021 15:24:38
// rtc.getTimeDate()); // (String) 15:24:38 Sun, Jan 17 2021
// rtc.getTimeDate(true)); // (String) 15:24:38 Sunday, January 17 2021
//
// rtc.getMicros(); // (long) 723546
// rtc.getMillis(); // (long) 723
// rtc.getEpoch(); // (long) 1609459200
// rtc.getSecond(); // (int) 38 (0-59)
// rtc.getMinute(); // (int) 24 (0-59)
// rtc.getHour(); // (int) 3 (0-12)
// rtc.getHour(true); // (int) 15 (0-23)
// rtc.getAmPm(); // (String) pm
// rtc.getAmPm(true); // (String) PM
// rtc.getDay(); // (int) 17 (1-31)
// rtc.getDayofWeek(); // (int) 0 (0-6)
// rtc.getDayofYear(); // (int) 16 (0-365)
// rtc.getMonth(); // (int) 0 (0-11)
// rtc.getYear(); // (int) 2022
u8g2.clearBuffer();
u8g2.setCursor(1, 35);
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.printf( "%2u:%02u", stunden, minuten );
u8g2.setFont(u8g2_font_logisoso16_tn);
u8g2.printf( ":%02u", sekunden );
//Wlan Daten
u8g2.setFont(u8g2_font_siji_t_6x10);
// 0=
// 1= no ssid available
// 2= scan network completed
// 3= connected
// 4= connection failed
// 5= connection lost
// 6= disconnected from Network
if (WiFi.status() == 3);
{
u8g2.setCursor(91, 10);
if (WiFi.SSID() == "FBI_Survillance_Van#4") // Heim WLAN
{
u8g2.printf("\xEE\x84\x8E"); // Symbol: Haus
}
if (WiFi.SSID() == "") // mein iPhone Hotspot muss noch gesetzt werden...
{
u8g2.printf("\xEE\x86\x87"); // Symbol: 1
}
u8g2.setCursor(102, 10);
if (digitalRead(5) == HIGH) // Selbsthaltung aktiv?
{
u8g2.printf("\xEE\x84\x8D"); // Power Symbol
}
u8g2.setCursor(114, 10);
//-30 dBm am besten
//-50 dBm Ausgezeichnet
//-65 dBm Sehr gut
//-70 dBm akzeptabel
//-80 dBm schlecht
//-90 dBm sehr schlecht
//-100 dBm am schlechtesten
if ((WiFi.RSSI() * (-1)) <= 50) // am besten (mit positiven werten lässt sich besser rechnen daher *(-1)
{
u8g2.printf("\xEE\x89\xA1");
}
if (((WiFi.RSSI() * (-1)) > 50) && ((WiFi.RSSI() * (-1)) <= 65)) // Ausgezeichnet
{
u8g2.printf("\xEE\x89\xA0");
}
if (((WiFi.RSSI() * (-1)) > 65) && ((WiFi.RSSI() * (-1)) <= 70)) // Sehr gut
{
u8g2.printf("\xEE\x89\x9F");
}
if (((WiFi.RSSI() * (-1)) > 70) && ((WiFi.RSSI() * (-1)) <= 80)) // akzeptabel
{
u8g2.printf("\xEE\x89\x9E");
}
if (((WiFi.RSSI() * (-1)) > 80) && ((WiFi.RSSI() * (-1)) <= 90)) // schlecht
{
u8g2.printf("\xEE\x89\x9D");
}
if (((WiFi.RSSI() * (-1)) > 90) && ((WiFi.RSSI() * (-1)) <= 100)) // sehr schlecht
{
u8g2.printf("\xEE\x88\x9B");
}
if (((WiFi.RSSI() * (-1)) > 100)) // absolut beschissen
{
u8g2.printf("\xEE\x88\x97");
}
}
//u8g2.setFont(_LCDML_DISP_font);
// Infoboxen...
// Draw Infobox lines
u8g2.drawLine(2, 37, 125, 37); // Horizontal oben
u8g2.drawLine(2, 50, 125, 50); // Horizontal mitte
u8g2.drawLine(64, 39, 64, 61); // vertikal mittig
//if(display == aktiv) // abfrage später bauen
// {
u8g2.setCursor(1, 48);
u8g2.printf("\xEE\x85\x8A"); // Display
// }
//if(Armlehne == aktiv)
// {
u8g2.setCursor(10, 48);
u8g2.printf("\xEE\x80\x8C"); // USB Symbol
// }
//if(inverter == aktiv)
// {
u8g2.setCursor(20, 48);
u8g2.printf("\xEE\x81\x81"); // Steckersymbol
// }
//if(ladeports == aktiv)
// {
u8g2.setCursor(29, 48);
u8g2.printf("\xEE\x80\x8C"); // USB Symbol
// }
//if(wireless Video == aktiv)
// {
u8g2.setCursor(40, 48);
u8g2.printf("\xEE\x87\xB5"); // Kamera Symbol
// }
//if(blinkerueberwachung == aktiv)
// {
// Array für Blinkerüberwachung
String blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
//Array für Dauerplus
for (int a = 0; a <= 1; a++)
{
u8g2.setCursor(52, 48);
u8g2.print(blinkerueb[a]); // Animierter Blinker
}
// }
//if(dauerplus == aktiv)
// {
u8g2.setCursor(1, 60);
u8g2.printf("\xEE\x88\x95"); // Blitz Symbol
// }
u8g2.setCursor(11, 60);
const char laden = '\x82' + g_func_load_info;
u8g2.print("\xEE\x89");
u8g2.print(laden);
u8g2.setCursor(66, 48);
//u8g2.printf("Infobox 2");
u8g2.printf("\xEE\x83\x92""\xEE\x81\xA2"); // Symbole testen
u8g2.setCursor(66, 60);
//u8g2.printf("Infobox 3");
if (inout)
{
int temp = 217;
u8g2.printf("In \xEE\x83\x8F:%4.1f", temp / 10.0); //temperaturanzeige über 1Wire DS18B20 im 5s wechsel: in, out
} else {
int temp = 335;
u8g2.printf("Out\xEE\x83\x8F:%4.1f", temp / 10.0); //temperaturanzeige über 1Wire DS18B20 im 5s wechsel: in, out
}
if (LCDML.TIMER_ms(g_timer_temp, 5000))
{
g_timer_temp = millis();
inout = !inout;
}
// Rahmen um die ganze geschichte...
u8g2.drawFrame(_LCDML_DISP_box_x0, _LCDML_DISP_box_y0, (_LCDML_DISP_box_x1 - _LCDML_DISP_box_x0), (_LCDML_DISP_box_y1 - _LCDML_DISP_box_y0));
u8g2.sendBuffer();
if (LCDML.TIMER_ms(g_timer_load, 200)) // this method checks every 200 milliseconds if it is called
{
g_timer_load = millis();
if (laden <= 0x8A)
{
g_func_load_info++;
} else {
g_func_load_info = 0;
}
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// The screensaver go to the root menu
LCDML.MENU_goRoot();
}
}
EDIT: Jetzt auch mit fünfsekündiger Umschaltung der Innen- und Außentemperatur. Daher auch spezifische Namen für die Zeiten.
Ach... Die Arbeit kann einem den ganzen Tag versauen... Verdammte Spätschicht...
Dein ernst? und dann noch nicht mal das zweite Icon animiert? Jetzt bin ich aber schwer enttäuscht...
![]()
![]()
![]()
![]()
Nein, Spaß beiseite... Vielen Dank..
```
const char * NTP_SERVER = "fritz.box";
//const char * NTP_SERVER = "de.pool.ntp.org";
const char * TZ_INFO = "WEST-1DWEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"; // Western European Time
setenv("TZ", TZ_INFO, 1);
tzset();
configTzTime(TZ_INFO, NTP_SERVER); // ESP32 Systemzeit mit NTP Synchronisieren
```
DAS wird wohl NUR in nem Heimischen WLAN funktionieren wo auch ne FritzBox werkelt... Für Einsatz im Auto mit wechselnden WLANs evtl bisl ungünstig...
Ich hab den entsprechenden RTC Code bereits im sketch Setup definiert...
Der holt sich also direkt beim einschalten die Uhrzeit ausm Netz.. ![]()
// *********************************************************************
// SETUP
// *********************************************************************
void setup()
{
#ifdef RTC_USAGE
#ifndef RTC_NTP
rtc.setTime(30, 24, 0, 6, 6, 2022); // Manuell stellen wenn RTC_NTP nicht gesetzt
#endif
#ifdef RTC_NTP
const char* ntpServer = "pool.ntp.org";
const long rtcOffset_sec = 3600;
const int daylightOffset_sec = 3600;
configTime(rtcOffset_sec, daylightOffset_sec, ntpServer);
struct tm timeinfo;
if (getLocalTime(&timeinfo))
{
rtc.setTimeStruct(timeinfo);
}
#endif
#endif
[...]
Aber schon keine schlechte Idee die Zeit beim Aufruf des Screensavers zu syncen...
aber ist das wirklich nötig?
Bzw sollte das nur ausgeführt werden wenn auch tatsächlich ne WLAN Verbindung besteht die NICHT durch das herstellen eines eigenen Hotspots (aus Sicht des ESP32) entstanden ist..
Ich hab mir gerade mal Deine Timer Funktion für die Ladeanzeige genauer angesehen...
if (LCDML.TIMER_ms(g_timer_load, 200)) // this method checks every 200 milliseconds if it is called
{
g_timer_load = millis();
if (laden <= 0x8A)
{
g_func_load_info++;
}
else
{
g_func_load_info = 0;
}
}
und mit den Wert von g_func_load_info mal auf den Display gezaubert...
Der zählt sauber von 0-9 durch und startet dann wieder von vorn...
Wenn ich jetzt nich n Knoten im Kopp habe, könnte man diese Var doch auch verwenden um einzelne Einträge eines Arrays abzufragen
u8g2.print(array[g_func_load_info]);
oder seh ich das falsch??
Was ich meine: Bei der Ladeanzeige sind die einzelnen Icons ja nur 1 von einander entfernt & fortlaufend...
Bei der zweiten Animation die ich gern hätte ist das eben nicht der Fall... Da liegen die Icons etwas weiter auseinander... (\xEE\x83\x92 & \xEE\x81\xA2)
Und das
if (laden <= 0x8A)
könnte man dann doch einfach mit
if (laden <= sizeof(array))
ersetzen...
Und schon hätte man nen Universelleren code mit frei definierbaren nicht zwingend aufeinanderfolgenden Icons...
und durch anpassen von
if (LCDML.TIMER_ms(g_timer_load, 200))
Kann jedes Icon in einer eigenen Geschwindigkeit animiert werden...
Oder seh ich das verkehrt??
Hmm... Jain...
Ein test ergab das sizeof(array) nicht die Anzahl an "Schubladen" sondern die Anzahl an Socken in jeder Schublade ausgibt...
für
String blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
u8g2.setCursor(110,48);
u8g2.print(sizeof(blinkerueb));
ist die Ausgabe: 24
Um jetzt statt auf 24 nur auf 1 zu kommen, also etwas kosmetisch vorgehen...
Warum auf 1?
Ein array Aufruf startet immer mit 0, wir wissen: im Array sind 2 Symbole abgelegt. Wenn wir also die Anzahl an Schubladen haben wollen müssen wir die 0 mitrechnen... bei 2 Schubladen also 0 & 1..
Wir wissen ebenfalls: ein Icon wird im aktuellen fall mit exakt 12 Zeichen definiert.
Somit ergäbe
String blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
u8g2.setCursor(100,48);
u8g2.print( (sizeof(blinkerueb)/12) );
2... Richtig? Richtig...
Gegenprobe mit
String ladeltg[] = {"\xEE\x89\x82", "\xEE\x89\x83", "\xEE\x89\x84", "\xEE\x89\x85", "\xEE\x89\x86", "\xEE\x89\x87", "\xEE\x89\x88", "\xEE\x89\x89", "\xEE\x89\x8A", "\xEE\x89\x8B"};
u8g2.setCursor(113,48);
u8g2.print( (sizeof(ladeltg)/12) );
Ergebnis: 10 Passt also..
Dennoch immer noch einer zuviel also weitere Kosmetische Behandlung..
String blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
u8g2.setCursor(100,48);
u8g2.print( (sizeof(blinkerueb)/12)-1 );
String ladeltg[] = {"\xEE\x89\x82", "\xEE\x89\x83", "\xEE\x89\x84", "\xEE\x89\x85", "\xEE\x89\x86", "\xEE\x89\x87", "\xEE\x89\x88", "\xEE\x89\x89", "\xEE\x89\x8A", "\xEE\x89\x8B"};
u8g2.setCursor(113,48);
u8g2.print( (sizeof(ladeltg)/12)-1 );
Ergebnis (mit Gegenprobe)
Erwartet: 1 & 9
geliefert: 1 & 9 SUCCESS!!!
Damit können wir dann doch schon weiter dengeln und die Codezeile des Timers auf
if (laden <= (sizeof(array)/12)-1)
anpassen & somit jedes einzelne Icon korrekt abrufen ohne in einen anderen Speicherbereich ausserhalb des Arrays zuzugreifen... ![]()
Sorry für den Spam... Das "mal eben" auszuformulieren hat beim Verständnis geholfen.. ![]()
Aktuell wird jetzt das Thema "multiple WLAN Zugangspunkte" akut...
Ich fahr gleich zu nem Lehrgang & will den ganzen kram mitnehmen um da im Hotel weiter dran zu schrauben... Da hab ich natürlich mein Heimisches WLAN nicht "dabei"... Nur mein Telefon & ggf das WLAN des Hotels...
Wie geh ich da am besten vor?
Ziel ist ja das abarbeiten einer WLAN "Liste"... Wenn Eintrag 1 nicht erreichbar Versuchs mit Eintrag 2, wenn 2 nicht erreichbar, Versuchs mit Eintrag 3, usw.. Wenn keins der WLANs aus der liste erreichbar ist, dann schau mal in der Gegend rum ob ein freies WLAN zur verfügung steht, wenn ja log dich kurz ein, hol die Uhrzeit & log dich wieder aus. Und: bau dein eigenes WLAN auf, aber NUR wenns durch das LCDML Menü auch eingeschaltet... (Fallback Hotspot zum laden über OTA ggf im "freien Feld")
Die sperrt mich nicht, wenn ich zu häufig die Zeit abfrage, zum Testen daher ideal. Wenn Dein Auto nahe genug an Deinem Router parkt, durchaus eine Synchronisationsmöglichkeit.
Ohne DS3231 brauche ich beim Einschalten eine Zeit, mit nur gelegentlich. Bei mir hier an der Wand habe ich eine Abweichung von wenigen Sekunden pro Jahr, im Auto könnte es etwas mehr sein.
Versuche mal (ungetestet)
const char * blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
const anzahlZeichen = sizeof(blinkerueb) / sizeof(blinkerueb[0])
Dafür ist dieses Forum ja da!
Gibts eigentlich sowas wie nen MicroControler Emulator um geschriebene Sketches ohne die nötige Hardware mal "laufen zu lassen"?
Ja, z. B. WOKWI, Link aus einem anderen Thema:
Hast Du DS3231 mit auf der Reise?
Jetzt auch getestet:
static uint8_t blinkerueb_pos = 0;
...
// Array für Blinkerüberwachung
const char * blinkerueb[] = {"\xEE\x83\x92", "\xEE\x81\xA2"};
const uint8_t blinkerueb_anzahl = sizeof(blinkerueb) / sizeof(blinkerueb[0]);
u8g2.setCursor(52, 48);
u8g2.print(blinkerueb[blinkerueb_pos]); // Animierter Blinker
if (blinkerueb_pos < blinkerueb_anzahl)
{
blinkerueb_pos++;
} else {
blinkerueb_pos = 0;
}
Neeee.... Den muss ich mir erst noch besorgen... Deswegen benutze ich ja gerade die interne RTC des ESP32... Nachteil ist halt das er erstmal WLAN braucht um die Uhr zu stellen...
Ich such aber gerade einen raus & bestell das Teil...
Hab den hier gefunden, taugt das was?
Bastel gerade an der MultiWiFi Geschichte... (im Zug
)
Das hat gerade höhere Prio, da halt nich mehr zu Hause ![]()
Komm da aber aktuell auch nich weiter...
// include libs
#include <LCDMenuLib2.h>
//OTA Required
#include <WiFi.h>
#include <WiFiMulti.h> // <--- frisch hinzugefügt
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "WiFi_access.h" // <--- "externe" Datei erstellt in der die WLAN Zugangspunkte drin stehen
die WiFi_access.h
wifiMulti.addAP("FBI_Survilancevan#4", "supergeheimespasswort"); // zu Hause
wifiMulti.addAP("Mein iPhone", "auchnsupergeheimespasswort"); // mein iPhone
//EOF
Objekt angelegt
// *********************************************************************
// Objects
// *********************************************************************
LCDMenuLib2_menu LCDML_0 (255, 0, 0, NULL, NULL); // root menu element (do not change)
LCDMenuLib2 LCDML(LCDML_0, _LCDML_DISP_rows, _LCDML_DISP_cols, lcdml_menu_display, lcdml_menu_clear, lcdml_menu_control);
WiFiMulti wifiMulti;
Irgendwas scheint noch zu fehlen...
Compiler meckert:
und zeigt dabei auf die unterste Zeile der WiFi_access.h
Ich vermute mal das ich beim „auslagern“ der WLAN Zugangsdaten was falsch gemacht hab…
Sieht bei mir genauso aus.
Du mußt Dich zwischen Akku LIR2032 und Batterie CR2032 entscheiden.
Gehört ins setup().
#include <WiFiMulti.h> // <--- frisch hinzugefügt
WiFiMulti wifiMulti;
...
WiFi.mode(WIFI_STA);
wifiMulti.addAP(router_ssid, router_password); // zu Hause
wifiMulti.addAP("Mein iPhone", "auchnsupergeheimespasswort"); // mein iPhone
Serial.println("Connecting Wifi...");
if (wifiMulti.run() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
Hier abgeschaut: ESP32 WiFiMulti: Connect to the Strongest Wi-Fi Network (from a list of networks)
OK, dann bestell ich den mal..
Ja klar...
Ich bin soo ![]()
![]()
....
im Setup sollte dann auch die #include WiFi_access.h funktionieren...
So hab das Setup mal hier im Hotel aufgebaut & festgestellt das der kleine Sch**ßer ohne ne WLAN Verbindung gar nicht erst bootet sondern in ner Resetschleife festhängt... Das Geht im Auto ja gar nicht... Das muss laufen, egal ob WLAN da ist oder nicht...
Von daher muss der Codeschnipsel
while (WiFi.waitForConnectResult() != WL_CONNECTED)
{
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
schonmal raus...
An der Stelle würd ich dann tatsächlich die Abfrage reinschmeißen ob er einen eigene Hotspot aufbauen darf...
Clevererweise über nen bit aus dem EEPROM...
Da war aber wieder auch was spezielles bei ESPs mit EEPROM..
Wie macht man das da?
ESP haben keinen EEPROM (höchstens eine Emulation).
Beim ESP32 könntest Du Preferences benutzen.
Gruß Tommy