diff --git a/.travis.yml b/.travis.yml
index 1eb9c4566d2d2fa62ef3ac330fb63425bed27849..88a1e72ba590475a21d8f6e194ad3696fb9dfcb7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,8 @@ cache:
 env:
     - PLATFORMIO_CI_SRC=examples/SSD1306UiDemo
     - PLATFORMIO_CI_SRC=examples/SSD1306SimpleDemo
+    - PLATFORMIO_CI_SRC=examples/SSD1306DrawingDemo
+    - PLATFORMIO_CI_SRC=examples/SSD1306OTADemo
     - PLATFORMIO_CI_SRC=examples/SSD1306ClockDemo
 
 
diff --git a/OLEDDisplay.cpp b/OLEDDisplay.cpp
index 75cb6ffdc60b9334db0402b1ae03440fc6c4b759..e55683f3b19345add7bb7f93822adc882bac4b62 100644
--- a/OLEDDisplay.cpp
+++ b/OLEDDisplay.cpp
@@ -125,13 +125,13 @@ void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
 void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
   drawHorizontalLine(x, y, width);
   drawVerticalLine(x, y, height);
-  drawVerticalLine(x + width, y, height);
-  drawHorizontalLine(x, y + height, width);
+  drawVerticalLine(x + width - 1, y, height);
+  drawHorizontalLine(x, y + height - 1, width);
 }
 
 void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
-  for (int16_t i = yMove; i < yMove + height; i++) {
-    drawHorizontalLine(xMove, i, width);
+  for (int16_t x = xMove; x < xMove + width; x++) {
+    drawVerticalLine(x, yMove, height);
   }
 }
 
@@ -161,6 +161,46 @@ void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
   setPixel(x0, y0 - radius);
 }
 
+void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) {
+  int16_t x = 0, y = radius;
+  int16_t dp = 1 - radius;
+  while (x < y) {
+    if (dp < 0)
+      dp = dp + 2 * (++x) + 3;
+    else
+      dp = dp + 2 * (++x) - 2 * (--y) + 5;
+    if (quads & 0x1) {
+      setPixel(x0 + x, y0 - y);
+      setPixel(x0 + y, y0 - x);
+    }
+    if (quads & 0x2) {
+      setPixel(x0 - y, y0 - x);
+      setPixel(x0 - x, y0 - y);
+    }
+    if (quads & 0x4) {
+      setPixel(x0 - y, y0 + x);
+      setPixel(x0 - x, y0 + y);
+    }
+    if (quads & 0x8) {
+      setPixel(x0 + x, y0 + y);
+      setPixel(x0 + y, y0 + x);
+    }
+  }
+  if (quads & 0x1 && quads & 0x8) {
+    setPixel(x0 + radius, y0);
+  }
+  if (quads & 0x4 && quads & 0x8) {
+    setPixel(x0, y0 + radius);
+  }
+  if (quads & 0x2 && quads & 0x4) {
+    setPixel(x0 - radius, y0);
+  }
+  if (quads & 0x1 && quads & 0x2) {
+    setPixel(x0, y0 - radius);
+  }
+}
+
+
 void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
   int16_t x = 0, y = radius;
 	int16_t dp = 1 - radius;
@@ -215,7 +255,7 @@ void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
 }
 
 void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
-  if (x < 0 || x > DISPLAY_WIDTH) return;
+  if (x < 0 || x >= DISPLAY_WIDTH) return;
 
   if (y < 0) {
     length += y;
@@ -245,9 +285,9 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
     }
 
     switch (color) {
-      case WHITE:   *bufferPtr |= drawBit; break;
-      case BLACK:   *bufferPtr &= drawBit; break;
-      case INVERSE: *bufferPtr ^= drawBit; break;
+      case WHITE:   *bufferPtr |=  drawBit; break;
+      case BLACK:   *bufferPtr &= ~drawBit; break;
+      case INVERSE: *bufferPtr ^=  drawBit; break;
     }
 
     if (length < yOffset) return;
@@ -280,28 +320,31 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
   if (length > 0) {
     drawBit = (1 << (length & 7)) - 1;
     switch (color) {
-      case WHITE:   *bufferPtr |= drawBit; break;
-      case BLACK:   *bufferPtr &= drawBit; break;
-      case INVERSE: *bufferPtr ^= drawBit; break;
+      case WHITE:   *bufferPtr |=  drawBit; break;
+      case BLACK:   *bufferPtr &= ~drawBit; break;
+      case INVERSE: *bufferPtr ^=  drawBit; break;
     }
   }
 }
 
 void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
   uint16_t radius = height / 2;
