SSD1306 / SH1106 OLED display

Overview

ManufacturerSolomon systech
NameSSD1306 or SH1106
DatasheetSSD1306.pdf
AdafruitMonochrome OLED breakouts, adafruit/Adafruit_SSD1306
Arduino referenceAdafruit SSD1306
ESPHome componentssd1306_i2c1 and display2
ESPHome configpackages/displays/ssd1306.yml3
Supply voltage, some breakout boards also support .

These OLED displays have two different chipsets -- the more comon SSD1306 or SH1106 which seems to be more common on the larger 1.3" models.

ESPHome config

Note

Both the SSD1306 and SH1106 displays are available with either I²C or SPI interfaces. But all of mine have I²C interfaces so this page only talks about the ssd1306_i2c component.

Using a display with an SPI interface should be very similar, apart from using the spi component instead of the i2c component.

For more info, see the [ssd1306 component in ESPHome](https://esphome.io/components/display/ssd1306#over-spi).

First set up an I²C bus first for the display:

i2c:
  - sda: ${sda_gpio_pin}
    scl: ${scl_gpio_pin}
    id: i2c_ssd1306

Most ESP32 boards have 2+ I²C interfaces that can be used with any available GPIO pins. Keep in mind that I²C uses the pins for both input and output, so avoid using any strapping pins.

Configure the ssd1306_i2c1 component for your display:

display:
  - platform: ssd1306_i2c
    id: ssd1306
    # or 'SH1106'
    model: "SSD1306 128x64"
    address: 0x3C
    i2c_id: i2c_ssd1306
    lambda: |-
      it.printf(0, 30, id(font_id), TextAlign::BASELINE_LEFT, "sudo.is");

Both the chipset model and dimensions are configured as a string in the model config item.

On/off switch

It is possible to turn off the display. While it is not exposed as a switch component in the ssd1306 component, the C++ API4 provides the turn_on(), turn_off() and is_on() functions.

We can use lambdas to call them, and template a switch component to control it and represent the state.

switch:
  - platform: template
    name: "${hostname} Display"
    id: ssd1306_switch_display
    internal: false
    disabled_by_default: false
    lambda: |-
      return id(ssd1306).is_on();
    turn_on_action:
      - lambda: |-
          id(ssd1306).turn_on();
    turn_off_action:
      - lambda: |-
          id(ssd1306).turn_off();

When turn_off() is called, the display gets fully powered off.

Brightness control

Note

The contrast config entry in the ssd1306 component is the initial contrast.

The C++ SSD1306 class API4 provides the functions set_contrast() and get_contrast(). Contrast basically works the same as brightness, so we can use that instead, with the same effect.

Template a number component to control the brightness/contrast by calling set_contrast:

number:
  - platform: template
    id: "ssd1306_contrast"
    name: "${hostname} Display"
    min_value: 0
    max_value: 100
    step: 0
    entity_category: ""
    unit_of_measurement: "%"
    device_class: power_factor
    mode: slider
    update_interval: 5s
    lambda: |-
      float contrast = id(ssd1306).get_contrast();
      return int(contrast*100);
    set_action:
      - lambda: |-
          id(ssd1306).set_contrast(x/100);

The get_contrast() function was added in my pull request esphome#6435 and was merged in ESPHome 2024.4.0.

It should also be possible to use a templated output component and then configure a light component using the monochromatic platform for a nicer presentation in Home Assistant.

Font

I've found that the font Noto Sans Mono looks good on this display.

SSD1306

Put the NotoSansMono-Regular.ttf file somewhere ESPHome can find it, and then configure2 the display to use it.

font:
  - file: "../fonts/NotoSansMono-Regular.ttf"
    id: notomono24
    size: 24

display:
  - platform: ssd1306_i2c
    id: ssd1306
    model: "SSD1306 128x64"
    address: 0x3C
    i2c_id: i2c_ssd1306
    lambda: |-
      it.printf(127, 30, id(notomono24), TextAlign::BASELINE_LEFT, "sudo.is");

Unfortunately you need to specify a font entry for each font size you want to use.

References