ESP32-CYD (Cheap Yellow Display) Projekt mit LVGL: 433 MHz On/Off-Timer Funk-Steckdosen-Steuerung
Es war einmal eine alte Mikrowelle...
Irgendwann Mitte oder Ende der Achtziger habe ich mir als junger Erwachsener einen Mikrowellenherd gekauft. Es war ein günstiges NoName-Gerät aus dem Supermarkt. Gar nicht mal teuer, 50 bis 60 Mark oder so.Jetzt kommt der Hammer: Obwohl das Gerät jetzt rund 40 Jahre alt ist: es funktioniert immer noch. Es macht klaglos immer noch Speisen und Getränke warm. Okay, die Lampe im Innern leuchtet nicht mehr, aber wer braucht die schon? Schlimmer ist da schon, dass der Drehregler zum Einstellen der Zeit mittlerweile ein wenig ausgeleiert ist und Spiel hat: Es lässt sich die Laufdauer nicht mehr genau einstellen.
Nun bin ich ein großer Fan von Latte Macchiato und muss dafür die Milch ca. 1 ½ Minuten in der Mikrowelle aufwärmen, um damit einen Latte zu zaubern. Eigentlich so ziemlich genau 86 Sekunden bei der Menge, die gebrauche und der Temperatur, wie sie aus dem Kühlschrank kommt und bei der Leistung meiner Mikrowelle.
Und schon komme ich auf das Problem zu sprechen, für das ich eine Lösung suche: Ich kann mit dem ausgeleierten Drehregler an der ollen Mikrowelle keine 1 ½ Minuten einstellen, geschweige denn genau 86 Sekunden.
Eine Zicke namens Alexa
Als erste "Lösung" hatte ich meine Amazon Alexa mit einer Routine hergenommen, um die Mikrowelle für 86 Sekunden einzuschalten. Eigentlich heißt der entsprechende Zauberspruch für Alexa "Schalte die Mikrowelle für 86 Sekunden ein", wobei "Mikrowelle" der Name des entsprechenden WLAN-Steckdose ist. Der Spruch war mir allerdings zu lang, um ihn immer wieder aufzusagen.Darum habe ich eine Routine namens "Mach Milch warm" erstellt, die das tun sollte. Der habe ich am Ende auch gesagt, dass sie das Abschalt-Kommando 3x mit ein paar Sekunden Abstand an die WLAN-Steckdose senden soll. Weil ich hatte das Problem, dass scheinbar der Funkverkehr zur Steckdose hin und wieder mal gestört war. Mit dem Ergebnis, dass ich eingebrannte, übergekochte Milch hatte und den eingekochten Schnodder dann lange einweichen musste, um ihn wieder vom Glasteller der Mikrowelle zu bekommen. Irgendwie kam das dann immer noch trotz 3x aus senden vor - sehr selten, aber trotzdem. Und trotz WLAN-Repeater im Flur. Seltener, aber die Gefahr war immer noch latent.
Und außerdem stellte sich Alexa extrem dämlich an, mich zu verstehen. Statt mir eine in die Mikrowelle gestellte Milch warm zu machen, antworte sie viel lieber mich dem Spruch "Ich glaube nicht, dass Menschen eine Taste zum Anmachen haben.". Sie wollte wohl viel lieber "Mach mich an" statt "Mach Milch warm" verstehen. Die Umbenennung der Routine in "Mach Latte" brachte auch nichts. Das verstand Sie viel viel zu oft als "Spiele mir Musik von Lotte" und legte auch gleich los, Musik von Deezer zu streamen. Ergo: Alexa von amazon ist eine Voll-Katastrophe und kann einen mit ihrem dummen Getue und Generve fast genau so schnell ins Irrenhaus bringen, wie den Passierschein A38 zu erhalten (Asterix-Fans erinnern sich).
Jetzt werden Einige von euch bestimmt denken: "Na, dann kauf dir halt eine neue Mikrowelle". Tja, da habe ich auch schon dran gedacht. Und da habe ich eigentlich nur einen einzigen Hersteller für Mikrowellen mit NumPad auf amazon gefunden: Hisense. Baugleiche oder bauähnliche Modelle gibt es wohl noch von Chefman. Und das Modell von Cecotec sieht auch aus, ob da die gleiche Technik drinsteckt, halt plus einen Grill.
Harvard und andere Business Schools
Leider sind die Produktbeschreibung auf amazon (wie halt überall) inzwischen nicht darauf ausgelegt, den Verbraucher genau zu informieren, was er da kauft oder damit er überprüfen kann, ob seine Wünsche und Bedürfnisse dem Produkt entsprechen. Sondern vielmehr ist es eine Aneinanderreihung von Buzzwords, die wichtig klingen und nichts genaues aussagen, sich aber "toll" anhören. Und natürlich Produkt-(Symbol)-Fotos, die unsere niederen Instinkte auf Gefühlsebene ansprechen: etwa ein Bild von einem so lecker aussehenden, knusprigen Braten, dass man gleich Appetit bekommt und sich fragt: "Wow. Das sieht so lecker aus. Meine alte Mikrowelle hat das nie so hinbekommen". Dabei ist das nur ein Symbolfoto mit Sternchen, wo das Fleisch gar nicht aus der Mikrowelle kommt. Denn da krieg man keine Knusprigkeit hin, wenn man nicht einen Zusatzgrill hat. Das steht auch ganz klein irgendwo im Kleingedruckten aus rechtlichen Gründen. Das liest natürlich niemand.Außerdem werden nur die Vorteile des Produktes aufgezählt. Die Vorteile und Pseudo-Vorteile sind dermaßen viele, dass man gar nicht mitbekommt, wenn etwas fehlt, was man eigentlich unbedingt braucht. Zuviel Pseudo-Informationen sind zu durchforsten, um das herauszukriegen. Zwischendurch wurde man beschossen mit leckeren (nichts sagenden) Fotos und (wenig aussagenden) tollen Werbebotschaften und Buzz-Words - große und genaue Zahlen kommen immer gut.
Irgendwann hat ein Harvard Business School Absolvent herausgefunden, dass man eigentlich kein gutes Produkt braucht und nur die Gefühle und Kauflust der
Aber damit ist das Profitmaximierungspotential natürlich noch nicht ausgeschöpft: Wie wäre es, wenn man die Produkte so designen würde, dass sie kaputt gingen, wenn diese schäbigen Verbraucherschutzgesetze nicht mehr gelten, weil die Gewährleistung ausgelaufen ist? Natürlich nur aus Versehen, der Verbraucher will ja schließlich keine Unsummen für ein Gerät bezahlen, weil da zu qualitative und hochpreisige Teile drin verbaut sind. ;)
Das Codewording für diese tolle Erfindung des Kapitalismus nennt sich "geplante Obsoleszenz" und sichert den stetigen Unternehmensprofit, weil die Kunden ihre Geräte ständig nach ein paar Jahren neu kaufen müssen. Scheiß auf die Umwelt, schmeiß' weg und kauf neu, Hauptsache der Umsatz stimmt!
Vielleicht habt ihr es schon gemerkt: die vorhergehenden Sätzen sind mit ein wenig Ironie gewürzt. Natürlich ist das so alles nicht toll für Verbraucher, Umwelt und die Menschheit generell. Aber es gilt in der heutigen Zeit diese Profitmaximierungsmaxime für Unternehmen, die alles ausnutzt, was gerade noch so legal ist. Da können nur Gesetze gegensteuern und Justitia, die sinnbildliche römische Göttin der Gerechtigkeit und des Rechtswesens, ist langsam und kommt bei der Kreativität der Business Gurus nicht hinterher. Kaum ein Unding per Gesetz eingedämmt, klaffen da schon zwei neue Dinge.
Damals war alles besser (jetzt in Echt!)
Tja, und jetzt endlich schließt sich der Kreis und der Grund, warum ich euch das alles erzähle und warum ich eigentlich gar keine neue Mikrowelle will: da sind dann Komponenten verbaut, die darauf ausgelegt sind, nach ein paar Jahren kaputt zu gehen. Darum hänge ich an meiner alten Mikrowelle: die wurde gebaut, da war geplante Obsoleszenz noch kein Thema. Die wurde so gebaut, dass sie lange hält. Der fette Elektrolytkondensator da drin, das Magnetron, die Ansteuerungs-Elektronik und die Bauteile darin. Das alles funktioniert nach 40 Jahren noch. Und es war nicht einmal teuer. Das waren so 25 bis 30 Euro umgerechnet für die Mikrowelle damals. Okay, heute kostet alles mehr wegen der Inflation, aber Elektronik ist eigentlich immer günstig geblieben.Ich hatte zwischendrin mal eine andere Mikrowelle, übernommen von einem Vormieter. Die konnte mehr, also hab ich die benutzt. Aber nach einem Jahr oder so Benutzungszeit von mir war die kaputt. Meine alte Mikrowelle ist sozusagen unbezahlbar, weil man sowas heute nicht mehr bekommt.
Vielleicht ist es auch dem geschuldet, dass ich mit Sache immer gut umgehe und sie halbwegs pflege, so mein Toaster zum Beispiel: der ist noch älter, den habe ich mal von meiner Oma geerbt. Der hat auch so ein altbackenes Ende der 1970er Muster und Farbe. Aber der funktioniert immer noch. Zwischendurch hatte ich in einem Tombola mal einen neuen Toaster gewonnen, der viel toller aussah - und nach 2 oder 2 ½ Jahren kaputt war. Also Omas alten Rowenta Toaster wieder rausgekramt und nie wieder einen modernen gewollt. Omas alten Toaster benutze ich täglich. Funktioniert seit 50 Jahren oder so. Oma hatte den ja auch schon ein paar Jahre in Gebrauch.
Und meine Waschmaschine funktioniert auch seit den frühen 1990ern. Meine Yamaha Stereoanlage seit den 1980ern. Das alte Gelump geht einfach nicht kaputt, wenn man es ordentlich behandelt. Vor einiger Zeit meinen ollen Commodore VC 20 getestet, auch aus den früher 1980ern: angeschlossen, funktioniert noch.
Lösung für das Problem - bitte zuverlässig und genau
Ergo: Mikrowelle bleibt, solange sie tut. Nur muss ich was tun, damit die zuverlässig und genau funktioniert.Zum Thema zuverlässig habe ich mir überlegt: Nein, keine Alexa mehr, keine WLAN-Steckdose. Zuerst kam mir ein Relais in den Sinn, dass ich über einen Mikrocontroller selbst schalte.
Dazu hätte es nur gebraucht:
- Einen Arduino Uno oder Nano oder vielleicht auch einen STM32 F103, aber der wäre eigentlich schon owerpowered.
- Eine NumPad-Tastatur mit 16 Tasten: 0 bis 9 zur Eingabe der Sekunden Laufzeit und eine Taste zum Starten
- ein Display zur Anzeige der Restlaufzeit. Eine vierstellige 7-Segment Anzeige würde dazu schon genügen. Oder es ginge auch eine 1602 LCD-Anzeige
- Ein Relais-Modul, um über den Arduino die Mikrowelle für die eingegebene Zeit mit Strom zu versorgen
Aber dann fand ich es ein bisschen doof mit so einem dicken Kabel zwischen Arduino und Mikrowelle. Außerdem werkle ich nicht so gerne mit 230 V herum. Das ist eine unnötige Gefahrenquelle.
Also besann ich mich auf mein altes Projekt Mit dem Raspberry Pi 433 MHz-Funksteckdosen schalten. Diese Baumarkt-Funksteckdose funken auf 433 MHz und sind zuverlässiger als WLAN. Ich spare mir das Stromkabel, indem ich die Mikrowelle in die Funksteckdose stecke und die dann die Steckdose ein- und ausschalte.
Und dann siegte irgendwie die Faulheit. Warum ein Display, eine Tastatur und einen Mikrocontroller zusammen löten, wenn ich dies alles schon mit dem Cheap Yellow Display habe?. Im Angebot kosten die Teile vielleicht 10 Euro und bieten on Board schon alles was ich brauche bis auf den 433 MHz-Sender.
CYD als Hardware steht damit
Mit dem Touchscreen des CYD kann ich das Num-Pad abbilden und die Eingaben entgegen nehmen. Der ESP32 auf dem CYD hat mehr als genügend Rechen-Power. WLAN und Bluetooth brauchen wir nicht. SD-Karte und RGB-LED auch nicht. Aber ein kleiner Piepser (Buzzer) wäre neben dem 433 MHz-Sendemodul vielleicht noch schön. Das lässt sich alles ohne viel Löterei zum Testen mittels der kleinen 4-poligen, mitgelieferten Kabel anschließen. Es kann also ohne Breadboard und ohne Löten getestet werden.Wer hier mit programmieren will, dem sei gesagt, dass es doch ein wenig Wissen gibt, dass ihr euch zuerst aneignen müsstet. Ihr könnt aber auch erst einmal dieser Artikel zu Ende lesen und dass dann nachholen.
Ihr solltet zum Einstieg in die Materie zuerst die Hardware und das Pinout des TouchScreen-ESP32 ESP32-2432S028R-kennenlernen.
Danach solltet ihr euch eine Entwicklungsumgebung mit PlatformIO in Visual Studio Code einrichten, wie in diesem Artikel besprochen. Danach solltet ihr noch den Artikel Programmierung des Displays mit der TFT_eSPI-Library lesen, in dem ihr lernt, wie wir etwas auf dem Display ausgeben.
Auch den Artikel über die Programmierung des Touchscreen Digitizer XPT2046, der im Cheap Yellow Display steckt, solltet ihr lesen.
Damit wäre dann die Hardware-Ansteuerung von Display und Touchscreen bewerkstelligt. Nun kommt als Dialogsystem die LVGL Library obendrauf. In diesem Artikel erfahrt ihr, wie man diese für die weitere Verwendung einbindet und mit der Standard-LVGL-Demo (die, mit dem das Gerät ausgeliefert wurde) testet.
Im darauffolgenden Artikel haben wir dann gelernt, wie man LVGL-Dialoge entwirft und mittels Events steuert. Damit haben wir genügend gelernt, um unsere eigenen Anwendungen mit LVGL-Dialogen zu programmieren.
Okay, das ist jetzt krass viel als Voraussetzung, aber ich werde nicht alles wieder und wieder durchkauen, sondern das dort Gesagte als Vorwissen voraussetzen.
Lasst uns mit der Oberfläche anfangen, Hardware folgt später