-  uint16_t innerRadius = radius - 3;
-  setColor(WHITE);
-  drawCircle(x + radius, y + radius, radius);
-  drawRect(x+radius, y, width - 2*radius, height);
-  drawCircle(x + width - radius, y + radius, radius);
-  setColor(BLACK);
-  fillRect(x+radius, y+1, width - 2*radius + 1, height - 1);
+  uint16_t xRadius = x + radius;
+  uint16_t yRadius = y + radius;
+  uint16_t doubleRadius = 2 * radius;
+  uint16_t innerRadius = radius - 2;
+
   setColor(WHITE);
-  uint16_t maxProgressWidth = (width - 2 * radius) * progress / 100;
-  for (uint16_t i = 0; i < maxProgressWidth; i++) {
-    fillCircle(x + radius + i, y + radius, innerRadius);
-  }
+  drawCircleQuads(xRadius, yRadius, radius, 0b00000110);
+  drawHorizontalLine(xRadius, y, width - doubleRadius + 1);
+  drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
+  drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
+
+  uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100;
 
+  fillCircle(xRadius, yRadius, innerRadius);
+  fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
+  fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius);
 }
 
 void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) {
@@ -384,24 +427,24 @@ void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) {
   // char* text must be freed!
   char* text = utf8ascii(strUser);
 
-  uint16_t xOffset = 0;
+  uint16_t yOffset = 0;
   // If the string should be centered vertically too
   // we need to now how heigh the string is.
   if (textAlignment == TEXT_ALIGN_CENTER_BOTH) {
-    uint16_t lb;
+    uint16_t lb = 0;
     // Find number of linebreaks in text
-    for (uint16_t i=0, lb=0; text[i]; i++) {
-      lb += (text[i] == '\n');
+    for (uint16_t i=0;text[i] != 0; i++) {
+      lb += (text[i] == 10);
     }
     // Calculate center
-    xOffset = (lb * lineHeight) / 2;
+    yOffset = (lb * lineHeight) / 2;
   }
 
   uint16_t line = 0;
   char* textPart = strtok(text,"\n");
   while (textPart != NULL) {
     uint16_t length = strlen(textPart);
-    drawStringInternal(xMove - xOffset, yMove + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length));
+    drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length));
     textPart = strtok(NULL, "\n");
   }
   free(text);
@@ -690,13 +733,13 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
       if (yOffset >= 0) {
         switch (this->color) {
           case WHITE:   buffer[dataPos] |= currentByte << yOffset; break;
-          case BLACK:   buffer[dataPos] &= currentByte << yOffset; break;
+          case BLACK:   buffer[dataPos] &= ~(currentByte << yOffset); break;
           case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
         }
         if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_WIDTH)) {
           switch (this->color) {
             case WHITE:   buffer[dataPos + DISPLAY_WIDTH] |= currentByte >> (8 - yOffset); break;
-            case BLACK:   buffer[dataPos + DISPLAY_WIDTH] &= currentByte >> (8 - yOffset); break;
+            case BLACK:   buffer[dataPos + DISPLAY_WIDTH] &= ~(currentByte >> (8 - yOffset)); break;
             case INVERSE: buffer[dataPos + DISPLAY_WIDTH] ^= currentByte >> (8 - yOffset); break;
           }
         }
@@ -706,7 +749,7 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
 
         switch (this->color) {
           case WHITE:   buffer[dataPos] |= currentByte >> yOffset; break;
-          case BLACK:   buffer[dataPos] &= currentByte >> yOffset; break;
+          case BLACK:   buffer[dataPos] &= ~(currentByte >> yOffset); break;
           case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break;
         }
 
diff --git a/OLEDDisplay.h b/OLEDDisplay.h
index f6a27d7d8d07a732931bd2cb489a1b7fc76fdfb3..74bdba1c2e786e0e886ab7c41c66ea3fc6ef5837 100644
--- a/OLEDDisplay.h
+++ b/OLEDDisplay.h
@@ -139,6 +139,9 @@ class OLEDDisplay : public Print {
     // Draw the border of a circle
     void drawCircle(int16_t x, int16_t y, int16_t radius);
 
+    // Draw all Quadrants specified in the quads bit mask
+    void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads);
+
     // Fill circle
     void fillCircle(int16_t x, int16_t y, int16_t radius);
 
