ESPHome Deep Sleep and wakeup with different modes

Hi,
I do want to have an ePaper in front of a meeting room, that shows, when the room is busy. The addon is, that there are two physical buttons, one where the user can update the ePaper and one where he can boot the room for a fixed length. Until know it is all running “perfectly” :slight_smile: but I noticed, that the battery is drained pretty “quick”, so I wanted to use deep sleep mode as often as I can.
To be most flexible, I want to be able to put the ESP in deepSleep by HomeAssistant (Deep sleep would be e.g. between 7pm and 8am on workdays, all weekend, and whenever I want it.)
I use GPIO17 refreshing the display and GPIO16 for booking a fixed timeslot.
If the ESP is in DeepSleep, I want to print this on the epaper and let the user notice, that it might take some time, until he can use the “Booking” switch, and before he has to use the ePaper rerefresh button to wake the ESP up.

Here is the esphome start file:

substitutions:
  # !!! ALL LOWER CASE, NO dashes (-) because prohibited by ESPHome IDs and no underscores (_) because prohibited in DNS Host Names
  rmgr_device_name: "framery1"


# --------------
# DO NOT CHANGE BELOW THIS LINE - must be the same for all framerys.
# --------------

packages:
  base: !include
    file: common/calendar_free_busy_display.yaml
    vars:
      rmgr_device_name: "${rmgr_device_name}"

# Core Configuration Section: https://esphome.io/components/esphome.html
esphome:

  # https://esphome.io/components/esphome.html#changing-esphome-node-name
  name: "${rmgr_device_name}"

and here the file that is for all rooms the same:

# Calendar / Free Busy DASHBOARD
#  For Home Assistant and ESPHome
# Inspired by WEATHERMAN by Madelena Mak 2022 - https://mmak.es
#
#######################
# VARIABLES passed into the system:
# - rmgr_device_name: the common prefix for sensors etc (still a bad name)
#


# Core Configuration Section: https://esphome.io/components/esphome.html
esphome:

  # name is defined in specific instance config (e.g. framery1.yaml etc)

  # https://esphome.io/components/esphome.html#on-boot
  # on_boot is an *Automation* (https://esphome.io/automations/#automation)
  on_boot: # == "Trigger"
      priority: 200.0
      then: # == "Actions"
        - component.update: epaper_screen_print
        - delay: 5s
        #- logger.log: "Initial sensor data received: Refreshing display..."
        #- lambda: 'id(initial_data_received) = true;'
        #- script.execute: epaper_screen_update

        # this triggers a reload in Home Assistant (which pushes the data down to the device)
        - homeassistant.event:
            event: "esphome.${rmgr_device_name}.booted"

# https://esphome.io/components/esp32.html
esp32:
  # "if unsure choose a generic board from Espressif such as esp32dev."
  board: esp32dev
  framework:
    type: arduino


# Enable logging
# https://esphome.io/components/logger.html
logger: 
#  level: NONE
#  level: ERROR
#  level: WARN
#  level: INFO
  level: DEBUG
#  level: VERBOSE
#  level: VERY_VERBOSE



# Global variables for detecting if the display needs to be refreshed. (Thanks @paviro!)
# https://esphome.io/components/globals.html
globals:
  - id: initial_data_received
    type: bool
    restore_value: no
    initial_value: 'false'

  - id: headline_text
    type: std::string
    restore_value: no
  - id: subheadline_text
    type: std::string
    restore_value: no

  - id: timeslots
    type: std::vector<std::string>
    restore_value: no
  - id: is_occupied
    type: std::vector<bool>
    restore_value: no
  - id: rmgr_booking_slot_length_minutes
    type: std::string
    restore_value: no
  - id: last_display_refresh
    type: std::string
    restore_value: no
# Enable Home Assistant API
# https://esphome.io/components/api.html
api:
  services:
    - service: "draw_schedule"
      variables:
        param_headline_text: string
        param_subheadline_text: string
        # !!! you need the same number of entries in param_timeslots and param_is_occupied
        param_timeslots: string[]
        param_is_occupied: bool[]
        param_rmgr_booking_slot_length_minutes: string
        param_last_display_refresh: string

      then:
        - lambda: 'id(initial_data_received) = true;'
        - lambda: 'id(headline_text) = param_headline_text;'
        - lambda: 'id(subheadline_text) = param_subheadline_text;'
        - lambda: 'id(timeslots) = param_timeslots;'
        - lambda: 'id(is_occupied) = param_is_occupied;'
        - lambda: 'id(rmgr_booking_slot_length_minutes) = param_rmgr_booking_slot_length_minutes;'
        - lambda: 'id(last_display_refresh) = param_last_display_refresh;'
        - logger.log: ".-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. calfreebusy_draw_schedule Data"
        - logger.log:
            format: "param_headline_text has value >%s<"
            args: [ 'id(headline_text).c_str()' ]
        - logger.log:
            format: "param_subheadline_text has value >%s<"
            args: [ 'id(subheadline_text).c_str()' ]
        - logger.log:
            format: "param_timeslots has value >%i<"
            args: [ 'id(timeslots)' ]
        - component.update: epaper_screen_print

# https://esphome.io/components/ota/esphome
ota:
  - platform: esphome

# Wifi information
wifi:
  # Optional manual IP
  networks:
#    channel: 11
    ssid: !secret wifi_ssid
    password: !secret wifi_password

#  manual_ip:
#    static_ip: 192.168.90.182
#    gateway: 192.168.90.1
#    subnet: 255.255.255.0


  # Enable fallback hotspot (captive portal) in case wifi connection fails
  # ausgeshcaltet, da es 
  # ap:
  #   ssid: !secret wifi_ssid
  #   password: !secret wifi_password


# Include custom fonts
font:
  - file: 'fonts/GothamRnd-Book.ttf'
    id: font_small_book
    size: 18
    glyphs: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ü', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.', '%', 'ä', 'ö', 'ü', 'ß', '(', ')']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_large_bold
    size: 108
    glyphs: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', '%']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_title
    size: 54
    glyphs: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', 'u', 'p', 'd', 't', '%']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_medium_bold
    size: 30
    glyphs: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ü', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.', '%', 'ä', 'ö', 'ü', 'ß', '(', ')']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_small_bold
    size: 18
    glyphs: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', '%']

  # Include Material Design Icons font
  # Thanks to https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: font_mdi_medlarge
    size: 18
    glyphs:
      - "\U000F05A9" # mdi-wifi
      - "\U000F0928" # mdi-wifi-strength-4
      - "\U000F0925" # mdi-wifi-strength-3 
      - "\U000F0922" # mdi-wifi-strength-2
      - "\U000F091F" # mdi-wifi-strength-1
      - "\U000F092B" # mdi-wifi-strength-alert-outline


# Check if epaper should be refreshed

sensor:
  
  - platform: wifi_signal
    name: "${rmgr_device_name} - WiFi Signal Strength"
    id: "${rmgr_device_name}_wifisignal"
    unit_of_measurement: "dBm"
    entity_category: "diagnostic"
    update_interval: 600s
   
#binary_sensor:
## refresh epaper display
#  - platform: homeassistant
#    entity_id: input_boolean.update_epaper_display
#    id: update_epaper_display

binary_sensor:
  - platform: gpio
    name: "${rmgr_device_name}_book_now"
    pin:
      number: GPIO16
      inverted: true
      mode:
        input: true
        pullup: true
    filters:
      - delayed_on: 10ms
    on_multi_click:
      - timing:
          - ON for at most 1s
          - OFF for at most 1s
          - ON for at most 1s
          - OFF for at least 0.2s
        then:
          - logger.log: "Double Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_booknow_doubleclicked
      - timing: # INFO: this is currently not used functionally.
          - ON for 1s to 2s
          - OFF for at least 0.5s
        then:
          - logger.log: "Single Long Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_booknow_longclicked
      - timing:
          - ON for at most 1s
          - OFF for at least 0.5s
        then:
          - logger.log: "Single Short Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_booknow_clicked


  - platform: gpio
    name: "${rmgr_device_name}_refresh"
    pin:
      number: GPIO17
      inverted: true
      mode:
        input: true
        pullup: true
    filters:
      - delayed_on: 10ms
    on_multi_click:
      - timing:
          - ON for at most 1s
          - OFF for at most 1s
          - ON for at most 1s
          - OFF for at least 0.2s
        then:
          - logger.log: "Double Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_refresh_doubleclicked
      - timing: # INFO: this is currently not used functionally.
          - ON for 1s to 2s
          - OFF for at least 0.5s
        then:
          - logger.log: "Single Long Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_refresh_longclicked
      - timing:
          - ON for at most 1s
          - OFF for at least 0.5s
        then:
          - logger.log: "Single Short Clicked"
          - homeassistant.event:
              event: esphome.${rmgr_device_name}_refresh_clicked



# Pins for Waveshare ePaper ESP Board
spi:
  clk_pin: GPIO13                 # SCLK 	P13 	SPI CLK pin, clock signal input
  mosi_pin: GPIO14                # DIN 	P14 	SPI MOSI pin, data input

# Now render everything on the ePaper screen.
display:
  - platform: waveshare_epaper
# models from https://esphome.io/components/display/waveshare_epaper
#    model: 7.50inV2   # s/w board   evtl. älterer Treiber ???
#    model: 7.50in-nV2   # s/w board   
    model: 7.50in-bV3  # r/s/w board

    id: epaper_screen_print
    cs_pin: GPIO15                # CS 	P15 	Chip selection, low active
    dc_pin: GPIO27                # DC 	P27 	Data/command, low for commands, high for data
    busy_pin: 
      number: GPIO25              # BUSY 	P25 	Busy status output pin (means busy) 
      inverted: true
    reset_pin: GPIO26             # RST 	P26 	Reset, low active
    reset_duration: 2ms

    update_interval: never
    rotation: 90°
    lambda: |-
      int offsetY = 40;
      int offsetX = 0;
      
      //# Print loading screen before data is received.
      if (id(initial_data_received) == false) {
        it.printf(240, 390, id(font_small_bold), TextAlign::TOP_CENTER, "WARTE AUF DATEN");
      } else { 

        // headline
        int lineHeight = 35;
        it.printf(50, offsetY, id(font_medium_bold), TextAlign::TOP_LEFT, "%s", id(headline_text).c_str());
        offsetY += lineHeight;
        
        // subheadline
        lineHeight = 22;
        it.printf(150, offsetY, id(font_small_book), TextAlign::TOP_LEFT, "%s", id(subheadline_text).c_str());
        offsetY += lineHeight;

        lineHeight = 22;
        for (size_t i = 0; i < id(timeslots).size(); ++i) {
          offsetY += lineHeight;
          it.printf(50, offsetY, id(font_small_book), TextAlign::TOP_LEFT, "%s", id(timeslots)[i].c_str());
          if (id(is_occupied)[i]) {
            it.filled_rectangle(120, offsetY, 100, lineHeight);
          }
        }
      }



      //# decide for the WiFi-signal Symbol
      //# is printed printed below
      std::string wifiSymbol = "";
      offsetX = it.get_width() - 50;
      offsetY = it.get_height() - 150;
      if(id(${rmgr_device_name}_wifisignal).has_state ()) {
        if (id(${rmgr_device_name}_wifisignal).state >= -50) {
            // Excellent
            wifiSymbol = "\U000F0928";
        } else if (id(${rmgr_device_name}_wifisignal).state  >= -60) {
            //Good
            wifiSymbol = "\U000F0925";
        } else if (id(${rmgr_device_name}_wifisignal).state  >= -67) {
            //Fair
            wifiSymbol = "\U000F0922";
        } else if (id(${rmgr_device_name}_wifisignal).state  >= -70) {
            //Weak
            wifiSymbol = "\U000F091F";
        } else {
            //Unlikely working signal
            wifiSymbol = "\U000F092B";
        }
      }

      // Print booking slot length + Last refresh + Wifi
      // we write from bottom to top 
      offsetX = it.get_width() - 50;
      offsetY = it.get_height() - 130;
      int lineHeight = 22;
      // Print DBI and Wifi Signal
      it.printf(offsetX - 25, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%.0f dB", id(${rmgr_device_name}_wifisignal).state);
      it.printf(offsetX, offsetY, id(font_mdi_medlarge), TextAlign::TOP_RIGHT, "%s", wifiSymbol.c_str());
      // 
      it.printf(offsetX - 150, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%s", id(rmgr_booking_slot_length_minutes).c_str());
      offsetY -= lineHeight;
      it.printf(offsetX, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%s", id(last_display_refresh).c_str());




captive_portal:

Before I start, I do want to know if this is
a.) doable and useful
b.) what drawback I might get.

There is still the way to have a bigger battery or use power in some roome, but I do like the idea, that I can hang it on the wall everywhere for about 14 days.

thank you for all suggestions
Juergen

It should be doable.
The ESP device would have to wake up at intervals to check for new bookings, if they can occur by other sources than the button.
The delay on the button, should be possible to handle with a little power led, which ESP device often have anyway. It will give the user an indication that something happens.

Esp is waking up pretty quickly and if all automation is done on esphome, I don’t see why not to sleep even during office hours. I expect the 99% of time no-one is playing with the device.