Am einfachsten und schnellsten ist natürlich der Intro-Screen angepasst, den ich schon im CYD-Projekt DC Utilities V5: Webradio und MP3-Player benutzt hatte. Das Logo haben wir ja bereits im Speicher hinterlegt und wir müssen nur noch den Text ändern. Fertig. Nach dem Einschalten kommt der Start-Screen und nach einem Tap auf das Display geht es dann weiter in die eigentliche Timer-Steuerungs-Oberfläche.
Da das Definieren der Oberfläche viel Kleinarbeit darstellt und beim Hinzufügen oder Verschieben eines Knopfes immer einiges an Koordinaten angepasst werden muss, rate ich dringend dazu, sich vorher ein Schmierzettel zu nehmen und mit Bleistift kurz aufzuzeichnen, wie man sich die Oberfläche vorstellt und was man alles braucht.
Schon bei diesem Prozess merkt man häufig, dass da noch ein Knopf fehlt oder dass die Buttons anders vielleicht intuitiver / ergonomischer angeordnet wären. Die Frage dabei ist immer: Was will ich, dass die App kann und was muss ich dafür haben?
Mein Gedankengang war dann ungefähr so: Ich brauche die Buttons 0 bis 9 und einen Start-Button. Und eine Anzeige, wo angezeigt wird, was ich eingeben habe. Naja, ein Lösch-Button bei Fehleingabe wäre auch nicht schlecht. Den mach ich rot. Und den Start-Button nenne ich kürzer "Go", dann kann ich eine große Schrift für die Buttonbeschriftungen nehmen. Ich will sowieso große Buttons. Ach, wenn es kurz piept, wenn ich einen Button drücke wäre nicht schlecht. Für später notieren: Buzzer wäre nicht schlecht. Äh, wo war ich? Ach ja, der Eingabe. Die will ich mit so wenigen Tasten wie möglich 8-6-Go muss reichen für 86 Sekunden. Ich will aber nicht immer alles in Sekunden eingeben. Meine Asia-Schalte braucht 4 Minuten und 30 Sekunden. Da will ich "4m30s" oder "4m30" eingeben können. Also brauche ich noch ein "M" und ein "S" Knopf, vielleicht passt ja auch "Min." und "Sek." drauf? Eigentlich wäre es ganz cool, auch extra Buttons zum Ein- und Ausschalten zu haben. "On" und "Off" oder "Ein" und "Aus" wären da die Beschriftungen. Oh, wenn ich 3 Buttons nebeneinander habe, dann sind dass 240 / 3 gleich 80 Breite pro Button. Dann passen 4 Zeilen untereinander für die 320 Höhe. Das reicht nicht. Ich brauche min. 5 Zeilen Buttons. Dann werden die halt nicht quadratisch. Oh, damit habe ich schon 15 Buttons. Kein Platz mehr für einen "Abbruch"-Button. Ach, da nehme ich den Go-Knopf und mache den beim Start zu einem Stop und der bricht dann ab. Damit man das sieht, mache ich das Go in grün und das Stop in rot. Okay, nochmal anschauen... Ja so passt das.