diff --git a/OLEDDisplayUi.cpp b/OLEDDisplayUi.cpp
index 5acc6eedcca015922d1e490c33e2e0565937e0e9..e78744299f6dbd0f6ef7155d6cef43208a0aa886 100644
--- a/OLEDDisplayUi.cpp
+++ b/OLEDDisplayUi.cpp
@@ -76,6 +76,14 @@ void OLEDDisplayUi::disableIndicator(){
   this->state.isIndicatorDrawen = false;
 }
 
+void OLEDDisplayUi::enableAllIndicators(){
+  this->shouldDrawIndicators = true;
+}
+
+void OLEDDisplayUi::disableAllIndicators(){
+  this->shouldDrawIndicators = false;
+}
+
 void OLEDDisplayUi::setIndicatorPosition(IndicatorPosition pos) {
   this->indicatorPosition = pos;
 }
@@ -220,7 +228,9 @@ void OLEDDisplayUi::tick() {
 
   this->display->clear();
   this->drawFrame();
-  this->drawIndicator();
+  if (shouldDrawIndicators) {
+    this->drawIndicator();
+  }
   this->drawOverlays();
   this->display->display();
 }
diff --git a/OLEDDisplayUi.h b/OLEDDisplayUi.h
index 77c46c75985471c62dde0f798cfece07315c4ed3..617346a3a2ede21c9f09a19a279aa89d4cbe8387 100644
--- a/OLEDDisplayUi.h
+++ b/OLEDDisplayUi.h
@@ -81,7 +81,7 @@ struct OLEDDisplayUiState {
   bool          isIndicatorDrawen         = true;
 
   // Normal = 1, Inverse = -1;
-  int8_t         frameTransitionDirection  = 1;
+  int8_t        frameTransitionDirection  = 1;
 
   bool          manuelControll            = false;
 
@@ -109,6 +109,8 @@ class OLEDDisplayUi {
     const char*         activeSymbol              = ANIMATION_activeSymbol;
     const char*         inactiveSymbol            = ANIMATION_inactiveSymbol;
 
+    bool                shouldDrawIndicators      = true;
+
     // Values for the Frames
     AnimationDirection  frameAnimationDirection   = SLIDE_RIGHT;
 
@@ -215,6 +217,16 @@ class OLEDDisplayUi {
      */
     void disableIndicator();
 
+    /**
+     * Enable drawing of indicators
+     */
+    void enableAllIndicators();
+
+    /**
+     * Disable draw of indicators.
+     */
+    void disableAllIndicators();
+
     /**
      * Set the position of the indicator bar.
      */
diff --git a/README.md b/README.md
index 6e60fc63c31e71c3a3b4cee911bb0ee8f9354350..a63d4ba8927a44ce6c8cefc3c36da7584791e66b 100644
--- a/README.md
+++ b/README.md
@@ -273,6 +273,16 @@ void enableIndicator();
  */
 void disableIndicator();
 
+/**
+ * Enable drawing of indicators
+ */
+void enableAllIndicator();
+
+/**
+ * Disable drawing of indicators.
+ */
+void disableAllIndicator();
+
 /**
  * Set the position of the indicator bar.
  */
@@ -375,3 +385,9 @@ This shows how to use define a maximum width after which the driver automaticall
 ![SPIVersion](https://github.com/neptune2/esp8266-oled-ssd1306/raw/master/resources/SPI_version.jpg)
 
 This shows the code working on the SPI version of the display. See demo code for ESP8266 pins used.
+
+## Project using this library
+
+ * [QRCode ESP8266](https://github.com/anunpanya/ESP8266_QRcode) (by @anunpanya)
+ * [Scan I2C](https://github.com/hallard/Scan-I2C-WiFi) (by @hallard)
+ * [Weather Station](https://github.com/squix78/esp8266-weather-station) (by @squix)
diff --git a/SH1106Brzo.h b/SH1106Brzo.h
index c1a89c474273becc9243547dee542687d9373eaa..385630b3267a7191fe0c81a21fe34d4b5de0a2e4 100644
--- a/SH1106Brzo.h
+++ b/SH1106Brzo.h
@@ -60,6 +60,8 @@ class SH1106Brzo : public OLEDDisplay {
        uint8_t minBoundY = ~0;
        uint8_t maxBoundY = 0;
 
+       uint8_t minBoundX = ~0;
+       uint8_t maxBoundX = 0;
        uint8_t x, y;
 
        // Calculate the Y bounding box of changes
@@ -70,6 +72,8 @@ class SH1106Brzo : public OLEDDisplay {
           if (buffer[pos] != buffer_back[pos]) {
             minBoundY = _min(minBoundY, y);
             maxBoundY = _max(maxBoundY, y);
+            minBoundX = _min(minBoundX, x);
+            maxBoundX = _max(maxBoundX, x);
           }
           buffer_back[pos] = buffer[pos];
         }
@@ -84,12 +88,18 @@ class SH1106Brzo : public OLEDDisplay {
        byte k = 0;
        uint8_t sendBuffer[17];
        sendBuffer[0] = 0x40;
+
+       // Calculate the colum offset 
+       uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
+       uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );
+
        brzo_i2c_start_transaction(this->_address, BRZO_I2C_SPEED);
+
        for (y = minBoundY; y <= maxBoundY; y++) {
          sendCommand(0xB0 + y);
-         sendCommand(0x02);
-         sendCommand(0x10);
-         for (x = 0; x < DISPLAY_WIDTH; x++) {
+         sendCommand(minBoundXp2H);
+         sendCommand(minBoundXp2L);
+         for (x = minBoundX; x <= maxBoundX; x++) {
              k++;
              sendBuffer[k] = buffer[x + y * DISPLAY_WIDTH];
              if (k == 16)  {
@@ -97,9 +107,15 @@ class SH1106Brzo : public OLEDDisplay {
                k = 0;
              }
          }
+         if (k != 0) {
+           brzo_i2c_write(sendBuffer, k + 1, true);
+           k = 0;
+         }
          yield();
        }
-       brzo_i2c_write(sendBuffer, k + 1, true);
+       if (k != 0) {
+         brzo_i2c_write(sendBuffer, k + 1, true);
+       }
        brzo_i2c_end_transaction();
      #else
      #endif
diff --git a/SH1106Spi.h b/SH1106Spi.h
new file mode 100644
index 0000000000000000000000000000000000000000..0a64e27568ff9fc1270e13ec0eec221ac9337a67
--- /dev/null
+++ b/SH1106Spi.h
@@ -0,0 +1,128 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 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.
+ *
+ * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
+ */
+
+#ifndef SH1106Spi_h
+#define SH1106Spi_h
+
+#include "OLEDDisplay.h"
+#include <SPI.h>
+
+class SH1106Spi : public OLEDDisplay {
+  private:
+      uint8_t             _rst;
+      uint8_t             _dc;
+
+  public:
+
+    SH1106Spi(uint8_t _rst, uint8_t _dc) {
+      this->_rst = _rst;
+      this->_dc  = _dc;
+    }
+
+    bool connect(){
+      pinMode(_dc, OUTPUT);
+      pinMode(_rst, OUTPUT);
+
+      SPI.begin ();
+      SPI.setClockDivider (SPI_CLOCK_DIV2);
+
+      // Pulse Reset low for 10ms
+      digitalWrite(_rst, HIGH);
+      delay(1);
+      digitalWrite(_rst, LOW);
+      delay(10);
+      digitalWrite(_rst, HIGH);
+      return true;
+    }
+
+    void display(void) {
+    #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+       uint8_t minBoundY = ~0;
+       uint8_t maxBoundY = 0;
+
+       uint8_t minBoundX = ~0;
+       uint8_t maxBoundX = 0;
+
+       uint8_t x, y;
+
+       // Calculate the Y bounding box of changes
+       // and copy buffer[pos] to buffer_back[pos];
+       for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
+         for (x = 0; x < DISPLAY_WIDTH; x++) {
+          uint16_t pos = x + y * DISPLAY_WIDTH;
+          if (buffer[pos] != buffer_back[pos]) {
+            minBoundY = _min(minBoundY, y);
+            maxBoundY = _max(maxBoundY, y);
+            minBoundX = _min(minBoundX, x);
+            maxBoundX = _max(maxBoundX, x);
+          }
+          buffer_back[pos] = buffer[pos];
+        }
+        yield();
+       }
+
+       // If the minBoundY wasn't updated
+       // we can savely assume that buffer_back[pos] == buffer[pos]
+       // holdes true for all values of pos
+       if (minBoundY == ~0) return;
+
+       // Calculate the colum offset
+       uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
+       uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );
+
+       for (y = minBoundY; y <= maxBoundY; y++) {
+         sendCommand(0xB0 + y);
+         sendCommand(minBoundXp2H);
+         sendCommand(minBoundXp2L);
+         digitalWrite(_dc, HIGH);   // data mode
+         for (x = minBoundX; x <= maxBoundX; x++) {
+           SPI.transfer(buffer[x + y * DISPLAY_WIDTH]);
+         }
+         yield();
+       }
+     #else
+      for (uint8_t y=0; y<DISPLAY_HEIGHT/8; y++) {
+        sendCommand(0xB0 + y);
+        sendCommand(0x02);
+        sendCommand(0x10);
+        digitalWrite(_dc, HIGH);   // data mode
+        for( uint8_t x=0; x < DISPLAY_WIDTH; x++) {
+          SPI.transfer(buffer[x + y * DISPLAY_WIDTH]);
+        }
+        yield();
+      }
+     #endif
+    }
+
+  private:
+    inline void sendCommand(uint8_t com) __attribute__((always_inline)){
+      digitalWrite(_dc, LOW);
+      SPI.transfer(com);
+    }
+};
+
+#endif
diff --git a/SH1106Wire.h b/SH1106Wire.h
index d885fab38e049b070d0f40e0292292d98c72d391..f0784b9423051a4e91bf2e237b38347a2f6b6ede 100644
--- a/SH1106Wire.h
+++ b/SH1106Wire.h
@@ -62,6 +62,10 @@ class SH1106Wire : public OLEDDisplay {
       #ifdef OLEDDISPLAY_DOUBLE_BUFFER
         uint8_t minBoundY = ~0;
         uint8_t maxBoundY = 0;
+
+        uint8_t minBoundX = ~0;
+        uint8_t maxBoundX = 0;
+
         uint8_t x, y;
 
         // Calculate the Y bounding box of changes
@@ -72,6 +76,8 @@ class SH1106Wire : public OLEDDisplay {
            if (buffer[pos] != buffer_back[pos]) {
              minBoundY = _min(minBoundY, y);
              maxBoundY = _max(maxBoundY, y);
+             minBoundX = _min(minBoundX, x);
+             maxBoundX = _max(maxBoundX, x);
            }
            buffer_back[pos] = buffer[pos];
          }
@@ -83,12 +89,16 @@ class SH1106Wire : public OLEDDisplay {
         // holdes true for all values of pos
         if (minBoundY == ~0) return;
 
+        // Calculate the colum offset
+        uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
+        uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );
+
         byte k = 0;
         for (y = minBoundY; y <= maxBoundY; y++) {
           sendCommand(0xB0 + y);
-          sendCommand(0x02);
-          sendCommand(0x10);
-          for (x = 0; x < DISPLAY_WIDTH; x++) {
+          sendCommand(minBoundXp2H);
+          sendCommand(minBoundXp2L);
+          for (x = minBoundX; x <= maxBoundX; x++) {
             if (k == 0) {
               Wire.beginTransmission(_address);
               Wire.write(0x40);
@@ -100,6 +110,10 @@ class SH1106Wire : public OLEDDisplay {
               k = 0;
             }
           }
+          if (k != 0)  {
+            Wire.endTransmission();
+            k = 0;
+          }
           yield();
         }
 
diff --git a/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino b/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino
index d9b5c1a4a2849d26c501cec9c306ea9ef41255db..e9db7d645a610f8c42d857ba20a774b2fe9cd89e 100644
--- a/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino
+++ b/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino
@@ -24,19 +24,21 @@
  *
  */
 
-#include <Wire.h>
 #include <TimeLib.h>
 
 // Include the correct display library
 // For a connection via I2C using Wire include
 #include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
 #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
+// or #include "SH1106.h" alis for `#include "SH1106Wire.h"`
 // For a connection via I2C using brzo_i2c (must be installed) include
 // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
 // #include "SSD1306Brzo.h"
+// #include "SH1106Brzo.h"
 // For a connection via SPI include
 // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
 // #include "SSD1306Spi.h"
+// #include "SH1106SPi.h"
 
 // Include the UI lib
 #include "OLEDDisplayUi.h"
@@ -53,14 +55,19 @@
 // D2 -> DC
 // D8 -> CS
 // SSD1306Spi        display(D0, D2, D8);
+// or
+// SH1106Spi         display(D0, D2);
 
 // Initialize the OLED display using brzo_i2c
 // D3 -> SDA
-// D4 -> SCL
+// D5 -> SCL
 // SSD1306Brzo display(0x3c, D3, D5);
+// or
+// SH1106Brzo  display(0x3c, D3, D5);
 
 // Initialize the OLED display using Wire library
 SSD1306  display(0x3c, D3, D5);
+// SH1106 display(0x3c, D3, D5);
 
 OLEDDisplayUi ui ( &display );
 
diff --git a/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino
new file mode 100644
index 0000000000000000000000000000000000000000..cf37fb0412002492388ed3d71fbb1ec58866c233
--- /dev/null
+++ b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino
@@ -0,0 +1,229 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 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.
+ *
+ */
+
+ // Include the correct display library
+ // For a connection via I2C using Wire include
+ #include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
+ #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
+ // or #include "SH1106.h" alis for `#include "SH1106Wire.h"`
+ // For a connection via I2C using brzo_i2c (must be installed) include
+ // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
+ // #include "SSD1306Brzo.h"
+ // #include "SH1106Brzo.h"
+ // For a connection via SPI include
+ // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
+ // #include "SSD1306Spi.h"
+ // #include "SH1106SPi.h"
+
+ // Use the corresponding display class:
+
+ // Initialize the OLED display using SPI
+ // D5 -> CLK
+ // D7 -> MOSI (DOUT)
+ // D0 -> RES
+ // D2 -> DC
+ // D8 -> CS
+ // SSD1306Spi        display(D0, D2, D8);
+ // or
+ // SH1106Spi         display(D0, D2);
+
+ // Initialize the OLED display using brzo_i2c
+ // D3 -> SDA
+ // D5 -> SCL
+ // SSD1306Brzo display(0x3c, D3, D5);
+ // or
+ // SH1106Brzo  display(0x3c, D3, D5);
+
+ // Initialize the OLED display using Wire library
+ SSD1306  display(0x3c, D3, D5);
+ // SH1106 display(0x3c, D3, D5);
+
+// Adapted from Adafruit_SSD1306
+void drawLines() {
+  for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) {
+    display.drawLine(0, 0, i, DISPLAY_HEIGHT-1);
+    display.display();
+    delay(10);
+  }
+  for (int16_t i=0; i<DISPLAY_HEIGHT; i+=4) {
+    display.drawLine(0, 0, DISPLAY_WIDTH-1, i);
+    display.display();
+    delay(10);
+  }
+  delay(250);
+
+  display.clear();
+  for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) {
+    display.drawLine(0, DISPLAY_HEIGHT-1, i, 0);
+    display.display();
+    delay(10);
+  }
+  for (int16_t i=DISPLAY_HEIGHT-1; i>=0; i-=4) {
+    display.drawLine(0, DISPLAY_HEIGHT-1, DISPLAY_WIDTH-1, i);
+    display.display();
+    delay(10);
+  }
+  delay(250);
+
+  display.clear();
+  for (int16_t i=DISPLAY_WIDTH-1; i>=0; i-=4) {
+    display.drawLine(DISPLAY_WIDTH-1, DISPLAY_HEIGHT-1, i, 0);
+    display.display();
+    delay(10);
+  }
+  for (int16_t i=DISPLAY_HEIGHT-1; i>=0; i-=4) {
+    display.drawLine(DISPLAY_WIDTH-1, DISPLAY_HEIGHT-1, 0, i);
+    display.display();
+    delay(10);
+  }
+  delay(250);
+  display.clear();
+  for (int16_t i=0; i<DISPLAY_HEIGHT; i+=4) {
+    display.drawLine(DISPLAY_WIDTH-1, 0, 0, i);
+    display.display();
+    delay(10);
+  }
+  for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) {
+    display.drawLine(DISPLAY_WIDTH-1, 0, i, DISPLAY_HEIGHT-1);
+    display.display();
+    delay(10);
+  }
+  delay(250);
+}
+
+// Adapted from Adafruit_SSD1306
+void drawRect(void) {
+  for (int16_t i=0; i<DISPLAY_HEIGHT/2; i+=2) {
+    display.drawRect(i, i, DISPLAY_WIDTH-2*i, DISPLAY_HEIGHT-2*i);
+    display.display();
+    delay(10);
+  }
+}
+
+// Adapted from Adafruit_SSD1306
+void fillRect(void) {
+  uint8_t color = 1;
+  for (int16_t i=0; i<DISPLAY_HEIGHT/2; i+=3) {
+    display.setColor((color % 2 == 0) ? BLACK : WHITE); // alternate colors
+    display.fillRect(i, i, DISPLAY_WIDTH - i*2, DISPLAY_HEIGHT - i*2);
+    display.display();
+    delay(10);
+    color++;
+  }
+  // Reset back to WHITE
+  display.setColor(WHITE);
+}
+
+// Adapted from Adafruit_SSD1306
+void drawCircle(void) {
+  for (int16_t i=0; i<DISPLAY_HEIGHT; i+=2) {
+    display.drawCircle(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, i);
+    display.display();
+    delay(10);
+  }
+  delay(1000);
+  display.clear();
+
+  // This will draw the part of the circel in quadrant 1
+  // Quadrants are numberd like this:
+  //   0010 | 0001
+  //  ------|-----
+  //   0100 | 1000
+  //
+  display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000001);
+  display.display();
+  delay(200);
+  display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000011);
+  display.display();
+  delay(200);
+  display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000111);
+  display.display();
+  delay(200);
+  display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00001111);
+  display.display();
+}
+
+void printBuffer(void) {
+  // Initialize the log buffer
+  // allocate memory to store 8 lines of text and 30 chars per line.
+  display.setLogBuffer(5, 30);
+
+  // Some test data
+  const char* test[] = {
+      "Hello",
+      "World" ,
+      "----",
+      "Show off",
+      "how",
+      "the log buffer",
+      "is",
+      "working.",
+      "Even",
+      "scrolling is",
+      "working"
+  };
+
+  for (uint8_t i = 0; i < 11; i++) {
+    display.clear();
+    // Print to the screen
+    display.println(test[i]);
+    // Draw it to the internal screen buffer
+    display.drawLogBuffer(0, 0);
+    // Display it on the screen
+    display.display();
+    delay(500);
+  }
+}
+
+void setup() {
+  display.init();
+
+  // display.flipScreenVertically();
+
+  display.setContrast(255);
+
+  drawLines();
+  delay(1000);
+  display.clear();
+
+  drawRect();
+  delay(1000);
+  display.clear();
+
+  fillRect();
+  delay(1000);
+  display.clear();
+
+  drawCircle();
+  delay(1000);
+  display.clear();
+
+  printBuffer();
+  delay(1000);
+  display.clear();
+}
+
+void loop() { }
diff --git a/examples/SSD1306OTADemo/SSD1306OTADemo.ino b/examples/SSD1306OTADemo/SSD1306OTADemo.ino
new file mode 100644
index 0000000000000000000000000000000000000000..6460ff9e4a308dffa396d0db473c6708e0c14f34
--- /dev/null
+++ b/examples/SSD1306OTADemo/SSD1306OTADemo.ino
@@ -0,0 +1,119 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 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.
+ *
+ */
+
+// WiFi includes
+ #include <ESP8266WiFi.h>
+
+ // OTA Includes
+ #include <ESP8266mDNS.h>
+ #include <ArduinoOTA.h>
+
+ const char *ssid         = "[Your SSID]";
+ const char *password     = "[Your Password]";
+
+
+// Include the correct display library
+// For a connection via I2C using Wire include
+#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
+#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
+// or #include "SH1106.h" alis for `#include "SH1106Wire.h"`
+// For a connection via I2C using brzo_i2c (must be installed) include
+// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
+// #include "SSD1306Brzo.h"
+// #include "SH1106Brzo.h"
+// For a connection via SPI include
+// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
+// #include "SSD1306Spi.h"
+// #include "SH1106SPi.h"
+
+// Use the corresponding display class:
+
+// Initialize the OLED display using SPI
+// D5 -> CLK
+// D7 -> MOSI (DOUT)
+// D0 -> RES
+// D2 -> DC
+// D8 -> CS
+// SSD1306Spi        display(D0, D2, D8);
+// or
+// SH1106Spi         display(D0, D2);
+
+// Initialize the OLED display using brzo_i2c
+// D3 -> SDA
+// D5 -> SCL
+// SSD1306Brzo display(0x3c, D3, D5);
+// or
+// SH1106Brzo  display(0x3c, D3, D5);
+
+// Initialize the OLED display using Wire library
+SSD1306  display(0x3c, D3, D5);
+// SH1106 display(0x3c, D3, D5);
+
+
+void setup() {
+  WiFi.begin ( ssid, password );
+
+  // Wait for connection
+  while ( WiFi.status() != WL_CONNECTED ) {
+    delay ( 10 );
+  }
+
+  display.init();
+  display.flipScreenVertically();
+  display.setContrast(255);
+
+  ArduinoOTA.begin();
+  ArduinoOTA.onStart([]() {
+    display.clear();
+    display.setFont(ArialMT_Plain_10);
+    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
+    display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2 - 10, "OTA Update");
+    display.display();
+  });
+
+  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+    display.drawProgressBar(4, 32, 120, 8, progress / (total / 100) );
+    display.display();
+  });
+
+  ArduinoOTA.onEnd([]() {
+    display.clear();
+    display.setFont(ArialMT_Plain_10);
+    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
+    display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, "Restart");
+    display.display();
+  });
+
+  // Align text vertical/horizontal center
+  display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
+  display.setFont(ArialMT_Plain_10);
+  display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, "Ready for OTA:\n" + WiFi.localIP().toString());
+  display.display();
+}
+
+void loop() {
+  ArduinoOTA.handle();
+}
diff --git a/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino b/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino
index 97594b95c3808ff30e459798a05e77f17fd557f5..ed7401915861f89d9a1f4dd6f697bc82b44f3069 100644
--- a/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino
+++ b/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino
@@ -23,24 +23,23 @@
  *
  */
 
