It took me about a week to get this going. There are still a few kinks that need to be ironed out, or worked around. But I wanted to get this out there before I forgot about it. I could not find a sketch for using an Arduino or ESP with an OLED and MQTT. Not one that didn’t just display data from a connected sensor., that is not what I wanted. I wanted to be able to send messages to the OLED screen via MQTT. I spent quite a while looking for it and I couldn’t find anything. About a week or two ago I finally broke the wall that was keeping me from sending and receiving MQTT message on an ESP. So I took that code and the working code from the Adafruit OLED sketch and made a baby.
I was able to produce a sketch that will simply display any text received via MQTT. Perfect. I plan on using this cobbled together with Node-Red. That way I can have one screen and send multiple sensor readings to it with minimal coding and parts. There are a few things I still need to figure out. For example I can’t get the screen to clear. Perhaps thats what the OLED reset pin was for? But my OLED only has four pins; SDA, SCL, Vcc and Ground. No reset. What to do? I think that is actually the only thing I need to work out. The Adafruit code will wrap your text to new lines, so make a note of that. I have gotten around clearing the screen by injecting spaces via MQTT. Its a little more effort in Node-Red for now until I get that down. But it works. It doesn’t matter how you get there as long as you get there right?
I Program the ESP via the Arduino IDE, if you don’t know how to set that up take a stroll down Google lane. Tons of help there on that topic. As it stands in the code below, once powered up the OLED should flash the Adafruit logo until a message is received then it will display the message until a new one is received. Simple. The default topic is “inTopic”, and the default OLED font size is 1. I have tried a font size of 2 but no higher. I also stumbled upon this library here. Much smaller and designed just for text. May try that in the future, but if it ain’t broke don’t fix it.
Items Required:
(1) ESP-01 (mine is a standard ESP-01 from eBay)
(1) OLED I2C Screen (I used a 0.96″ 4pin OLED also off eBay)
IDE Library Requirements:
Wire
Adafruit GFX
Adafruit SSD1306
ESP8266WiFi
PubSubClient
Some places that helped
https://learn.adafruit.com/monochrome-oled-breakouts/arduino-library-and-examples
https://github.com/adafruit/Adafruit-GFX-Library
https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts
https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives
https://github.com/knolleary/pubsubclient
This was the tutorial that helped me get what I have going. I couldn’t get the OLED to work quite right until I came across this post. I used it as the base for what I have.
http://randomnerdtutorials.com/guide-for-oled-display-with-arduino/
This page helped but not until I specified the SDA, SCL pins for the ESP. I couldn’t get the display to work properly and do what I wanted.
http://randomnerdtutorials.com/esp8266-0-96-inch-oled-display-with-arduino-ide/
And the code (below): [See the comments for updated code]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> // not available on ESP-01, but needed in the code #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); const char* ssid = "SSID"; // ssid const char* password = "password"; // password const char* mqtt_server = "10.0.0.10"; // mqqt server const char* inTopic = "inTopic"; // topic esp will subscribe to const char* clientId = "esp-testing"; // id of the esp WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; void setup() { // set gpio0 and gpio2 as sda, scl Wire.begin(0,2); // initialize with the I2C addr 0x3C (for the 128x32)(initializing the display) display.begin(SSD1306_SWITCHCAPVCC, 0x3C); Serial.begin(9600); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); } 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("."); } 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("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); String message = (char*)payload; // if payload = X // if ((char)payload[0] == '1') { // on any payload if ((char)payload[0]) { // do stuff display.clearDisplay(); // oled will wrap lines, single line stops at U, lol, at you get it... // display.print("abcdefghijklmnopqrstuvwxyz"); display.setTextColor(WHITE); display.setTextSize(1); display.setCursor(0,0); // print the message we get from mqtt display.print(message); // if payload = 0, using this to clear the line } else if ((char)payload[0] == '0') { // do stuff display.clearDisplay(); display.setTextColor(BLACK); display.setTextSize(1); display.setCursor(0,0); display.print("....................."); } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(clientId)) { Serial.println("connected"); // Once connected, publish an announcement... // client.publish("outTopic", "hello world"); // ... and resubscribe client.subscribe(inTopic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void displayTempHumid(){ delay(2000); display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(1); display.setCursor(0,0); display.print("Humidity: "); display.print("10"); display.print(" %\t"); display.setCursor(0,10); display.print("Temperature: "); display.print("71"); display.print(" F"); display.setCursor(0,20); display.print("Temperature: "); display.print("53"); display.print(" F"); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // displayTempHumid(); display.display(); } |
https://gist.github.com/jhaury/96f24de0e55e777d000813caef37bf79
updated gist from the comments
Discover more from Its_All.Lost
Subscribe to get the latest posts sent to your email.
Hey Lost, does this sketch blank out the Oled? This is a fantastic sketch (A lot of the others didn’t work…) but I can’t get the screen to reset. The messages arive like:
OFF
ONF
0NF
000000
1111111
ON0000
OFF111
etc. The screen never resets. Am I missing something? (I’m glad your site survived!)
That is the same issue I had/have. I haven’t yet figured out how to clear/blank out the existing messages when a new one arrives. So far I have gotten around the clearing the screen issue by injecting extra spaces in all of the MQTT messages sent. Basically make sure all the messages sent to the screen are the same character length, so everything gets re-written to the entire screen.
Using your example:
OFF
ON_
0__
000000
111111
ON____
OFF___
(using _ as a blank space in this example)
Hope that helps! Glad this was useful to someone!
That certainly makes sense, but I think I’d have to adjust all the other things blasting mqtt around if I wanted them to show up here. I see tons of posts about clearing the screen, but nothing has worked so far.
However! Your sketch worked right off the bat which was AWESOME! Just want to figure out that last piece.
After revisiting this post and looking at the code it looks like you can leave out the whole “void displayTempHumid()” part at the bottom. The call to it is commented out at the bottom so I believe (if I remember correctly) that it was a leftover piece of code from something else.
Awesome thanks I’ll give it a shot!
It must be something with the payload message. I was able to convert your code over to U8G2 thinking that maybe the Adafruit drivers were weird. It does the same thing.
If you use
u8g2.drawStr(0,24,”New Message”);
then it will clear the screen and print the next thing with no overlapping.
However, in order to use a payload message you have to use
u8g2.print(message);
which still has the overlapping issue which makes me think it has to do with pubsubclient and not clearing it from memory? I’ve tried every combo of clearing/pasting/forcing with both libraries and can’t figure it out. I suck at code though so I’m sure someone else has figured it out.
So close!
Sorry I keep spamming your site. I got it working with U8G2 instead of the adafruit libraries (although they may work now!)
#include Wire.h#include Arduino.h#include U8g2lib.h#include ESP8266WiFi.h#include PubSubClient.hU8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 2, /* data=*/ 0); // pin remapping with ESP8266 HW I2Cconst char* ssid = "SSID"; // ssidconst char* password = "PW"; // passwordconst char* mqtt_server = "192.168.X.X"; // mqtt serverconst char* inTopic = "/"; // topic esp will subscribe toconst char* clientId = "esp"; // id of the espWiFiClient espClient;PubSubClient client(espClient);long lastMsg = 0;char msg[50];int value = 0;void setup(){ u8g2.begin(); u8g2.enableUTF8Print(); Serial.begin(9600); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback);}void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(".");} 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("] "); for (int i = 0; i < length; i++) { payload[length] = '\0'; Serial.print((char)payload[i]);} Serial.println(); String message = String((char*)payload); if ((char)payload[0]) {// if ((char)payload[0] == '1') { u8g2.clearBuffer(); u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.setCursor(0, 24); u8g2.print(message);// u8g2.drawStr(0,24,"Turning ON"); u8g2.sendBuffer(); delay(5000); } else if ((char)payload[0] == '0') { u8g2.clearBuffer(); u8g2.print(message);// u8g2.drawStr(0,24,"Turning OFF"); u8g2.sendBuffer(); }}void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); if (client.connect(clientId)) { Serial.println("connected"); client.subscribe(inTopic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } }}void loop(){ if (!client.connected()) { reconnect(); } client.loop();}
Fantastic! I will have to give this a go for sure. Thanks for sharing all your efforts/code!
No worries, spam away my friend.
How i connect scl and sda to digital pins d1 or what i connect them to?
Yes you connect the OLEDs SCL/SDA to the SCL/SDA pins on the ESP. The pins differ depending on the ESP module you are using. An ESP-01 uses GPIO2 as SDA and GPIO0 as SCL. The nodemcu module uses D2 as SDA and D1 as SCL. Double check Google with your board and you should find a pinout.
I have found running an i2c scanner program on the ESP first to double check my connections to the screen helps me greatly before I get started.
Fantastic work! I really wanted to use my tiny esp8266-01 for a project using the OLED but was ready to give up. Just set everything up and it works great!