OLED Display and ESP8266 
     All Displays

Where to get:



https://www.aliexpress.com

Library

esp8266-oled-ssd1306

https://github.com/ThingPulse/esp8266-oled-ssd1306

Documentation

In the README.md file included with the library.

README.md

Get IIC Address



/*
* i2c_port_address_scanner
* Scans ports D0 to D7 on an ESP8266 and searches for I2C device. based on the original
* code available on Arduino.cc and later improved by user Krodal and Nick Gammon
* (www.gammon.com.au/forum/?id=10896)
* D8 throws exceptions thus it has been left out
*
*/

#include <Wire.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\n\nI2C Scanner to scan for devices on each port pair D0 to D7");
  scanPorts();
}

uint8_t portArray[] = {16, 5, 4, 0, 2, 14, 12, 13};
String portMap[] = {"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7"}; //for Wemos
//String portMap[] = {"GPIO16", "GPIO5", "GPIO4", "GPIO0", "GPIO2", "GPIO14", "GPIO12", "GPIO13"};

void scanPorts() {
  for (uint8_t i = 0; i < sizeof(portArray); i++) {
    for (uint8_t j = 0; j < sizeof(portArray); j++) {
      if (i != j){
        Serial.print("Scanning (SDA : SCL) - " + portMap[i] + " : " + portMap[j] + " - ");
        Wire.begin(portArray[i], portArray[j]);
        check_if_exist_I2C();
      }
    }
  }
}

void check_if_exist_I2C() {
  byte error, address;
  int nDevices;
  nDevices = 0;
  for (address = 1; address < 127; address++ )  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0){
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    } else if (error == 4) {
      Serial.print("Unknow error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  } //for loop

  if (nDevices == 0)
    Serial.println("No I2C devices found");
  else
    Serial.println("**********************************\n");
  //delay(1000);           // wait 1 seconds for next scan, did not find it necessary
}

void loop() {
}


...

Scanning (SDA : SCL) - D2 : D7 - No I2C devices found
Scanning (SDA : SCL) - D3 : D0 - No I2C devices found
Scanning (SDA : SCL) - D3 : D1 - No I2C devices found
Scanning (SDA : SCL) - D3 : D2 - No I2C devices found
Scanning (SDA : SCL) - D3 : D4 - No I2C devices found
Scanning (SDA : SCL) - D3 : D5 - I2C device found at address 0x3C  !
**********************************
 
Scanning (SDA : SCL) - D3 : D6 - No I2C devices found
Scanning (SDA : SCL) - D3 : D7 - No I2C devices found
Scanning (SDA : SCL) - D4 : D0 - No I2C devices found
Scanning (SDA : SCL) - D4 : D1 - No I2C devices found

...

Demo Code

/*
  The MIT License (MIT)
  Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
  Copyright (c) 2018 by Fabrice Weinberg
   See complete copyright notice at the bottom of the file

  Modified from the demo program by the above authors by Deid Reimer (Jan 2019) to:
    - Simplify to the specific application
    - Add wifi and web server
    - Add temperature and voltage
    - Add request and display Murphy saying e.g.:
        "Real programmers don't comment their code.  If it was hard to write it should
         be hard to understand."

*/
//  Include wifi web server and web client libraries
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>

// Include DS18B20 temperature sensor libraries.
#include <OneWire.h>
#include <DallasTemperature.h>

// Include the display library and custom images
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
#include "images.h"

// Definitions and initialization

// Read battery voltage on ADC.
ADC_MODE(ADC_VCC);

// Temperature data wire is connected to D6/GPIO 12
#define ONE_WIRE_BUS D6

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// and pass our oneWire instance reference to the Dallas Temperature routine
DallasTemperature DS18B20(&oneWire);

// Create variables to hold the temperature and voltage measurements
char temperatureCString[8];
char voltageCString[8];

// Create a variable type to hold the display function addresses
typedef void (*Demo)(void);

//  Delay time.  This will be changed by each display function.
int delayNow = 5;

// Which of the n functions is current
int demoMode = 0;

// Text from the web form
String inputText;

//  Which of the several display lists choosen by >>... is current
int displayType = 2;

// Break out of delay loop when true.
bool doBreak = false;

// Instantiate and tell the web server to listen on port 80
ESP8266WebServer server(80);

// Initialize the OLED display using Wire library
// 0x3C is the display address
// D3 is SDA - data line
// D5 is SCL - clock line
SSD1306Wire  display(0x3c, D3, D5);



// -----------------------------------------
// Wifi and web functions

// Convert IP to String.
String ipToString(IPAddress ip) {
  String ips = String(ip[0]) + "." + String(ip[1]) + "." + String(ip[2]) + "." + String(ip[3]);
  return ips;

// Function to request an IP address.
bool getIP(IPAddress ip, IPAddress gateway, IPAddress subnet, char* ssid, char* password) {

  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);

  WiFi.disconnect();
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Loop until a connection or 20 tries
  int j = 0;
  while (WiFi.status() != WL_CONNECTED and j < 20) {
    delay(500);
    Serial.print(j);
    Serial.println(ssid);
    display.clear();
    display.drawString(0, 0, String(j));
    display.drawString(0, 20, ssid);
    display.display();
    j++;
  }

  // Display the connection information if connected and return status
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    display.clear();
    display.drawString(0, 0, "IP address: ");
    display.drawString(0, 15, ipToString(WiFi.localIP()));

    Serial.print("Connected to ");
    Serial.println(ssid);

    display.drawString(0, 30, "Connected to");
    display.drawString(0, 45, ssid);

    display.display();
    delay(10000);
    return true;
  } else {
    return false;
  }
}