-#include <Wire.h>
-
 // Include the correct display library
 // For a connection via I2C using Wire include
 #include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
 #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
+// or #include "SH1106.h" alis for `#include "SH1106Wire.h"`
 // For a connection via I2C using brzo_i2c (must be installed) include
 // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
 // #include "SSD1306Brzo.h"
+// #include "SH1106Brzo.h"
 // For a connection via SPI include
 // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
 // #include "SSD1306Spi.h"
+// #include "SH1106SPi.h"
 
 // Include custom images
 #include "images.h"
 
-// Use the corresponding display class:
-
 // Initialize the OLED display using SPI
 // D5 -> CLK
 // D7 -> MOSI (DOUT)
@@ -48,14 +47,19 @@
 // D2 -> DC
 // D8 -> CS
 // SSD1306Spi        display(D0, D2, D8);
+// or
+// SH1106Spi         display(D0, D2);
 
 // Initialize the OLED display using brzo_i2c
 // D3 -> SDA
-// D4 -> SCL
+// D5 -> SCL
 // SSD1306Brzo display(0x3c, D3, D5);
+// or
+// SH1106Brzo  display(0x3c, D3, D5);
 
 // Initialize the OLED display using Wire library
 SSD1306  display(0x3c, D3, D5);
+// SH1106 display(0x3c, D3, D5);
 
 
 #define DEMO_DURATION 3000
