Inkplate 6, ESPHome

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.

I’ve been using waveshare displays and they don’t have the line issue, disappointed this does.
I got the pages changing with the capacitive button, quite smart.

New Update

Update 2024-11-26 (date written in ISO 8601 standard)
I wanted to use Header and Footer, but I did not find any way to do it. It does not mean that there is no way.
My way is to use partial update, virtual switch and “If state”

Template switch named “Winter Mode”
if (id(winter_mode).state) in Display lambda

New Code:

substitutions:
  friendly_name: Inkplate Hallway
  devicename: inkplate_hallway
  update_slow: 600s   # WiFi, Uptime, 
  update_fast: 30s    # Screen, update
  update_full: '360'  # '360'

esphome:
  name: ${devicename}
  friendly_name: $friendly_name

esp32:
  board: esp-wrover-kit
  framework:
    type: arduino

logger:
  level: DEBUG
  logs:
    component: ERROR

api:
  encryption:
    key: !secret inkplate_api_key

ota:
  - platform: esphome
    password: !secret inkplate_ota_password

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

  ap:
    ssid: $friendly_name Hotspot
    password: !secret fallback_ap_password

captive_portal:
web_server:
  port: 80
  auth:
    username: !secret admin_user
    password: !secret fallback_ap_password

mdns:
  disabled: false

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

time:
  - platform: sntp
    id: esptime
    on_time:
      - seconds: 0
        minutes: /1
        then:
          - component.update: ${devicename}_display

i2c:

mcp23017:
  - id: mcp23017_hub
    address: 0x20

globals:
  - id: winter_bool
    type: bool
    restore_value: true
    initial_value: 'true'
    
binary_sensor:
  - platform: gpio
    name: "Garage 1 Door Button"
    pin:
      number: GPIO12          # WARNING GPIO12 is a strapping PIN and should only be used for I/O with care.
      mode: INPUT_PULLUP
      inverted: true
    internal: true
    on_click:
    - min_length: 2ms
      max_length: 2500ms
      then:
        - homeassistant.service:
            service: cover.open_cover
            data: 
              entity_id: cover.garage_1_uni_door
    - min_length: 3000ms
      max_length: 15000ms
      then:
        - homeassistant.service:
            service: lock.lock
            data:
              entity_id: lock.backdoor

  - platform: gpio
    name: "Garage 2 Door Button"
    pin:
      number: GPIO13
      mode: INPUT_PULLUP
      inverted: true
    internal: true
    on_click:
    - min_length: 2ms
      max_length: 2500ms
      then:
        - homeassistant.service:
            service: cover.open_cover
            data: 
              entity_id: cover.garage_2_uni_door
    - min_length: 3000ms
      max_length: 15000ms
      then:
        - homeassistant.service:
            service: lock.lock
            data:
              entity_id: lock.frontdoor

switch:
# Virtual switch based on a global variable.
  - platform: template
    name: "Winter Mode"
    icon: mdi:snowflake
    id: winter_mode
    restore_mode: RESTORE_DEFAULT_ON
    turn_on_action:
      - globals.set:
          id: winter_bool
          value: 'true'
      - component.update: ${devicename}_display
    turn_off_action:
      - globals.set:
          id: winter_bool
          value: 'false'
      - component.update: ${devicename}_display
    lambda: |-
      return id(winter_bool);

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

text_sensor:
  - platform: homeassistant
    id: garage_1_state
    name: "Garage 1 State"
    entity_id: sensor.garage_1_cover_state
    internal: true
    on_value:
      then: 
        - component.update: ${devicename}_display
    
  - platform: homeassistant
    id: garage_2_state
    name: "Garage 2 State"
    entity_id: sensor.garage_2_cover_state
    internal: true
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: lock_frontdoor
    name: "Frontdoor"
    entity_id: lock.frontdoor
    internal: true
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: lock_backdoor
    name: "Backdoor"
    entity_id: lock.backdoor
    internal: true
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: lock_garage_back
    name: "Garage Back"
    entity_id: lock.garage_back
    internal: true
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: current_weather
    entity_id: sensor.current_weather
    on_value:
      then: 
        - component.update: ${devicename}_display

