ESP8266 OLED Display für ioBroker über MQTT
In diesem Artikel beschreibe ich das OLED Display Projekt, mit dem Informationen von ioBroker angezeigt werden können.
Das Display soll über das MQTT-Protokoll Informationen aus ioBroker Datenpunkten (Objekte) anzeigen können. Angesteuert werden soll das Display von einem ESP8266 über WLAN. Die wichtigste Anforderung an das Projekt war die Trennung zwischen Logik-und Präsentationsschicht. Die komplette Logik soll später in ioBroker abgebildet werden können. Der ESP8266 abonniert die entsprechenden MQTT-Topics und zeigt diese auf dem OLED-Display an. Bevor wir nun mit dem Aufbau der Hardware beginnen können, hier die Liste der benötigten Komponenten:
Preis: 6,49 €
1 gebraucht & neu ab 6,49 €
Preis: 5,79 €
2 gebraucht & neu ab 5,79 €
Preis: 6,99 €
2 gebraucht & neu ab 6,99 €
1. Aufbau der Hardware
Im nächsten Schritt kümmern wir uns um den Aufbau des ESP8266 mit dem OLED-Display und beginnen mit der Programmierung. Zunächst verkabeln wir den ESP8266 mit dem OLED Display nach folgender Pin-Belegung:
OLED-Display | ESP8266 |
---|---|
GND | GND |
VCC | 3V3 |
SCL | D1 |
SDA | D2 |
2. Programmierung der Software für den ESP8266
Nach dem wir nun den ESP8266 mit dem Display verbunden haben beginnen wir mit der Einrichtung der Arduino IDE für unser Projekt sowie mit der Programmierung der Software für den ESP8266. Im ersten Schritt müssen wir noch folgende Libraries installieren, welche für die Kommunikation mit dem Display benötigt werden:
- Adafruit GFX Library
- Adafruit SSD1306


Sketch-Code für die Programmierung des ESP8266:
#include <SPI.h> #include <Wire.h> #include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> const char* ssid = "WIFI-SSID"; const char* password = "WIFI-PWD"; const char* mqtt_server = "MQTT-BROKER-IP (ioBroker)"; String _DisplayLine1 = ""; String _DisplayLine2 = ""; String _DisplayLine3 = ""; String _DisplayLine4 = ""; #define OLED_RESET 0 Adafruit_SSD1306 display(OLED_RESET); WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); if ( strcmp( topic, "display_line1" ) == 0 ) { _DisplayLine1 = ""; for (int i = 0; i < length; i++) { _DisplayLine1 += (char)payload[i]; } } if ( strcmp( topic, "display_line2" ) == 0 ) { _DisplayLine2 = ""; for (int i = 0; i < length; i++) { _DisplayLine2 += (char)payload[i]; } } if ( strcmp( topic, "display_line3" ) == 0 ) { _DisplayLine3 = ""; for (int i = 0; i < length; i++) { _DisplayLine3 += (char)payload[i]; } } if ( strcmp( topic, "display_line4" ) == 0 ) { _DisplayLine4 = ""; for (int i = 0; i < length; i++) { _DisplayLine4 += (char)payload[i]; } } UpdateDisplay(); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // Attempt to connect if (client.connect(clientId.c_str())) { Serial.println("connected"); client.subscribe("display_line1"); client.subscribe("display_line2"); client.subscribe("display_line3"); client.subscribe("display_line4"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void UpdateDisplay() { display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(2); display.setCursor(1,0); display.print(_DisplayLine1.c_str()); display.setCursor(1,16); display.print(_DisplayLine2.c_str()); display.setCursor(1,32); display.print(_DisplayLine3.c_str()); display.setCursor(1,48); display.print(_DisplayLine4.c_str()); display.display(); } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); display.begin( SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(2); display.display(); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); }
3. Vorbereitungen in ioBroker
Im ersten Schritt legen wir uns 4 Datenpunkte „display_line1 … display_line4“ in ioBroker an. Die Inhalte (Zeichenfolgen) der Datenpunkte werden später auf dem Display angezeigt. Zur Initialisierung können wir diese Datenpunkte bereits mit den Zeichenfolgen „Zeile 1“ bis „Zeile 4“ befüllen.