diff --git a/examples/SSD1306UiDemo/SSD1306UiDemo.ino b/examples/SSD1306UiDemo/SSD1306UiDemo.ino
index a51c57c6380a05785badda4d4dfc39dd90570502..31357569ff3849b6c1098165aa96f9880129327f 100644
--- a/examples/SSD1306UiDemo/SSD1306UiDemo.ino
+++ b/examples/SSD1306UiDemo/SSD1306UiDemo.ino
@@ -24,18 +24,19 @@
  *
  */
 
-#include <Wire.h>
-
-// Include the correct display library
-// For a connection via I2C using Wire include
-#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
-#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
-// For a connection via I2C using brzo_i2c (must be installed) include
-// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
-// #include "SSD1306Brzo.h"
-// For a connection via SPI include
-// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
-// #include "SSD1306Spi.h"
+ // Include the correct display library
+ // For a connection via I2C using Wire include
+ #include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
+ #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
+ // or #include "SH1106.h" alis for `#include "SH1106Wire.h"`
+ // For a connection via I2C using brzo_i2c (must be installed) include
+ // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
+ // #include "SSD1306Brzo.h"
+ // #include "SH1106Brzo.h"
+ // For a connection via SPI include
+ // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
+ // #include "SSD1306Spi.h"
+ // #include "SH1106SPi.h"
 
 // Include the UI lib
 #include "OLEDDisplayUi.h"
@@ -52,14 +53,19 @@
 // D2 -> DC
 // D8 -> CS
 // SSD1306Spi        display(D0, D2, D8);
+// or
+// SH1106Spi         display(D0, D2);
 
 // Initialize the OLED display using brzo_i2c
 // D3 -> SDA
-// D4 -> SCL
+// D5 -> SCL
 // SSD1306Brzo display(0x3c, D3, D5);
+// or
+// SH1106Brzo  display(0x3c, D3, D5);
 
 // Initialize the OLED display using Wire library
 SSD1306  display(0x3c, D3, D5);
+// SH1106 display(0x3c, D3, D5);
 
 OLEDDisplayUi ui     ( &display );