sensor:
  - platform: homeassistant
    id: porch_temp
    name: "Porch Temperature"
    entity_id: sensor.motion_porch_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display
      
  - platform: homeassistant
    id: indoor_temp
    name: "Smoke Detector Hallway: Air temperature"
    entity_id: sensor.smoke_detector_hallway_air_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: sauna_temp
    name: "Sauna Temperature"
    entity_id: sensor.sauna_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: greenhouse_temp
    name: "Greenhouse Temperature"
    entity_id: sensor.weather_greenhouse_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: greenhouse_hum
    name: "Greenhouse Humidity"
    entity_id: sensor.weather_greenhouse_humidity
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: garage1_temperature
    name: "Garage 1 Temperature"
    entity_id: sensor.garage_1_uni_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display

  - platform: homeassistant
    id: garage2_temperature
    name: "Garage 2 Temperature"
    entity_id: sensor.garage_2_uni_temperature
    on_value:
      then: 
        - component.update: ${devicename}_display

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:
  - file: "images/00-indoor.png"
    id: indoor
    type: BINARY
  - file: "images/00-outdoor.png"
    id: outdoor
    type: BINARY
  - file: "images/00-garage1.png"
    id: garage1_img
    type: BINARY
  - file: "images/00-garage2.png"
    id: garage2_img
    type: BINARY
  - file: "images/00-garage_closed.png"
    id: garage_closed_img
    type: BINARY
  - file: "images/00-garage_down.png"
    id: garage_down_img
    type: BINARY
  - file: "images/00-garage_up.png"
    id: garage_up_img
    type: BINARY
  - file: "images/00-garage_half.png"
    id: garage_half_img
    type: BINARY
  - file: "images/00-garage_arrow.png"
    id: garage_arrow_img
    type: BINARY
  - file: "images/00-garage_loading.png"
    id: garage_loading_img
    type: BINARY
  - file: "images/00-garage_error.png"
    id: garage_error_img
    type: BINARY
  - file: "images/00-greenhouse.png"
    id: greenhouse
    type: BINARY
  - file: "images/00-sauna.png"
    id: sauna
    type: BINARY
  - file: "images/00-lock.png"
    id: lock
    type: BINARY
# Weather icons
  - file: "images/0-default.png"
    id: wpng_default
    type: BINARY
  - file: "images/1-clear-night.png"
    id: wpng_clear_night
    type: BINARY
  - file: "images/2-cloudy.png"
    id: wpng_cloudy
    type: BINARY
  - file: "images/3-fog.png"
    id: wpng_fog
    type: BINARY
  - file: "images/4-hail.png"
    id: wpng_hail
    type: BINARY
  - file: "images/5-lightning.png"
    id: wpng_lightning
    type: BINARY
  - file: "images/7-partlycloudy.png"
    id: wpng_partlycloudy
    type: BINARY
  - file: "images/8-pouring.png"
    id: wpng_pouring
    type: BINARY
  - file: "images/9-rainy.png"
    id: wpng_rainy
    type: BINARY
  - file: "images/10-snowy.png"
    id: wpng_snowy
    type: BINARY
  - file: "images/11-snowy-rainy.png"
    id: wpng_snowy_rainy
    type: BINARY
  - file: "images/12-sunny.png"
    id: wpng_sunny
    type: BINARY
  - file: "images/13-windy.png"
    id: wpng_windy
    type: BINARY
  - file: "images/14-windy-variant.png"
    id: wpng_windy_variant
    type: BINARY
  - file: "images/15-exceptional.png"
    id: wpng_exceptional
    type: BINARY

display:
  # Resolution 800 (x) x 600 (y)
