How to turn off OLED peripheral in deep sleep?

As I have the energy monitoring working well, I thought it might be a nice idea to have an OLED display running off an ESP that shows real time energy consumption: a visual reminder to save energy as every time we look at the number its going up…

As we are supposed to be saving energy with this it would make sense to run it off a battery, so my idea is a motion sensor to wake up from deep sleep and display the data. However I have run into an interesting problem testing this out - the esp32 shuts down and restarts by the deep sleep code, but the display stays on and still draws some current. So, is there any way to completely turn off the OLED at the same time?

Snippet of the code that runs without the wake up from the PIR:

captive_portal:

font:
  - file: "arial.ttf"
    id: font1
    size: 22
    
  - file: "arial.ttf"
    id: font2
    size: 14
    
time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  - platform: homeassistant
    id: Energy_Sensor
    entity_id: sensor.house_daily_energy

  - platform: homeassistant
    id: Consumed_Energy_Sensor
    entity_id: sensor.total_consumed_daily_energy
    
  - platform: homeassistant
    id: Hidden_Energy_Sensor
    entity_id: sensor.hidden_daily_energy
    
  - platform: adc
    pin: GPIO35
    name: "battery"
    unit_of_measurement: "V"
    icon: "mdi:battery-high"
    device_class: "voltage"
    state_class: "measurement"
    accuracy_decimals: 2
    attenuation: 11db
    filters:
      - multiply: 2.0
 
    
i2c:
  sda: GPIO21
  scl: GPIO22

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x64"
#    reset_pin: D0
    address: 0x3C
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 0, id(font2), "Current Energy:");
          it.printf(23, 25, id(font1), "%.3f kWh", id(Energy_Sensor).state);
          it.strftime(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%H:%M", id(homeassistant_time).now());
      - id: page2
        lambda: |-
          it.printf(0, 0, id(font2), "Consumed Energy");
          it.printf(23, 25, id(font1), "%.3f kWh", id(Consumed_Energy_Sensor).state);
          it.strftime(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%H:%M", id(homeassistant_time).now());
      - id: page3
        lambda: |-
          it.printf(0, 0, id(font2), "Hidden Energy:");
          it.printf(23, 25, id(font1), "%.3f kWh", id(Hidden_Energy_Sensor).state);
          it.strftime(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%H:%M", id(homeassistant_time).now());
          
interval:
  - interval: 8s
    then:
      - display.page.show_next: my_display
      - component.update: my_display
      
#binary_sensor:
#  - platform: gpio
#    pin: GPIO13
#    name: "PIR Sensor"
#    device_class: motion
    
deep_sleep:
  run_duration: 30s
  sleep_duration: 5min

switch:
  - platform: gpio
    pin: GPIO5
    name: "LED"

But you posted Snippet of the code that runs without the wake up from the PIR:

Is GPIO5 the power pin for the display?

GPIO5 is the internal LED - the board is a LilyGO T Energy (GitHub - LilyGO/LILYGO-T-Energy) that can be turned off. I did try to power the OLED via a GPIO pin but it throws an SPI communication error. The wakeup works but to try to turn off the OLED I commented it out.

What if you used esphome.on_shutdown trigger and performed a lambda action: id(my_display).turn_off();?

Worked for me in a project which used OLED display, to turn off the screen after a period of inactivity. Filling the entire screen with black color might do the trick, as well.

Awesome, that did the trick, thanks a million! I didn’t see that in the docs anywhere and google failed me too. I can’t measure any current flowing to the oled with a multimeter anymore. The screen displays within about 2 sec of the motion being triggered so I am happy with that. Takes a few extra seconds to populate the data so something else to play around with…MQTT perhaps rather than the API. And to see how long it lasts off one LiFePO4 battery, but I have played around with ESPnow on these boards and they last weeks and weeks.

Full code for anyone interested:

esphome:
  name: display
  on_shutdown:
    then:
      lambda: |-
        id(my_display).turn_off();

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "not telling"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    # Set this to the IP of the ESP
    static_ip: xxx.xxx.x.x
    # Set this to the IP address of the router. Often ends with .1
    gateway: xxx.xxx.x.x
    # The subnet of the network. 255.255.255.0 works for most home networks.
    subnet: xxx.xxx.x.x
    dns1: xxx.xxx.x.x
  fast_connect: on

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Display Fallback Hotspot"
    password: "not telling"

captive_portal:

font:
  - file: "arial.ttf"
    id: font1
    size: 22
    
  - file: "arial.ttf"
    id: font2
    size: 14
    
time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  - platform: homeassistant
    id: Energy_Sensor
    entity_id: sensor.house_daily_energy

  - platform: homeassistant
    id: Consumed_Energy_Sensor
    entity_id: sensor.total_consumed_daily_energy
    
  - platform: homeassistant
    id: Hidden_Energy_Sensor
    entity_id: sensor.hidden_daily_energy
    
  - platform: adc
    pin: GPIO35
    name: "battery"
    unit_of_measurement: "V"
    icon: "mdi:battery-high"
    device_class: "voltage"
    state_class: "measurement"
    accuracy_decimals: 2
    attenuation: 11db
    filters:
      - multiply: 2.0
    id: battery
 
i2c:
  sda: GPIO21
  scl: GPIO22

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x64"
#    reset_pin: D0
    address: 0x3C
    id: my_display
    flip_y: true
    flip_x: true
    rotation: 180°
    pages:
      - id: page1
        lambda: |-
          it.printf(2, 0, id(font2), "Current Energy:");
          it.printf(10, 25, id(font1), "%.3f kWh", id(Energy_Sensor).state);
          it.strftime(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%H:%M", id(homeassistant_time).now());
      - id: page2
        lambda: |-
          it.printf(2, 0, id(font2), "Consumed Energy");
          it.printf(23, 25, id(font1), "%.3f kWh", id(Consumed_Energy_Sensor).state);
          it.printf(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%.2f V", id(battery).state);
      - id: page3
        lambda: |-
          it.printf(2, 0, id(font2), "Hidden Energy:");
          it.printf(23, 25, id(font1), "%.3f kWh", id(Hidden_Energy_Sensor).state);
          it.strftime(64, 64, id(font2), TextAlign::BASELINE_CENTER, "%H:%M", id(homeassistant_time).now());
          
interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display
      
binary_sensor:
  - platform: gpio
    pin: GPIO13
    name: "PIR Sensor"
    device_class: motion
    
deep_sleep:
  run_duration: 47s
#  sleep_duration: 5min
  wakeup_pin: 13
  wakeup_pin_mode: KEEP_AWAKE
  
switch:
  - platform: gpio
    pin: GPIO5
    name: "LED"

3 Likes

Great, glad that it worked.

For reference, I found turn_on() and turn_off() methods in API reference for SSD1351 display: https://esphome.io/api/classesphome_1_1ssd1351__base_1_1_s_s_d1351.html.