Meine Schmierereien will ich euch nicht antun, aber beim Kreativprozess muss es nicht schön sein. Hauptsache ich da, seinen Gedanken Form zu verleihen. Schön kommt später. Und sieht dann so aus wie rechts gezeigt.
Im Grunde genommen genau das, was meinem Gedankengang entsprach.
Die folgende Funktion how_screen_main() zaubert den Inhalt auf den Bildschirm:
void show_screen_main () {
LV_LOG_USER ("Show ");
tftBrightness_init(TftBrightness);
lv_obj_t *label;
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
int wi = 66; int space = 10;
int hi = 44;
int x1 = 5; int x2 = x1+wi+space; int x3 = x2+wi+space;
int y = 0; int yp = hi+space;
uint8_t btn_id=0;
lab_counter = lv_label_create(lv_screen_active());
lv_label_set_text(lab_counter, "");
lv_obj_set_style_text_font(lab_counter, &lv_font_montserrat_38, 0); //https://docs.lvgl.io/9.1/overview/font.html#fonts
lv_obj_set_style_text_align(lab_counter, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_align(lab_counter, LV_TEXT_ALIGN_LEFT, 0, 0);
lv_obj_t *btnC = lv_button_create(lv_screen_active());
lv_obj_set_style_bg_color(btnC, lv_color_hex(0xff0000), 0);
lv_obj_set_user_data(btnC, &main_btn_ids[btn_id]); btn_id++;
lv_obj_add_event_cb (btnC, evt_btn, LV_EVENT_CLICKED, NULL);
lv_obj_remove_flag (btnC, LV_OBJ_FLAG_PRESS_LOCK);
lv_obj_set_width (btnC, wi);
lv_obj_set_height (btnC, hi);
lv_obj_align (btnC, LV_TEXT_ALIGN_LEFT, x3, y);
label = lv_label_create(btnC);
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
lv_label_set_text(label, "C");
lv_obj_center(label);
y=yp;
lv_obj_t *btn1 = lv_button_create(lv_screen_active());
lv_obj_set_user_data(btn1, &main_btn_ids[btn_id]); btn_id++;
lv_obj_add_event_cb (btn1, evt_btn, LV_EVENT_CLICKED, NULL);
lv_obj_remove_flag (btn1, LV_OBJ_FLAG_PRESS_LOCK);
lv_obj_set_width (btn1, wi);
lv_obj_set_height (btn1, hi);
lv_obj_align (btn1, LV_TEXT_ALIGN_LEFT, x1, y);
label = lv_label_create(btn1);
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
lv_label_set_text(label, "1");
lv_obj_center(label);
...
}Wenn man das so macht, kann man die Positionen schnell anpassen, ohne dafür alle 15 Buttons an jeweils zwei Stellen zu ändern. So war mir nämlich zum Beispiel aufgefallen (als ich die erste Zeile noch bei x1=0 beginnen ließ), dass die Animation, bei der sich beim Drücken der Button etwas vergrößert, nicht richtig dargestellt, sondern links abgeschnitten wurde. Außerdem sind die Randbereiche des Touchscreens weniger empfindlich. Es empfiehlt sich also ein bisschen Abstand zum Rand. Mit der hier vorgestellten Methode musste ich nur ein paar Variablen oben anpassen und der Rest rückt sich dann automatisch zurecht. Es gibt auch Button-Arrays in LVGL, aber Einzelbuttons fand ich dann doch besser, weil ein paar Buttons global sein müssen, um die Beschriftung oder Farbe von außerhalb dieser Funktion ändern zu können und das mit Buttons-Arrays dann wieder nicht so einfach geht.
Alle Button rufen übrigens denselben Event evt_btn auf. Um dann noch zu wissen, woher der Tap kam, haben die Buttons IDs. Diese sind:
static uint8_t main_btn_ids[] = {'C',
'1', '2', '3',
'4', '5', '6',
'7', '8', '9',
'0', 'M', 'S',
'O', 'F', 'G' }; void evt_btn(lv_event_t *e) {
bool long_press = false;
if (TapDuration >= 700) long_press=true; // ab wieviel ms TapDuration ist es ein Long-Press?
long m=0; long s=0;
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *btn = (lv_obj_t *) lv_event_get_target(e);
uint8_t *btn_id = (uint8_t*) lv_obj_get_user_data(btn);
int beeplen=50;
if(code == LV_EVENT_CLICKED) {
debug_print ("Button pressed "); if (long_press) debug_print("long "); debug_println (*btn_id);
beep(beeplen);
if (long_press) { delay (beeplen); beep (beeplen);}
if (CountdownActive && *btn_id != 'G' ) {
return; // im Countdown ist nur Abbruch desselben erlaubt
}
...
switch(*btn_id) {
case 'C': // Clear
Counter = "";
if (long_press) {
enter_powersave();
return;
}
break;
case '1': if (long_press) { Counter = "1m26s"; } else { Counter = Counter + "1"; } break;
case '2': if (long_press) { Counter = "4m30s"; } else { Counter = Counter + "2"; } break;
case '3': if (long_press) { Counter = "9m0s"; } else { Counter = Counter + "3"; } break;
case '4': Counter = Counter + "4"; break;
...
case 'G': // GO!
if(!CountdownActive) {
long p = Counter.indexOf ('m');
if (p != -1) { m = Counter.substring(0,p).toInt(); } else { p=-1; }
long p2 = Counter.indexOf ('s');
if (p2 != -1) { s = Counter.substring(p+1,p2).toInt(); } else { s = Counter.substring(p+1,Counter.length()).toInt(); }
SeksToGo = m*60 + s;
debug_print ("SeksToGo="); debug_println(SeksToGo);
// Button rot und Stp.
lv_obj_set_style_bg_color(btnGo, lv_color_hex(0xff0000), 0);
lv_label_set_text(lab_btnGo, "Stp.");
// Display aktualisieren
refreshCounterFromSeksToGo(); // macht schon refreshLVGL
switchOn();
SeksToGo-=1; // senden des Codes hat schon 1 Sekunden gebraucht
refreshCounterFromSeksToGo(); // macht schon refreshLVGL
CountdownSeconds=SeksToGo;
CountdownActive = true;
// Timer wird alle 1000 ms aufgerufen
CountdownTimer = lv_timer_create(countdown_timer_cb, 1000, NULL);
} else {
// Go ist jetzt Stp. und bewirkt Abbruch
if (CountdownTimer != NULL) {
lv_timer_del(CountdownTimer);
CountdownTimer = NULL;
CountdownActive = false;
// Button wieder grün und Go
lv_obj_set_style_bg_color(btnGo, lv_color_hex(0x00c000), 0);
lv_label_set_text(lab_btnGo, "Go");
switchOff();
Counter="";
}
}
break;
}
}
lv_label_set_text(lab_counter, Counter.c_str() );
}debug_print ist eine eigene Serial.print()-Routine, nur mit dem Unterschied, dass ich einen Schalter umlegen kann und dann kein Output mehr erfolgt, weil da ja nur während der Entwicklung und zum Debuggen gut ist.
Da wir die Eingabe auch noch zulassen wollen (nämlich um abzubrechen), wenn der Countdown läuft, können wir das nicht einfach ein einer "while (sekunden) { delay(1000); sekunden--; }"-Schleife tun, weil während der Schleife der Dialog tot wäre. Sondern wird müssen einen Timer bemühen. Es gibt LV-Timer und ESP32-Timer und noch einmal besondere Sleep-Timer. Das habe ich euch in diesem separaten Artikel über Hardware- Software- und LVGL-Timer genauer erklärt.
Und dann gibt es noch eine besondere Art von Timern, die Sleep-Timer, die ich auch in meinem Projekt verwende und über die ein einen extra Artikel gibt: Den ESP32 schlafen legen, um Strom zu sparen.
Das war es eigentlich auch schon zur Dialogsteuerung. Kommen wir zur Hardware.
Zusatz-Hardware: 433 MHz Funk-Modul

Die Funksteckdosen, die ich benutze, habe ich schon einmal im Artikel Mit dem Raspberry Pi 433 MHz-Funksteckdosen schalten vorgestellt. Sie haben an der Rückseite zehn DIP-Switches zur Konfiguration des Signals, auf das sie hören sollen:

Hier wäre das also - zwei Gruppen à 5 Bit: 11111 00001. Das merken wir uns für unseren Code. Denn darüber sprechen wir die richtige Funksteckdose an. Achja, und dran denken, dass bei vielen Funksteckdosen die Leistung beschränkt ist. Durch meine darf zum Beispiel nur 1000 Watt fließen, was für mein Mikrowellen-Modell aber ausreicht.
Außerdem findet ihr in dem Artikel mehr zur Hardware, dem 433-MHz-Sender FS1000A, falls euch das interessiert. Im Artikel benutzen wir einen Raspberry Pi mit den 433Utils, aber es gibt so etwas natürlich auch für Arduino und ESP32.
Beim ESP32 heißt die Funksteckdosen-Steuerungs-Library RC-Switch und ist zu finden unter https://github.com/sui77/rc-switch.
Einfacher ist es aber, die platformio.ini unter "lib_deps =" mit "sui77/rc-switch @ 2.6.4" zu ergänzen. Noch den entsprechenden Header inkludieren und schon kann man mit einem Einzeiler pro Funktion ein- und ausschalten:
String SwitchBits1="11111";
String SwitchBits2="00001";
void switchOn() {
lv_obj_set_style_bg_color(btnOff, lv_color_hex(0xffffff), 0);
lv_obj_set_style_bg_color(btnOn, lv_color_hex(0xffff00), 0);
refreshLVGL();
digitalWrite(Pin_Buzzer, HIGH);
mySwitch.switchOn(SwitchBits1.c_str(), SwitchBits2.c_str());
digitalWrite(Pin_Buzzer, LOW);
}
void switchOff() {
lv_obj_set_style_bg_color(btnOn, lv_color_hex(0xffffff), 0);
lv_obj_set_style_bg_color(btnOff, lv_color_hex(0xffff00), 0);
refreshLVGL();
digitalWrite(Pin_Buzzer, HIGH);
mySwitch.switchOff(SwitchBits1.c_str(), SwitchBits2.c_str());
digitalWrite(Pin_Buzzer, LOW);
}
Unten rechts findet man einen Anschluss, der auf dem Board als P3 bzw. "Extended IO" bezeichnet wird
- GND (Ground, Masse)
- IO35 (GPI Pin 35) (ja, 35, nicht 33, das sieht nur so aus wegen des Vias dort)
- IO22 (GPIO Pin 22, überschneidet sich mit Connector CN1)
- IO21 (GPIO Pin 21, überschneidet sich mit dem Pin für die Hintergrundbeleuchtung des TFT)
Links daneben findet man einen Anschluss, der auf dem Board als CN1 bzw. "Temperature and humidity interface" bezeichnet wird:
- GND (Ground, Masse)
- IO22 (GPIO Pin 22, überschneidet sich mit Connector P3)
- IO27 (GPIO Pin 27)
- 3.3V (Versorgungsspannung 3.3V, ca. 20 mA)
Von P3 nehmen wir uns GND und IO22 für den Buzzer und von CN1 nehmen wir uns GND, 3.3V und IO27 für den 443 MHz-Transmitter und definieren das gleich mal als Variablen für unseren Code:
int Pin_Buzzer = 22;
int Pin_433 = 27;

Die FS1000A Module stammen noch aus 5V-Arduino-Zeiten und funktionieren am besten mit 5 V.
Sie tun es auch mit 3.3V, aber dann nicht so weit. Das sollte eigentlich kein Problem darstellen, da ja Sender (mein Projekt) und Empfänger (Funksteckdose der Mikrowelle) im selben Zimmer, der Küche, sind.
Trotzdem wären 5V sicherer. Ich habe darum mal ein bisschen auf der Platine des CYD herumgemessen, wo man am besten 5V für die Spannungsversorgung des FS1000A hernehmen könnte. Weil, die muss es irgendwo geben, wenn wir per USB mit 5V einspeisen.
Hier haben sich folgende Punkte gezeigt: Vor der Dioden rechts neben dem USB-C-Port sind es die 5V vom USB. Danach wandern die 5V in die Diode D1 und es fallen 0.3V ab und es kommen 4.7V wieder heraus.
Jetzt könnte man direkt an dem einen Beinchen vor der Diode die 5V abgreifen, oder man gibt sich mit 4.7V zufrieden und benutzt Lötpad S3, was mit Sicherheit eine stabilere Lötverbindung ergibt.
Ich werde es erst einmal mit 3.3V versuchen und wenn das irgendwie instabil erscheint, dem FS1000A mehr Saft geben.
Zu dem aktiven Buzzer muss ich wohl nicht viel Worte verlieren. Er wird als Output definiert und wenn man den Pin_Buzzer auf HIGH setzt, piept das Ding vor sich hin, bis das Signal wieder LOW wird. Total simpel.
Demo und Video
Ich habe wieder ein kleine Demonstrations-Video gemacht, dass die neuen Dialoge in Aktion zeigt:3D-gedrucktes Gehäuse und Installation
Mein CYD-Gehäuse musste ich ein bisschen anpassen. Zum einen brauchte ich ein Loch mit 12 mm Durchmesser im Gehäuse für den aktiven Buzzer. Das passte von der Höhe gerade so eben, guckt aber ein wenig raus, weil er halt über die komplette Gehäusehöhe geht. Beinahe hätte ich den Deckel von dem Gehäuse ein wenig anfeilen müssen, aber schlussendlich hat es dann doch gerade so gepasst. Fixiert wurde der Buzzer mit etwas Klebeknete, aber der dürfte auch so nicht einfach so herusfallen. Außerdem wurden die 4-poligen Kabel sehr stark geknickt und fast schon beschädigt, wenn man den Deckel anschraubt, weil sie gegen die Gehäusewände drücken. Also mal zwei Löcher für die Konnektoren P3 und CN1 vorgesehen, damit die "noch ein wenig atmen können".Die 433MHz-Funkplatine habe ich auch noch so gerade in das Gehäuse bekomme. Und zwar dort, so das ESD auf der CYD-Platine Zeichen ist, mit der Antenne nach rechts außen, Richtung Funksteckdose. Allerdings musste ich die Pins auf der Unterseite der Platine sehr knapp abschneiden, damit der Platz passt. Das war hier also auch sehr knapp. Ein 1mm dickes Silikonklebeband sorgt für Isolation und Halt. Ich habe mich dann übrigens für die Spannungsversorgung mit 4.7V entschieden. Funktioniert klarlos bis jetzt.
Es konnte also das Standard-CYD-Gehäuse mit ein paar Modifikationen benutzt werden.
Eigentlich wollte ich auch den Deckel mit OpenSCAD ein wenig anpassen und die Öffnung für den Licht-Sensor ein wenig größer machen, aber da gab es immer ein Fehler "nicht mannigfaltige Kante" beim Importieren in ideaMaker und OpenSCAD hat den Import einfach ignoriert, so dass Markus' Modell-Vorlage auf einmal weg und nur noch die Modifikationen beim Rendern mit F6 zu sehen waren. Beim Vor-Rendern mit F5 war alles prima, nur F6 ging nicht, und damit auch kein Exportieren als STL und damit kein Drucken. Welche Odyssee es war, Markus' Modell sauber zu kriegen, damit es in OpenSCAD benutzbar war, das schildere ich in diesem Artikel: Kaputte STL-Files mit nicht mannigfaltigen Kanten reparieren
Bei der Stromversorgung habe ich mich dann doch gegen eine Powerbank und für ein feste Stromversorgung über USB-Netzteil entschieden. Außerdem hatte ich noch ein langes USB-Micro-Kabel übrig. Wenn ich das in der Fuge zwischen den Türen außen lang laufen lasse, wird es weder gequetscht noch allzu sehr gebogen. Ein bisschen doppelseitiges Silikonklebeband hier und da sorgt dafür, dass das Kabel nicht im Weg ist.
So, und hier noch ein Foto von der fertigen Installation in meiner Küche:

Quellen, Literaturverweise und weiterführende Links
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Vorstellung Hardware und Pinout
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Erste Schritte Programmierung der RGB LED
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Displays mit der TFT_eSPI-Library
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Programmierung des Touchscreen Digitizer XPT2046
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Einbinden der LVGL Library
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Dialoge entwerfen mit der LVGL Library
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - LVGL-Dialog / Utilities: RGB-LED Color Changer
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Utilities Test Display und Touch
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Utility V3 Settings und WLAN-Scan
- ESP32-2432S028 mit 2.8" Touchscreen (Cheap Yellow Display) - Utility V5 WebRadio und MP3-Player
- LVGL-Dokumentation für Version 9.1