- 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
  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 # Inkplate config pin , but results WARNING GPIO0 is a strapping PIN and should only be used for I/O with care.
  spv_pin:
    mcp23xxx: mcp23017_hub
    number: 2 # Inkplate config pin , but results WARNING GPIO2 is a strapping PIN and should only be used for I/O with care.
  powerup_pin:
    mcp23xxx: mcp23017_hub
    number: 4
  wakeup_pin:
    mcp23xxx: mcp23017_hub
    number: 3
  vcom_pin:
    mcp23xxx: mcp23017_hub
    number: 5 # Inkplate config pin , but results WARNING GPIO5 is a strapping PIN and should only be used for I/O with care.

  lambda: |-
    it.fill(COLOR_ON);
      // -- Header --\\
    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);
      }        

    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());

      // Weather
    if (id(current_weather).state == "clear-night") {
      it.image(336, 25, id(wpng_clear_night));
      } else if (id(current_weather).state == "cloudy") {
      it.image(336, 25, id(wpng_cloudy));
      } else if (id(current_weather).state == "fog") {
      it.image(336, 25, id(wpng_fog));
      } else if (id(current_weather).state == "hail") {
      it.image(336, 25, id(wpng_hail));
      } else if (id(current_weather).state == "lightning") {
      it.image(336, 25, id(wpng_lightning));
      } else if (id(current_weather).state == "lightning-rainy") {
      it.image(336, 25, id(wpng_lightning));
      } else if (id(current_weather).state == "partlycloudy") {
      it.image(336, 25, id(wpng_partlycloudy));
      } else if (id(current_weather).state == "pouring") {
      it.image(336, 25, id(wpng_pouring));
      } else if (id(current_weather).state == "rainy") {
      it.image(336, 25, id(wpng_rainy));
      } else if (id(current_weather).state == "snowy") {
      it.image(336, 25, id(wpng_snowy));
      } else if (id(current_weather).state == "snowy-rainy'") {
      it.image(336, 25, id(wpng_snowy_rainy));
      } else if (id(current_weather).state == "sunny") {
      it.image(336, 25, id(wpng_sunny));
      } else if (id(current_weather).state == "windy") {
      it.image(336, 25, id(wpng_windy));
      } else if (id(current_weather).state == "windy-variant") {
      it.image(336, 25, id(wpng_windy_variant));
      } else if (id(current_weather).state == "exceptional") {
      it.image(336, 25, id(wpng_exceptional));
      } else {
      it.image(336, 25, id(wpng_default));
      }

    // 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);
      }

    // -- Footer --\\
    // 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");
      }

    // Door Locks
    if (id(lock_backdoor).state == "unlocked") {
      it.image(40, 480, id(lock));
      }

    if (id(lock_garage_back).state == "unlocked") {
      it.image(336, 480, id(lock));
      }

    if (id(lock_frontdoor).state == "unlocked") {
      it.image(632, 480, id(lock));
      }

    // -- Footer end --\\
    if (id(winter_mode).state) {

      // -- Winter -- \\

      if (id(garage_1_state).state == "Fully Closed") {
        it.printf(25, 520, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1");
        it.image(30, 350, id(garage_closed_img));
        } else if (id(garage_1_state).state == "Fully Open"){
        it.image(30, 350, id(garage1_img));
        it.image(185, 480, id(garage_arrow_img));
        } else if (id(garage_1_state).state == "Partially Open") {
        it.image(30, 350, id(garage_half_img));
        } else if (id(garage_1_state).state == "Door is Closing") {
        it.image(30, 350, id(garage_down_img));
        } else if (id(garage_1_state).state == "Door is Opening") {
        it.image(30, 350, id(garage_up_img));
        } else if (id(garage_1_state).state == "Loading") {
        it.image(410, 350, id(garage_loading_img));
        } else {
        it.image(185, 480, id(garage_error_img));
        }
      if (id(garage1_temperature).has_state()) {
        it.printf(350, 390, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(garage1_temperature).state);
        it.printf(350, 390, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(garage1_temperature).state);          
        }

      if (id(garage_2_state).state == "Fully Closed") {
        it.printf(25, 550, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1");
        it.image(410, 350, id(garage_closed_img));
        } else if (id(garage_2_state).state == "Fully Open"){
        it.image(410, 350, id(garage2_img));
        it.image(485, 480, id(garage_arrow_img));
        } else if (id(garage_2_state).state == "Partially Open"){
        it.image(410, 350, id(garage_half_img));
        } else if (id(garage_2_state).state == "Door is Closing"){
        it.image(410, 350, id(garage_down_img));
        } else if (id(garage_2_state).state == "Door is Opening"){
        it.image(410, 350, id(garage_up_img));
        } else if (id(garage_2_state).state == "Loading"){
        it.image(410, 350, id(garage_loading_img));
        } else {
        it.image(185, 480, id(garage_error_img));
        }
      if (id(garage2_temperature).has_state()) {
        it.printf(730, 390, id(helvetica_85), COLOR_OFF, TextAlign::TOP_RIGHT, "%.1f", id(garage2_temperature).state);
        it.printf(730, 390, id(helvetica_36), COLOR_OFF, TextAlign::TOP_LEFT, "°C", id(garage2_temperature).state);          
        }

      // -- Winter end -- \\
    } else {
      // -- Summer -- \\

      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);
        }

        // Garage 1
      if (id(garage_1_state).state == "Fully Closed") {
        it.printf(25, 520, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 1");
        } else if (id(garage_1_state).state == "Fully Open"){
        it.image(185, 480, id(garage1_img));
        } else if (id(garage_1_state).state == "Partially Open") {
        it.image(185, 480, id(garage_half_img));
        } else if (id(garage_1_state).state == "Door is Closing") {
        it.image(185, 480, id(garage_down_img));
        } else if (id(garage_1_state).state == "Door is Opening") {
        it.image(185, 480, id(garage_up_img));
        } else if (id(garage_1_state).state == "Loading") {
        it.image(185, 480, id(garage_loading_img));
        } else {
        it.image(185, 480, id(garage_error_img));
        }

      // Garage 2
      if (id(garage_2_state).state == "Fully Closed") {
        it.printf(25, 550, id(helvetica_25), COLOR_ON, TextAlign::TOP_LEFT, "Garage 2");
        } else if (id(garage_2_state).state == "Fully Open"){
        it.image(485, 480, id(garage2_img));
        } else if (id(garage_2_state).state == "Partially Open") {
        it.image(485, 480, id(garage_half_img));
        } else if (id(garage_2_state).state == "Door is Closing") {
        it.image(485, 480, id(garage_down_img));
        } else if (id(garage_2_state).state == "Door is Opening") {
        it.image(485, 480, id(garage_up_img));
        } else if (id(garage_2_state).state == "Loading") {
        it.image(485, 480, id(garage_loading_img));
        } else {
        it.image(485, 480, id(garage_error_img));
        }

        // -- Summer end -- \\
      }