4. Erstellung der ioBroker Display-Logik
Auf dem Display sollen in meinem Beispiel 4 Zeilen angezeigt werden. Das Display soll folgenden Aufbau bekommen:
System: <STATUS>
Device: <STATUS>
Status: <STATUS>
Water: <YES>
Dabei soll im Systemstatus OK angezeigt werden, wenn keine Warnung oder Systemmeldung seitens den HomeMatic Aktoren vorliegt. In der zweiten Zeile möchte ich anzeigen ob noch ein Gerät (Device) eingeschaltet ist. Der Status gibt an, ob noch Fenster oder Türen geöffnet sind. In der letzten Zeile steht der Status des Bewässerungsbedarfs. Der Outdoorsensor misst hier die Bodenfeuchtigkeit und soll ab einem vorher definierten Grenzwert die Anzeige „Water“ auf YES stellen.
Nach dem wir nun die Logik der Anzeige definiert haben, beginnen wir mit der Implementierung des entsprechenden Scripts. Im ersten Schritt lege mich nun ein neues JavaScript an. Der Script-Code der Steuerung wird nun folgendermaßen definiert:
on({id: "hm-rpc.0.XXX.1.STATE", change: "ne"}, function (obj) { UpdateDisplayStatus(); }); on({id: "hm-rpc.0.XXX.1.STATE", change: "ne"}, function (obj) { UpdateDisplayStatus(); }); on({id: "hm-rpc.0.XXX.1.STATE", change: "ne"}, function (obj) { UpdateDisplayStatus(); }); on({id: "hm-rpc.0.XXX.1.STATE", change: "ne"}, function (obj) { UpdateDisplayStatus(); }); on({id: "hm-rpc.0.XXX.1.STATE", change: "ne"}, function (obj) { UpdateDisplayStatus(); }); function UpdateDisplayStatus() { // Display Line 1 var SystemStatusText = "OK"; if ( getState("hm-rega.0.maintenance").val &amp;amp;amp;gt; 0 ) { SystemStatusText = "ER"; } // Display Line 2 var StatusDeviceText = "OFF"; var StatusDevice_TV = getState("hm-rpc.0.XXX.1.STATE").val; var StatusDevice_Licht_Flur = getState("hm-rpc.0.XXX.1.STATE").val; var StatusDevice_Licht_Esszimmer = getState("hm-rpc.0.XXX.1.STATE").val; if ( StatusDevice_Licht_Flur === true || StatusDevice_Licht_Esszimmer === true || StatusDevice_TV === true ) { StatusDeviceText = " ON"; } // Display Line 3 var StateText = "OK"; var StateHaustuer = getState("hm-rpc.0.XXX.1.STATE").val; var StateTerassentuer = getState("hm-rpc.0.XXX.1.STATE").val; if ( StateHaustuer === true || StateTerassentuer === true) { StateText = "ER"; } // Display Line 4 var WaterState = "NO"; if ( getState("mqtt.0.outdoor1_Bodenfeuchtigkeit").val &amp;amp;amp;gt; 700 ) { WaterState = "YES"; } // Save display lines setState('mqtt.0.display_line1', "System:" + SystemStatusText ); setState('mqtt.0.display_line2', "Device:" + StatusDeviceText ); setState('mqtt.0.display_line3', "Status: " + StateText ); setState('mqtt.0.display_line4', "Water: " + WaterState ); }
Die Basis der Logik-Steuerung stellt die Funktion UpdateDisplayStatus() dar. Diese Funktion ermittelt alle Werte für die Anzeige und schreibt diese im letzten Schritt in die entsprechenden Datenpunke des MQTT-Adapters. Somit werden die neuen Display-Werte an den ESP8266 publiziert. Für das Update des Displays wird die UpdateDisplayStatus() Methode nach einem Update der STATE Datenpunkte der jeweiligen Geräte aufgerufen.
Nach diesem Schema könnt Ihr natürlich auch eine eigene Logik definieren, welche zur Anzeige von Werten dargestellt werden soll.
Ich hoffe euch gefällt dieser Artikel. Über Kommentare unterhalb des Artikels oder per E-Mail freue ich mich wie immer ?
Pingback: StatusDisplay ESP8266 ePaper |
Hallo !
Durch dich bin ich zum ESPEasy kommen und habe es nicht bereut. Das machst Du super.
Beim Skecth von oben bekomme ich aber diese Meldung:
exit status 1
PubSubClient.h: No such file or directory
Kannst Du mir helfen?
Gruß
Thomas
Hallo Matthias,
jetzt habe ich mein Problem mit PubSubclient behoben, war einfach,sorry für meinen Kommentar.
Aber nach dem Upload des Sketchs für das Display blinkt die WLAN Lampe nur noch und ich empfange meinen Arduino nicht mehr…..
Moin Thomas,
kein Problem. Hast Du in die Setup-Methode bereits Ausgaben für die serielle Schnittstelle gemacht? Mit diesen Ausgaben siehst Du dann, wie weit das Programm läuft, und wo er evtl. hängen bleibt. Versuche das mal und geb mir nochmals Bescheid. Alternativ erneut flashen und nochmal probieren.
Moin Matthias,
mein Arduino freezed jetzt immer. Über die ser.Schnittstelle läuft dann auch nichts.
Das Problem tritt immer dann auf, wenn ich den Sketch uploade.
Ich habe die 2er Firmware.
Moin,
tritt das Problem schon während dem Upload auf? Wenn nein, versuche mal Code herauszunehmen (auskommentieren), so lange bis Du die Zeile ausfindig machen kannst, die den freeze verursacht.
Hallo !
Jetzt ist der Fehler raus. Ich hatte die IP im http-Format eingegeben. Mist.
Nun gehts. Aber bei mir ist die Schrift so groß´, dass nur 2 Zeilen reinpassen. Woran kann das liegen?
und wie machst Du das mit der generellen Erreichbarkeit des EspEASY? nach dem Start des Scripts von Dir, ist der Nodemcu nicht mehr erreichbar.
Dadurch kann ich auch nicht die anderen POrts belegen,oder?
Hallo,
konntest du es lösen? Bei mir werden leider auch nur 2 Zeilen angezeigt.
Hi,
Ich habe einen Sonoff Touch im Flur für die Statusabfrage verbaut .
Im moment habe ich es so realisiert, dass wenn ich auf den Sonoff Touch drücke, dann eine Nachricht per Telegram auf das Handy kommt ob die Fenster auf sind.
Alles mit iobroker am laufen.
Jetzt die frage, könnte man auch so ein OLED Display über den Sonoff Touch anschließen und laufen lassen ?
Bei Tastendruck auf den Sonoff Touch bekomme ich eine Info auf dem OLED Display ob z.b Fenster auf sind?
Danke dir schonmal
Ja, das wäre über einen ESP8266, OLED-Display sowie MQTT auf jeden Fall möglich. Der Sonoff triggert einen Datenpunkt im ioBroker. Dadurch werden die Informationen gesammelt und über einen weiteren Datenpunkt an MQTT-weitergegeben. Der ESP8266 hat den Datenpunkt abonniert und zeigt dann die Informationen an. Sollte relativ easy möglich sein 🙂
Moin moin.
Hab da mal ne Frage.
Ich habe einen Wemos D1 Mini, ein OLED Display (SH1106) und einen fertigen ioBroker mit mqtt.
Auf dem ioBroker läuft ein Blockly Script, das 4 MQTT Datenpunkte regelmässig updatet. Nicht mit Zahlen, sondern mit kurzem Text.
Ich würde gerne einfach diese 4 Datenpunkte untereinander auf dem Display ausgeben. Diese 4 Zeilen sollte sich natürlich aktualisieren, sobald der Datenpunkt im MQTT Broker aktualisiert wird.
Mit espEasy klappt es teilweise, denn leider kann es nur Zahlen ausgeben.
Wäre das mit deinem Sketch und Script auch für Text möglich?
Vielen Dank schonmal.
Grüße
Andreas
4 Zeilen Fix.
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 0
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//Adafruit_SSD1306 display(OLED_RESET);
Hallo,
ist es möglich Benutzername und Kennwort bei der MQTT Verbindung mit zu übergeben?
das würde mich auch brennend interessieren.
Hallo,
klar, das geht ganz einfach:
In Zeile 22 des Skechtes, den Code wie folgt erweitern:
PubSubClient client(espClient,"DeinUserName","DeinPasswort");
no matching function for call to ‚PubSubClient::PubSubClient(WiFiClient&, const char [13], const char [13])‘
Was mach ich falsch?
Hallo ich habe das Problem das ich immer nur 2 Zeilen von iobroker im adurino einlesen kann
client.subscribe(„display_line1“);
client.subscribe(„display_line2“);
client.subscribe(„display_line3“);
client.subscribe(„display_line4“);
Wenn ich z.b Zeile 1 und 2 auskommentiere kann ich 3 in d 4 einlesen
Schoene Gruesse von Gerhard
Ich nochmal,
was mache ich falsch?
Es werden immer nur zwei Zeilen eingelesen
15:32:18.292 -> Attempting MQTT connection…connected
15:32:22.737 -> Message arrived [display_line1]
Message arrived [display_line2]
Attempting MQTT connection…connected
15:33:27.876 -> Message arrived [display_line1]
Message arrived [display_line2]
Attempting MQTT connection…connected
15:34:33.205 -> Message arrived [display_line1] usw.
Schöne Grüße Gerhard
Hallo,
Super-Projekt, aber ich bekomme es irgendwie nicht hin.
Wenn ich Deine Anleitung 1 zu 1 befolge, zeigt das OLED komische Pixel und die MCU startet immer wieder neu.
Jetzt habe ich mal den Code von Andre (s.o.) eingefügt, dann startet er normal, sagt auch, dass er die MQTT Zeilen empfangen hat, aber das Display bleibt komplett schwarz (Objekte im IO-Broker befüllt)
Habe eine NodeMCU 3.3, Pinout müsste das gleiche sein?!
Vielen Dank für einen Tipp
LG Thilo
Klasse Projekt. Vielen Dank dafür.
Ich habe dazu aber noch Fragen.
Kann ich einen 2ten WLAN Zugang eintragen? Wenn ja, wie?
Kann man dss anpassen, dss es auch mit dem Sonoff Adapter geht, ohne den direkten Mqtt Server?
Ich würde gern Temperatur Werte von meinen Zigbee Wetter Sensoren anzeigen lassen. Gibt es für so einen Fall auch eine Vorlage?
Vielen Dank Gruß Christian
Hallo Matthias,
wahrscheinlich liegt es an irgendeiner Einstellung meines Browser oder Rechner. Aber irgendwie wird Dein Script hier ziemlich verstümmelt angezeigt:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
und weiter unten:
if ( strcmp( topic, „display_line1“ ) == 0 )
{
_DisplayLine1 = „“;
for (int i = 0; i < length; i++) { _DisplayLine1 += (char)payload[i]; }
}
if ( strcmp( topic, „display_line2“ ) == 0 )
{
_DisplayLine2 = „“;
for (int i = 0; i < length; i++) { _DisplayLine2 += (char)payload[i]; }
}
if ( strcmp( topic, „display_line3“ ) == 0 )
{
_DisplayLine3 = „“;
for (int i = 0; i < length; i++) { _DisplayLine3 += (char)payload[i]; }
}
if ( strcmp( topic, „display_line4“ ) == 0 )
{
_DisplayLine4 = „“;
for (int i = 0; i < length; i++) { _DisplayLine4 += (char)payload[i]; }
}
Hallo Werner,
sorry für das Problem. Nein, durch eine Software-Aktualisierung wurde der Code falsch dargestellt. Jetzt passt es wieder 🙂
LG Matthias
Hallo. Leider ist das in diesem Beitrag aufgeführte OLED-Display nicht mehr verfügbar. Ich habe deshalb das 1,3 Zoll OLED Display von AZDelivery. Dieses wird jedoch über einen SH1106 Chip gesteuert, anders wie das o.g. Display über den SSD1306.
Was muss im Sketch angepasst werden, damit das OLED-Display korrekt angesteuert wird?
Vielen Dank.
Moin,
der Link führt zum Display, laut Amazon sind auch noch genügend vorrätig? Das neue Display habe ich noch nicht hier, von Daher kann ich Dir hier noch nicht viel sagen.
Du kannst Dir aber mal folgendes Repo auf GitHub ansehen:
https://github.com/rene-mt/esp8266-oled-sh1106
LG Matthias