// Function to build amd display the web page.
void showPage() {
  String webPage00 = "<html><head><meta charset=\"UTF-8\"><meta name=viewport content=\"width=device-width, initial-scale=1.5\"><title>OLDisplay</title>";
  String webPage000 = "<meta name = \"viewport\" content = \"width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0\">";
  String webPage01 = "</head><body>";
  String webPage0 = "<h3>Message for OLED ...</h3>";
  String webPage02 = "<FORM METHOD=\"get\" action=\"/getForm\"> <input type=\"text\" name=\"getText\">";
  String webPage03 = "<input type=\"submit\" value=\"Submit\"></form>" ;
  String webPage99 = "</body></html>";

  String webPage =  webPage00 + webPage000 + webPage01 + webPage0 + webPage02 + webPage03 + webPage99;
  server.send(200, "text/html", webPage);
  Serial.println("sent new page");
  delay(2000);
}

// Function to get the data from the web form

void handleForm() {
  showPage();
  doBreak = true;
  String formText  = server.arg("getText");
  if (formText.length() >=150) {
    formText = formText.substring(0,149);
  }
  // Check for short/long command, or just new text.
  if (formText == ">>Short") {
    displayType = 1;
    demoMode = 0;
  } else if (formText == ">>Long") {
    displayType = 2;
    demoMode = 0;
  } else if (formText == ">>Rand") {
    displayType = 3;
    demoMode = 0; 
  } else {
    inputText = formText;
    demoMode = 1;
  }
  Serial.println("Text received. Contents: ");
  Serial.println(formText);
  Serial.println(inputText);
  delay(2);
}

// ------------------------------------------------------------
// Oled display functions

Demo longDemos[] = {drawTempVolt, drawFontFaceDemo, drawTextFlowDemo, drawMurphy, drawTextAlignmentDemo, drawRectDemo, drawCircleDemo, drawProgressBarDemo, drawImageDemo};
Demo shortDemos[] = {drawTempVolt, drawTextFlowDemo};
Demo randDemos[] = {drawTempVolt, drawMurphy};
int longDemoLength = (sizeof(longDemos) / sizeof(Demo));
int shortDemoLength = (sizeof(shortDemos) / sizeof(Demo));
int randDemoLength = (sizeof(randDemos) / sizeof(Demo));

//Get and display a murphy saying
void drawMurphy() {
  HTTPClient http;
  http.begin("http://drsol.com/~deid/murphy/murphy.php");
  int stat = http.GET();
  if (stat > 0) {
    String text = http.getString();
    delayNow = 10;
    display.setFont(ArialMT_Plain_10);
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.drawStringMaxWidth(0, 0, 128, text);
  } else {
    display.setFont(ArialMT_Plain_16);
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.drawStringMaxWidth(0, 0, 128, "Oops - No Web!");
  }
  http.end();
}

// Display temperature and voltage.
void drawTempVolt() {
  delayNow = 3;
  float tempC;
  int battVolt;
  //float tempF;

  // Loop until the temperature is on out of range
  do {
    DS18B20.requestTemperatures();
    tempC = DS18B20.getTempCByIndex(0);

    delay(1000);
  } while (tempC == (-127.0));
  tempC = tempC + 1;
  dtostrf(tempC, 6, 2, temperatureCString);
  //  tempF = DS18B20.getTempFByIndex(0);
  //  dtostrf(tempF, 6, 2, temperatureFString)
  String t = temperatureCString;

  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, t + " C");

  int voltage = analogRead(A0);
  float v = voltage / 65536.0 * 3.3;
  Serial.println (v);
  display.drawString(16, 18, String(v) + " V");
}

// Display different font sizes
void drawFontFaceDemo() {
  delayNow = 5;
  // create more fonts at http://oleddisplay.squix.ch/
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Hello PiMakers");
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 10, "Hello World");
  display.setFont(ArialMT_Plain_24);
  display.drawString(0, 26, "Nice Day!");
}

// Display the text retrieved from the "web"
void drawTextFlowDemo() {
  delayNow = 9;
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawStringMaxWidth(0, 0, 128, inputText);
}

