ESP-01, MQTT and an OLED (SSD1306)

OLED ScreenIt 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]

 

 https://gist.github.com/jhaury/96f24de0e55e777d000813caef37bf79

 

10 Comments

  1. Doo
    August 19, 2017 / 9:47 am

    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!)

    • justin
      Author
      August 19, 2017 / 10:33 am

      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!

      • Doo
        August 19, 2017 / 3:12 pm

        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.

  2. justin
    Author
    August 19, 2017 / 10:37 am

    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.

    • Doo
      August 19, 2017 / 10:40 am

      Awesome thanks I’ll give it a shot!

  3. Doo
    August 20, 2017 / 2:30 pm

    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!

  4. Doo
    August 20, 2017 / 6:10 pm

    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.h

    U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 2, /* data=*/ 0); // pin remapping with ESP8266 HW I2C

    const char* ssid = "SSID"; // ssid
    const char* password = "PW"; // password
    const char* mqtt_server = "192.168.X.X"; // mqtt server
    const char* inTopic = "/"; // topic esp will subscribe to
    const char* clientId = "esp"; // id of the esp

    WiFiClient 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();
    }

    • justin
      Author
      August 20, 2017 / 7:48 pm

      Fantastic! I will have to give this a go for sure. Thanks for sharing all your efforts/code!

      No worries, spam away my friend.

    • swegamerheregamer
      November 13, 2017 / 12:07 am

      How i connect scl and sda to digital pins d1 or what i connect them to?

      • justin
        Author
        November 14, 2017 / 7:12 pm

        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.

Leave a Reply

%d bloggers like this: