Inkplate 6, ESPHome

I bought a Inkplate 6 display, wanted to use it to show some info I need.
This is my first e-paper project, still working on it and making some adjustments.

Things to do:
create two more display pages using “pages:”
create info icons (instead of text)
create weather icons

This one shows

  • temperatures in four locations from my sensors.
  • if garage door is open, if not no garagedoor info is shown.
  • weather from SMHI (Swedish weather).

The weather code is from semenyak anton’s project.

My code:

substitutions:
  friendly_name: inkplate
  partial_update: 10s
  full_update: "360"

esphome:
  name: inkplate
  platform: ESP32
  board: esp-wrover-kit

wifi:
  ssid: !secret wifi_iot_ssid
  password: !secret wifi_iot_password

  ap:
    ssid: $friendly_name Fallback Hotspot
    password: !secret wifi_iot_password

captive_portal:
web_server:
  port: 80
  auth:
    username: !secret iot_admin
    password: !secret admin_iot_password

logger:

api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password

switch:
  - platform: restart
    name: "Inkplate Reboot"
    id: reboot

  - platform: gpio
    id: battery_read_mosfet
    pin:
      mcp23017: mcp23017_hub
      number: 9
      inverted: true

#  - platform: template
#    name: "Inkplate Greyscale mode"
#    lambda: return id(inkplate_display).get_greyscale();
#    turn_on_action:
#      - lambda: id(inkplate_display).set_greyscale(true);
#    turn_off_action:
#      - lambda: id(inkplate_display).set_greyscale(false);

  - platform: template
    name: "Inkplate Partial Updating"
    lambda: return id(inkplate_display).get_partial_updating();
    turn_on_action:
      - lambda: id(inkplate_display).set_partial_updating(true);
    turn_off_action:
      - lambda: id(inkplate_display).set_partial_updating(false);
      
text_sensor:
  - platform: wifi_info
    ip_address:
      name: $friendly_name IP Address

  - platform: homeassistant
    id: garage_1
    name: Garage 1
    entity_id: cover.garage_1_door
    
  - platform: homeassistant
    id: garage_2
    name: Garage 2
    entity_id: cover.garage_2_door
    
  - platform: homeassistant
    id: current_weather
    entity_id: sensor.current_weather

sensor:
  - platform: adc
    id: battery_voltage
    update_interval: never
    attenuation: 11db
    pin: 35

  - platform: template
    name: "Inkplate Battery Voltage"
    lambda: |-
      id(battery_read_mosfet).turn_on();
      delay(1);
      float adc = id(battery_voltage).sample();
      id(battery_read_mosfet).turn_off();
      return adc;
    filters:
      - multiply: 2

  - platform: wifi_signal
    name: $friendly_name WiFi Strength
    update_interval: 60s

  - platform: uptime
    name: $friendly_name "Uptime"

  - platform: homeassistant
    id: porch_temp
    name: "Porch Temperature"
    entity_id: sensor.porch_temperature
      
  - platform: homeassistant
    id: indoor_temp
    name: "Smoke Detector Upstairs Temperature"
    entity_id: sensor.smoke_detector_upstairs_temperature

  - platform: homeassistant
    id: sauna_temp
    name: "Sauna Temperature"
    entity_id: sensor.sauna_temperature
    
  - platform: homeassistant
    id: greenhouse_temp
    name: "Greenhouse Temperature"
    entity_id: sensor.greenhouse_temperature
    
  - platform: homeassistant
    id: greenhouse_hum
    name: "Greenhouse Humidity"
    entity_id: sensor.greenhouse_humidity

i2c:

mcp23017:
  - id: mcp23017_hub
    address: 0x20

binary_sensor:
  - platform: status
    name: "Inkplate Status"
    id: system_status

  - platform: gpio
    name: "Inkplate Touch Pad 1"
    pin:
      mcp23017: mcp23017_hub
      number: 10
  - platform: gpio
    name: "Inkplate Touch Pad 2"
    pin:
      mcp23017: mcp23017_hub
      number: 11
  - platform: gpio
    name: "Inkplate Touch Pad 3"
    pin:
      mcp23017: mcp23017_hub
      number: 12

time:
  - platform: sntp
    id: esptime

font:
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_96
    size: 96
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_85
    size: 85
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_48
    size: 48
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_36
    size: 36
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_25
    size: 25

image:
#0-default.png
  - file: "images/0-default.png"
    id: wpng_0
    type: BINARY
#1-clear-night.png
  - file: "images/1-clear-night.png"
    id: wpng_1
    type: BINARY
#2-cloudy.png
  - file: "images/2-cloudy.png"
    id: wpng_2
    type: BINARY
#3-fog.png
  - file: "images/3-fog.png"
    id: wpng_3
    type: BINARY
#4-hail.png
  - file: "images/4-hail.png"
    id: wpng_4
    type: BINARY
#5-lightning.png
  - file: "images/5-lightning.png"
    id: wpng_5
    type: BINARY
#6-lightning-rainy.png
  - file: "images/6-lightning-rainy.png"
    id: wpng_6
    type: BINARY
#7-partlycloudy.png
  - file: "images/7-partlycloudy.png"
    id: wpng_7
    type: BINARY
#8-pouring.png
  - file: "images/8-pouring.png"
    id: wpng_8
    type: BINARY
#9-rainy.png
  - file: "images/9-rainy.png"
    id: wpng_9
    type: BINARY
#10-snowy.png
  - file: "images/10-snowy.png"
    id: wpng_10
    type: BINARY
#11-snowy-rainy.png
  - file: "images/11-snowy-rainy.png"
    id: wpng_11
    type: BINARY
#12-sunny.png
  - file: "images/12-sunny.png"
    id: wpng_12
    type: BINARY
#13-windy.png
  - file: "images/13-windy.png"
    id: wpng_13
    type: BINARY
#14-windy-variant.png
  - file: "images/14-windy-variant.png"
    id: wpng_14
    type: BINARY
#15-exceptional.png
  - file: "images/15-exceptional.png"
    id: wpng_15
    type: BINARY

display:
- platform: inkplate6
  id: inkplate_display
  greyscale: false
  partial_updating: true
  update_interval: $partial_update
  full_update_every: $full_update # When partial updating is enabled, forces a full screen update after chosen number of updates
# Resolution 600 (y) x 800 (x)

  ckv_pin: 32
  sph_pin: 33
  gmod_pin:
    mcp23017: mcp23017_hub
    number: 1
  gpio0_enable_pin:
    mcp23017: mcp23017_hub
    number: 8
  oe_pin:
    mcp23017: mcp23017_hub
    number: 0
  spv_pin:
    mcp23017: mcp23017_hub
    number: 2
  powerup_pin:
    mcp23017: mcp23017_hub
    number: 4
  wakeup_pin:
    mcp23017: mcp23017_hub
    number: 3
  vcom_pin:
    mcp23017: mcp23017_hub
    number: 5

  pages:
    - id: page1
      lambda: |-
        it.fill(COLOR_ON);

        // Weekday 
        it.strftime(25, 25, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "%A", id(esptime).now());
        
        if (id(current_weather).state == "clear-night")
        {
           it.image(336, 25, id(wpng_1));
        }
        else if (id(current_weather).state == "cloudy")
        {
           it.image(336, 25, id(wpng_2));
        }
        else if (id(current_weather).state == "fog")
        {
           it.image(336, 25, id(wpng_3));
        }
        else if (id(current_weather).state == "hail")
        {
           it.image(336, 25, id(wpng_4));
        }
        else if (id(current_weather).state == "lightning")
        {
           it.image(336, 25, id(wpng_5));
        }
        else if (id(current_weather).state == "lightning-rainy")
        {
           it.image(336, 25, id(wpng_6));
        }
        else if (id(current_weather).state == "partlycloudy")
        {
           it.image(336, 25, id(wpng_7));
        }
        else if (id(current_weather).state == "pouring")
        {
           it.image(336, 25, id(wpng_8));
        }
        else if (id(current_weather).state == "rainy")
        {
           it.image(336, 25, id(wpng_9));
        }
        else if (id(current_weather).state == "snowy")
        {
           it.image(336, 25, id(wpng_10));
        }
        else if (id(current_weather).state == "snowy-rainy'")
        {
           it.image(336, 25, id(wpng_11));
        }
        else if (id(current_weather).state == "sunny")
        {
           it.image(336, 25, id(wpng_12));
        }
        else if (id(current_weather).state == "windy")
        {
           it.image(336, 25, id(wpng_13));
        }
        else if (id(current_weather).state == "windy-variant")
        {
           it.image(336, 25, id(wpng_14));
        }
        else if (id(current_weather).state == "exceptional")
        {
           it.image(336, 25, id(wpng_15));
        }
        else
        {
           it.image(336, 25, id(wpng_0));
        }

        // Time
        it.strftime(650, 45, id(helvetica_48), COLOR_OFF, TextAlign::CENTER, "%Y-%m-%d", id(esptime).now());
        it.strftime(650, 120, id(helvetica_96), COLOR_OFF, TextAlign::CENTER, "%H:%M", id(esptime).now());

        // Line x=10, y=180 to x=590, y=180
        it.line(10, 180, 790, 180, COLOR_OFF);
    
        // Temperature 
        if (id(indoor_temp).has_state()) {
          it.print(160, 220, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "Indoor: ");
          it.printf(600, 220, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f°C", id(indoor_temp).state);
        }

        if (id(porch_temp).has_state()) {    
          it.print(160, 270, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "Outdoor: ");
          it.printf(600, 270, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f°C", id(porch_temp).state);
        }
    
        if (id(sauna_temp).has_state()) {
          it.print(160, 320, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "Sauna: ");
          it.printf(600, 320, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f°C", id(sauna_temp).state);
        }

        if (id(greenhouse_temp).has_state()) {
          it.print(160, 370, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "Greenhouse: ");
          it.printf(600, 370, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f°C", id(greenhouse_temp).state);
          it.printf(630, 370, id(helvetica_48), COLOR_OFF, TextAlign::TOP_LEFT, "%.1f%%", id(greenhouse_hum).state);
        }

        // Status
        if (id(system_status).state) {
          it.print(780, 550, id(helvetica_36), COLOR_ON, TextAlign::TOP_RIGHT, "Offline");
        } else {
          it.print(780, 550, id(helvetica_36), COLOR_OFF, TextAlign::TOP_RIGHT, "Offline");
        }

        // Garage
        if (id(garage_1).state == "closed") {
          it.printf(25, 520, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1 is");
        } else {
          std::string val = to_string(id(garage_1).state);
          it.printf(25, 520, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 1 is %s",id(garage_1).state.c_str());
        }
        
        if (id(garage_2).state == "closed") {
          it.printf(25, 550, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 2 is");
        } else {
          std::string val = to_string(id(garage_2).state);
          it.printf(25, 550, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 2 is %s",id(garage_2).state.c_str());
        }


Update 2022-03-09 (date written in ISO 8601 standard)

Fixed the design, printed a case, cleaned unused code.
I chose to use constant power instead of battery, simply because I have the unit stationary.
Added two buttons for Open/Close the garage doors, with icons showing if garage is open.
Created layout for winter, I don’t need to monitor the greenhouse in winter time, the sensor is indoors.
For now the space is empty, but in future it will show the temperature in both garages.

component.update: ${devicename}_display to garadedoor text sensor, updates icon when state changes.
Globals to keep virtual switch state.

substitutions:
  friendly_name: Inkplate
  devicename: inkplate
  update_fast: 30s    # Screen, 
  update_medium: 120s # Battery, 
  update_slow: 600s   # WiFi, Uptime, 
  update_full: '360'
  door_delay: 180s

esphome:
  name: ${devicename}
  platform: ESP32
  board: esp-wrover-kit

<<: !include include/base.yaml

time:
  - platform: sntp
    id: esptime

i2c:

mcp23017:
  - id: mcp23017_hub
    address: 0x20

globals: # Create virtual switch state for Winter Mode
  - id: pages
    type: bool
    restore_value: no
    initial_value: 'false'
    
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO12
      mode: INPUT_PULLUP
      inverted: true
    name: "garage 1 door button"
    on_press:
    - homeassistant.service:
        service: cover.open_cover
        data: 
          entity_id: cover.garage_1_door

  - platform: gpio
    pin:
      number: GPIO13
      mode: INPUT_PULLUP
      inverted: true
    name: "garage 2 door button"
    on_press:
    - homeassistant.service:
        service: cover.open_cover
        data: 
          entity_id: cover.garage_2_door

switch:
  - platform: template # Create virtual switch for Winter Mode
    name: "$friendly_name Winter Mode"
    icon: mdi:snowflake
    id: winter_mode
    restore_state: false
    turn_on_action:
      - display.page.show: winter_page
      - component.update: ${devicename}_display
      - globals.set:
          id: pages
          value: 'true'
    turn_off_action:
      - display.page.show: summer_page
      - component.update: ${devicename}_display
      - globals.set:
          id: pages
          value: 'false'
    lambda: |-
      return id(pages);

  - platform: template
    name: "$friendly_name Partial Updating"
    lambda: return id(${devicename}_display).get_partial_updating();
    turn_on_action:
      - lambda: id(${devicename}_display).set_partial_updating(true);
    turn_off_action:
      - lambda: id(${devicename}_display).set_partial_updating(false);

  - platform: shutdown
    name: "$friendly_name Shutdown"
    id: powerdown

text_sensor:
  - platform: homeassistant
    id: garage_1
    name: Garage 1
    entity_id: cover.garage_1_door
    on_value: # update screen when state changes
      then: 
        - component.update: ${devicename}_display
    
  - platform: homeassistant
    id: garage_2
    name: Garage 2
    entity_id: cover.garage_2_door
    on_value:
      then: 
        - component.update: ${devicename}_display
    
  - platform: homeassistant
    id: current_weather
    entity_id: sensor.current_weather
    
sensor:
  - platform: homeassistant
    id: porch_temp
    name: "Porch Temperature"
    entity_id: sensor.motion_porch_temperature
      
  - platform: homeassistant
    id: indoor_temp
    name: "Smoke Detector Hallway: Air temperature"
    entity_id: sensor.smoke_detector_hallway_air_temperature

  - platform: homeassistant
    id: sauna_temp
    name: "Sauna Temperature"
    entity_id: sensor.sauna_temperature
    
  - platform: homeassistant
    id: greenhouse_temp
    name: "Greenhouse Temperature"
    entity_id: sensor.greenhouse_temperature_2
    
  - platform: homeassistant
    id: greenhouse_hum
    name: "Greenhouse Humidity"
    entity_id: sensor.greenhouse_humidity_2

font:
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_96
    size: 96
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_85
    size: 85
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_48
    size: 48
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_36
    size: 36
  - file: "0_fonts/Helvetica.ttf"
    id: helvetica_25
    size: 25

image:
#1-indoor.png
  - file: "images/1-indoor.png"
    id: indoor
    type: BINARY
#1-outdoor.png
  - file: "images/1-outdoor.png"
    id: outdoor
    type: BINARY
#1-garage.png
  - file: "images/1-garage.png"
    id: garage_img
    type: BINARY
#1-garage_error.png
  - file: "images/1-garage_error.png"
    id: garage_error_img
    type: BINARY
#1-greenhouse.png
  - file: "images/1-greenhouse.png"
    id: greenhouse
    type: BINARY
#1-sauna.png
  - file: "images/1-sauna.png"
    id: sauna
    type: BINARY
#0-default.png
  - file: "images/0-default.png"
    id: wpng_0
    type: BINARY
#1-clear-night.png
  - file: "images/1-clear-night.png"
    id: wpng_1
    type: BINARY
#2-cloudy.png
  - file: "images/2-cloudy.png"
    id: wpng_2
    type: BINARY
#3-fog.png
  - file: "images/3-fog.png"
    id: wpng_3
    type: BINARY
#4-hail.png
  - file: "images/4-hail.png"
    id: wpng_4
    type: BINARY
#5-lightning.png
  - file: "images/5-lightning.png"
    id: wpng_5
    type: BINARY
#6-lightning-rainy.png
  - file: "images/6-lightning-rainy.png"
    id: wpng_6
    type: BINARY
#7-partlycloudy.png
  - file: "images/7-partlycloudy.png"
    id: wpng_7
    type: BINARY
#8-pouring.png
  - file: "images/8-pouring.png"
    id: wpng_8
    type: BINARY
#9-rainy.png
  - file: "images/9-rainy.png"
    id: wpng_9
    type: BINARY
#10-snowy.png
  - file: "images/10-snowy.png"
    id: wpng_10
    type: BINARY
#11-snowy-rainy.png
  - file: "images/11-snowy-rainy.png"
    id: wpng_11
    type: BINARY
#12-sunny.png
  - file: "images/12-sunny.png"
    id: wpng_12
    type: BINARY
#13-windy.png
  - file: "images/13-windy.png"
    id: wpng_13
    type: BINARY
#14-windy-variant.png
  - file: "images/14-windy-variant.png"
    id: wpng_14
    type: BINARY
#15-exceptional.png
  - file: "images/15-exceptional.png"
    id: wpng_15
    type: BINARY

display:
- platform: inkplate6
  id: ${devicename}_display
  greyscale: false
  partial_updating: true
  update_interval: $update_fast
  full_update_every: $update_full # When partial updating is enabled, forces a full screen update after chosen number of updates
  model: inkplate_6
# Resolution 800 (x) x 600 (y)

  ckv_pin: 32
  sph_pin: 33
  gmod_pin:
    mcp23xxx: mcp23017_hub
    number: 1
  gpio0_enable_pin:
    mcp23xxx: mcp23017_hub
    number: 8
  oe_pin:
    mcp23xxx: mcp23017_hub
    number: 0
  spv_pin:
    mcp23xxx: mcp23017_hub
    number: 2
  powerup_pin:
    mcp23xxx: mcp23017_hub
    number: 4
  wakeup_pin:
    mcp23xxx: mcp23017_hub
    number: 3
  vcom_pin:
    mcp23xxx: mcp23017_hub
    number: 5

  pages:
    - id: summer_page
      lambda: |-
        it.fill(COLOR_ON);

        // Weekday, Outdoor temp
        it.strftime(150, 45, id(helvetica_48), COLOR_OFF, TextAlign::CENTER, "%A", id(esptime).now());
        
        if (id(porch_temp).has_state()) { 
          it.printf(230, 120, id(helvetica_96), COLOR_OFF, TextAlign::CENTER_RIGHT, "%.1f", id(porch_temp).state);
          it.printf(230, 95, id(helvetica_36), COLOR_OFF, TextAlign::CENTER_LEFT, "°C", id(porch_temp).state);
        }        

        // Date Time
        it.strftime(650, 45, id(helvetica_48), COLOR_OFF, TextAlign::CENTER, "%Y-%m-%d", id(esptime).now());
        it.strftime(650, 120, id(helvetica_96), COLOR_OFF, TextAlign::CENTER, "%H:%M", id(esptime).now());

        if (id(current_weather).state == "clear-night")
        {
           it.image(336, 25, id(wpng_1));
        }
        else if (id(current_weather).state == "cloudy")
        {
           it.image(336, 25, id(wpng_2));
        }
        else if (id(current_weather).state == "fog")
        {
           it.image(336, 25, id(wpng_3));
        }
        else if (id(current_weather).state == "hail")
        {
           it.image(336, 25, id(wpng_4));
        }
        else if (id(current_weather).state == "lightning")
        {
           it.image(336, 25, id(wpng_5));
        }
        else if (id(current_weather).state == "lightning-rainy")
        {
           it.image(336, 25, id(wpng_6));
        }
        else if (id(current_weather).state == "partlycloudy")
        {
           it.image(336, 25, id(wpng_7));
        }
        else if (id(current_weather).state == "pouring")
        {
           it.image(336, 25, id(wpng_8));
        }
        else if (id(current_weather).state == "rainy")
        {
           it.image(336, 25, id(wpng_9));
        }
        else if (id(current_weather).state == "snowy")
        {
           it.image(336, 25, id(wpng_10));
        }
        else if (id(current_weather).state == "snowy-rainy'")
        {
           it.image(336, 25, id(wpng_11));
        }
        else if (id(current_weather).state == "sunny")
        {
           it.image(336, 25, id(wpng_12));
        }
        else if (id(current_weather).state == "windy")
        {
           it.image(336, 25, id(wpng_13));
        }
        else if (id(current_weather).state == "windy-variant")
        {
           it.image(336, 25, id(wpng_14));
        }
        else if (id(current_weather).state == "exceptional")
        {
           it.image(336, 25, id(wpng_15));
        }
        else
        {
           it.image(336, 25, id(wpng_0));
        }

        // Line x=10, y=180 to x=590, y=180
        it.line(10, 180, 790, 180, COLOR_OFF);
    
        // Temperature 
        if (id(indoor_temp).has_state()) {
          it.image(30, 200, id(indoor));
          it.printf(350, 240, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(indoor_temp).state);
          it.printf(350, 240, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(indoor_temp).state);
        }

        if (id(greenhouse_temp).has_state()) {
          it.image(30, 350, id(greenhouse));
          it.printf(350, 390, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(greenhouse_temp).state);
          it.printf(350, 390, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(greenhouse_temp).state);          
          it.printf(600, 380, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f%%", id(greenhouse_hum).state);
          // it.printf(600, 430, id(helvetica_48), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f%%", id(greenhouse_hum).state);
        }
    
        if (id(sauna_temp).has_state()) {
          it.image(410, 200, id(sauna));
          it.printf(730, 240, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(sauna_temp).state);
          it.printf(730, 240, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(sauna_temp).state);
        }

        // Status
        if (id(system_status).state) {
          it.print(780, 550, id(helvetica_36), COLOR_ON, TextAlign::TOP_RIGHT, "Offline");
        } else {
          it.print(780, 550, id(helvetica_36), COLOR_OFF, TextAlign::TOP_RIGHT, "Offline");
        }

        // Garage
        if (id(garage_1).state == "closed") {
          it.printf(25, 520, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1");
          // it.image(185, 480, id(garage_img));
        } else if (id(garage_1).state == "open"){
          it.image(185, 480, id(garage_img));
          // std::string val = to_string(id(garage_1).state);
          // it.printf(25, 550, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 1 is %s",id(garage_1).state.c_str());
        } else {
          it.image(185, 480, id(garage_error_img));
        }
        
        if (id(garage_2).state == "closed") {
          it.printf(25, 550, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 2");
          // it.image(485, 480, id(garage_img));
        } else if (id(garage_2).state == "open"){
          it.image(485, 480, id(garage_img));
          // std::string val = to_string(id(garage_2).state);
          // it.printf(25, 550, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 2 is %s",id(garage_2).state.c_str());
        } else {
          it.image(485, 480, id(garage_error_img));
        }
    - id: winter_page
      lambda: |-
        it.fill(COLOR_ON);

        // Weekday, Outdoor temp
        it.strftime(150, 45, id(helvetica_48), COLOR_OFF, TextAlign::CENTER, "%A", id(esptime).now());
        
        if (id(porch_temp).has_state()) { 
          it.printf(230, 120, id(helvetica_96), COLOR_OFF, TextAlign::CENTER_RIGHT, "%.1f", id(porch_temp).state);
          it.printf(230, 95, id(helvetica_36), COLOR_OFF, TextAlign::CENTER_LEFT, "°C", id(porch_temp).state);
        }        

        // Date Time
        it.strftime(650, 45, id(helvetica_48), COLOR_OFF, TextAlign::CENTER, "%Y-%m-%d", id(esptime).now());
        it.strftime(650, 120, id(helvetica_96), COLOR_OFF, TextAlign::CENTER, "%H:%M", id(esptime).now());

        if (id(current_weather).state == "clear-night")
        {
           it.image(336, 25, id(wpng_1));
        }
        else if (id(current_weather).state == "cloudy")
        {
           it.image(336, 25, id(wpng_2));
        }
        else if (id(current_weather).state == "fog")
        {
           it.image(336, 25, id(wpng_3));
        }
        else if (id(current_weather).state == "hail")
        {
           it.image(336, 25, id(wpng_4));
        }
        else if (id(current_weather).state == "lightning")
        {
           it.image(336, 25, id(wpng_5));
        }
        else if (id(current_weather).state == "lightning-rainy")
        {
           it.image(336, 25, id(wpng_6));
        }
        else if (id(current_weather).state == "partlycloudy")
        {
           it.image(336, 25, id(wpng_7));
        }
        else if (id(current_weather).state == "pouring")
        {
           it.image(336, 25, id(wpng_8));
        }
        else if (id(current_weather).state == "rainy")
        {
           it.image(336, 25, id(wpng_9));
        }
        else if (id(current_weather).state == "snowy")
        {
           it.image(336, 25, id(wpng_10));
        }
        else if (id(current_weather).state == "snowy-rainy'")
        {
           it.image(336, 25, id(wpng_11));
        }
        else if (id(current_weather).state == "sunny")
        {
           it.image(336, 25, id(wpng_12));
        }
        else if (id(current_weather).state == "windy")
        {
           it.image(336, 25, id(wpng_13));
        }
        else if (id(current_weather).state == "windy-variant")
        {
           it.image(336, 25, id(wpng_14));
        }
        else if (id(current_weather).state == "exceptional")
        {
           it.image(336, 25, id(wpng_15));
        }
        else
        {
           it.image(336, 25, id(wpng_0));
        }

        // Line x=10, y=180 to x=590, y=180
        it.line(10, 180, 790, 180, COLOR_OFF);
    
        // Temperature 
        if (id(indoor_temp).has_state()) {
          it.image(30, 200, id(indoor));
          it.printf(350, 240, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(indoor_temp).state);
          it.printf(350, 240, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(indoor_temp).state);
        }

        if (id(sauna_temp).has_state()) {
          it.image(410, 200, id(sauna));
          it.printf(730, 240, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(sauna_temp).state);
          it.printf(730, 240, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(sauna_temp).state);
        }

        // Status
        if (id(system_status).state) {
          it.print(780, 550, id(helvetica_36), COLOR_ON, TextAlign::TOP_RIGHT, "Offline");
        } else {
          it.print(780, 550, id(helvetica_36), COLOR_OFF, TextAlign::TOP_RIGHT, "Offline");
        }

        // Garage
        if (id(garage_1).state == "closed") {
          it.printf(25, 520, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1");
          // it.image(185, 480, id(garage_img));
        } else if (id(garage_1).state == "open"){
          it.image(185, 480, id(garage_img));
          // std::string val = to_string(id(garage_1).state);
          // it.printf(25, 550, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 1 is %s",id(garage_1).state.c_str());
        } else {
          it.image(185, 480, id(garage_error_img));
        }
        
        if (id(garage_2).state == "closed") {
          it.printf(25, 550, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 2");
          // it.image(485, 480, id(garage_img));
        } else if (id(garage_2).state == "open"){
          it.image(485, 480, id(garage_img));
          // std::string val = to_string(id(garage_2).state);
          // it.printf(25, 550, id(helvetica_25), COLOR_OFF, TextAlign::TOP_LEFT, "Garage 2 is %s",id(garage_2).state.c_str());
        } else {
          it.image(485, 480, id(garage_error_img));
        }

base.yaml

## Common settings.
wifi:
  ssid: !secret wifi_iot_ssid
  password: !secret wifi_iot_password

  ap:
    ssid: $friendly_name Fallback Hotspot
    password: !secret wifi_iot_password

captive_portal:
web_server:
  port: 80
  auth:
    username: !secret top_secret_user
    password: !secret wifi_iot_password
  
logger:

api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password

packages:
  switch: !include switch_reboot.yaml
  sensor: !include sensor_wifi_uptime.yaml
  text_sensor: !include text_sensor_wifi_uptime.yaml
  binary_sensor: !include binary_sensor_status.yaml
6 Likes

Looks cool. Congrats.

You find various approaches with the inkplate here in the forum. I looked for one where you can change content shown on the display without need for reprogramming the ESP.

I found a way to display any Lovelace dashboard on the Inkplate. Doing so anyone who can build a dashboard via UI can create a compelling view on the inkplate.

Mine is running for 3 weeks now on the 1st battery charge with update every 5 minutes.

What I miss is having my code integrated into ESPHome to be able to get the easy integration for the buttons, see battery consumption etc. I tried, but failed so far.

A question.
Isn’t there a way to make a dictionary/associative array/key value pair with the images in ESP-Home?

Example:

["fog": "wpng_3"] 

That way you don’t need the large if section in the lambda, you can just use array[weather].

I’m about to start a project with a screen also soon and it would be nice to have that ability.

Thank you for your input, I will be playing around with that. Thinking about buying an other inkplate just for playing around with. Lovelace UI in inkplate sounds very nice.

Hi Echo, looks good! Just received my Inkplate6 and have been fiddling around with it, using part of your code. I’m having trouble displaying the weather icons correctly. I found some color icons which display ok, but only as a filled icon, and I would like to show only the outlines (as in your example). So I retrieved several sets of weather icons in b/w, only outlines, but if I replace the color icons with any of them they show up as squares and sometimes the icon is visible inside the square but filled and in negative. I checked the icons in photoshop for size, resolution, nr of bits/channel, all seems ok. Are there any specifications for using bitmaps on e-paper or the Inkplate specific that I missed?
And mind sharing your icons?
Thanks!

There is a font you can use.
Materialdesigns font, the same as all the HA icons use.
That way you create a sensor in HA with the weather, in my case i use something like 3-6;10.5;[rain icon] and in ESP this string is split and produce the output:

And then I have one sensor with five days weather that just have a second delimiter between the days, that way I can loop through the days and output it all fairly easy.

Hi Helllis81, the thought struck my mind earlier but I was afraid that the size/resolution of those fonts would be to grainy for a large icon, so I did not look into that. Great, will give it a try, am already using materialdesigns fonts on a smaller e-paper display so I know how to implement them.
Thanks!

This should almost certainly solve my problem for showing weather icons, but I’m still curious about the specs for bitmaps to show correctly on the inkplate display (or waveshare e-paper displays).

My display is not the six inch. The image is only on a 2.9 inch.
But you could try the font and see what it looks like.

My icons are 8bit grayscale .png, inverted black and white.
I’m not happy with my icons yet, need to do some pixel adjustments.

I think you have to play around with the picture type

#0-default.png
  - file: "images/0-default.png"
    id: wpng_0
    type: BINARY

BINARY: Two colors, suitable for 1 color displays or 2 color image in color displays. Uses 1 bit per pixel, 8 pixels per byte.

GRAYSCALE: Full scale grey. Uses 8 bits per pixel, 1 pixel per byte.
0-default 1-clear-night 2-cloudy 3-fog 4-hail 5-lightning 6-lightning-rainy 7-partlycloudy 8-pouring 9-rainy 10-snowy 12-sunny 13-windy 14-windy-variant 15-exceptional
11-snowy-rainy

Hi Echo, yeah I also tried setting the picture type to grayscale, that did not solve my problem. Also tried converting the bitmaps from RGB 8bit to grayscale 8bit, did not work. But you have inverted the bitmaps, that’s interesting, did not try that yet. Just noticed inverted bitmaps are part of the image package, but this results in just a black square. I’ll take some time researching this, I must be missing something simple. The most amazing thing is that color bitmaps display without problems but as a filled b/w image instead of outlines. I would appreciate it if you can send me one of your bitmaps so I can test with that.
Will report back after my research later this day.

I will upload my icons.

Any updates on your project? Hows it looking now? Thanks

Yes. I had one update I forgot to post. Thank you for reminding me.

include/base.yaml

## Common settings.
wifi:
  ssid: !secret wifi_iot_ssid
  password: !secret wifi_iot_password
  power_save_mode: none
  reboot_timeout: 60min
  fast_connect: true

  ap:
    ssid: $friendly_name Fallback Hotspot
    password: !secret wifi_iot_password

captive_portal:
web_server:
  port: 80
  auth:
    username: admin
    password: !secret wifi_iot_password
  
logger:

api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password

packages:
  switch: !include switch_reboot.yaml
  sensor: !include sensor_wifi_uptime.yaml
  text_sensor: !include text_sensor_wifi_uptime.yaml
  binary_sensor: !include binary_sensor_status.yaml

switch_reboot.yaml

switch:
  - platform: restart
    name: "$friendly_name Reboot"
    id: reboot

sensor_wifi_uptime.yaml

sensor:
  - platform: wifi_signal
    name: $friendly_name WiFi Strength
    update_interval: $update_slow

  - platform: uptime
    name: $friendly_name Uptime raw
    id: uptime_raw
    update_interval: $update_slow
    internal: true
    on_raw_value:
      then:
        - logger.log:
            format: "Raw Value of Uptime sensor: %f, %f"
            args: ['id(uptime_raw).raw_state', 'id(uptime_raw).state']
            level: INFO
        - text_sensor.template.publish:
            id: uptime_show
            state: !lambda |-
              int seconds = round(id(uptime_raw).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              if ( days ) {
                return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
              } else if ( hours ) {
                return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
              } else if ( minutes ) {
                return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
              } else {
                return { (String(seconds) +"s").c_str() };
              }    

text_sensor_wifi_uptime.yaml

text_sensor:
  - platform: wifi_info
    ip_address:
      name: $friendly_name IP Address
      
  - platform: template
    name: $friendly_name Uptime
    id: uptime_show
    icon: mdi:timer-outline
    update_interval: $update_slow

binary_sensor_status.yaml

binary_sensor:
  - platform: status
    name: "$friendly_name Status"
    id: system_status

Hi, nice update thanks.

I expecting a inkplate6 tomorrow, excited to try out the pages functionality. Based on your code, adding additional id: page2 etc would it change to that page when you press the corresponding capacitive button?

Thanks

I did not find a good way to use the capacitive buttons with my case design, so I skipped them.
I soldered some buttons to the top pin-outs for the garage doors. The buttons are almost not visible but still easy to find with fingers. The page 2 and 3 is in planning stage. I’m planning to use page 1 for summer and page 2 for winter.

Which pins did you solder on for your buttons?

number: GPIO12 and number: GPIO13 in the upper part of the board.

Thanks for the reply.

I just got my Inkplate 6 today. Doing Partial refresh every second for a clock, I get grey horizonal lines slowly appearing. Is this normal? Is mine faulty?

Continuing the discussion from Inkplate 6, ESPHome:

It is normal. Because the screen is not whiped, the lines will be there, for every partial it gets fuzzier. I do partial for minimum of 30sec. For clock you need only 60sec update, skip the seconds. Full update whipes the wole screen and the picture is perfect.
If you want to partial update a picture you can try using one black, one white shifting 3-4 times before you posr the right picture.