// Display text in different horizontal alignments
void drawTextAlignmentDemo() {
  delayNow = 5;
  // Text alignment demo
  display.setFont(ArialMT_Plain_10);

  // The coordinates define the left starting point of the text
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0, 10, "Left aligned (0,10)");

  // The coordinates define the center of the text
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.drawString(64, 22, "Center aligned (64,22)");

  // The coordinates define the right end of the text
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString(128, 33, "Right aligned (128,33)");
}

// Display drawing on the screen - a rectangle.
void drawRectDemo() {
  delayNow = 5;
  // Draw a pixel at given position
  for (int i = 0; i < 10; i++) {
    display.setPixel(i, i);
    display.setPixel(10 - i, i);
  }
  display.drawRect(12, 12, 20, 20);

  // Fill the rectangle
  display.fillRect(14, 14, 17, 17);

  // Draw a line horizontally
  display.drawHorizontalLine(0, 40, 20);

  // Draw a line vertically
  display.drawVerticalLine(40, 0, 20);
}

// Display a couple of circles.
void drawCircleDemo() {
  delayNow = 5;
  for (int i = 1; i < 8; i++) {
    display.setColor(WHITE);
    display.drawCircle(32, 32, i * 3);
    if (i % 2 == 0) {
      display.setColor(BLACK);
    }
    display.fillCircle(96, 32, 32 - i * 3);
  }
}

// Display a progress bar
void drawProgressBarDemo() {
  int counter = 1;
  int progress;
  delayNow = 0;
  while (counter < 100) {
    display.clear();
    progress = (counter) % 100;
    // draw the progress bar
    display.drawProgressBar(0, 32, 120, 10, progress);
    // draw the percentage as String
    display.setTextAlignment(TEXT_ALIGN_CENTER);
    display.drawString(64, 15, String(progress) + "%");
    display.display();
    // Count for the progress bar
    counter++;
    delay(60);
    Serial.println(counter);
  }
}

// Display an image.
void drawImageDemo() {
  delayNow = 5;
  // see http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html
  // on how to create xbm files
  // display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
  display.drawXbm(34, 14, noobs_width, noobs_height, noobs_bits);
}

// -----------------------------------------------------------
// Setup
void setup() {
  // Reserve space for the web form input variable
  inputText.reserve(150);
  inputText = "There is nothing to see here yet";

  // Set up serial interface
  Serial.begin(9600);
  Serial.println();

  // Initialise the UI, this will init the display too.
  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);
  delay(500);

  //  Connect to WiFi.   Try each Access Point below and give up if none.
  WiFi.mode(WIFI_STA);
  //bool stat = getIP ({0,0,0,0},{0,0,0,0},{0,0,0,0}, "Steele", "Piwehavelotsof.");
  bool stat = getIP ({10, 10, 45, 10}, {10, 10, 45, 254}, {255, 255, 255, 0}, "Steele", "verysecret");
  if (!stat) {
    Serial.println("try makiki");
    stat = getIP ({0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, "Makiki", "secret");
  } if (!stat) {
    Serial.println("try lalala6");
    stat = getIP ({192, 168, 78, 39}, {192, 168, 78, 1}, {255, 255, 255, 0}, "lalala6", "mostlysecret");
  } if (!stat) {
    Serial.println("try lalala");
    stat = getIP ({192, 168, 0, 39}, {192, 168, 0, 1}, {255, 255, 255, 0}, "lalala", "hopefully secret");
  }

  if (!stat) {
    // Continue without an an internet connection.
    Serial.println("Continuing without IP");
    display.clear();
    display.drawString(0, 10, "No IP");
    display.display();
    delay(5000);
  }

  // Start the web server.
  server.begin();

  // Set up the responder for the web request.
  server.on("/getForm", handleForm);
  server.on("/", showPage);
  //server.onNotFound(showPage);
}


//-----------------------------------
// Loop
void loop() {
  // Look for and handle a web request.
  server.handleClient();

  // Create a display and show it.
  display.clear();
  // Choose which set of displays to run one of.
  if ( displayType == 1) {
    shortDemos[demoMode]();
    demoMode = (demoMode + 1)  % shortDemoLength;
  } else if (displayType == 2) {
    longDemos[demoMode]();
    demoMode = (demoMode + 1)  % longDemoLength;
  } else if (displayType == 3) {
    randDemos[demoMode]();
    demoMode = (demoMode +1) % randDemoLength;
  } 
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.display();

  // Delay for a while, but break up the delay so that web requests are handled
  // in a reasonable length of time
  int delaySlice = delayNow * 100;
  int j = 0;
  while (++j <= 10) {
    server.handleClient();
    delay(delaySlice);
    if (doBreak) {
      doBreak = false;
      break;
    }
  }
}

/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
   Copyright (c) 2018 by Fabrice Weinberg

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

Then I added Time: