M5stack Dial et ESPHOME

Voilà à quoi ressemble la page_b1 par exemple.

Code 19/06/24
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  #########################
  # use_address: 192.168.2.53
  #########################
  manual_ip:
    static_ip: !secret ip_m5stack_dial
    gateway: !secret wifi_gtw
    subnet: !secret wifi_sub
  ap:
    ssid: "m5stack-dial-fallback"
    password: !secret wifi_ap_password

ota:
  password: !secret ota_password

logger:
  # level: DEBUG

api:
  encryption:
    key: !secret api_encryption_key

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  on_boot:
    then:
      - pcf8563.read_time: rtc_time
      - delay: 13s
      - light.turn_on: backlight
      - display.page.show: page_01
      
external_components:
  - source: github://dgaust/esphome@gc9a01
    components: [ gc9a01, ft3267 ]
    refresh: 0s

<<: !include m5dial_files/colors_and_fonts.yaml
<<: !include m5dial_files/images_and_icons.yaml

spi: #required by display.ili9xxx
  mosi_pin: GPIO5
  clk_pin: GPIO6

i2c:
  - id: bus_internal #required by touchscreen.ft3267
    sda: GPIO11
    scl: GPIO12
    scan: false

touchscreen:
  platform: ft3267
  on_touch:
    then:
      - logger.log:
          format: 'Touch ID: %d at _____________________ (%d, %d)'
          args: [touch.id, touch.x, touch.y]

rc522_i2c: # RFiD
  i2c_id:  bus_internal
  address: 0x28
  on_tag:
    then:
      - rtttl.play: 'two_short:d=4,o=5,b=100:16e6,16e6'
      - homeassistant.tag_scanned: !lambda 'return x;'

rtttl: # buzzer
  output: rtttl_out
  id: my_rtttl

time:
  - platform: pcf8563
    id: rtc_time
    address: 0x38
    update_interval: never
  - platform: homeassistant
    on_time_sync:
      then:
        - pcf8563.write_time: rtc_time
        - logger.log: "time synced"

output:
  - id: lcdbacklight # screen backlight
    platform: ledc
    pin: GPIO9
    min_power: 0
    max_power: 1
  - platform: ledc # buzzer
    pin: GPIO3
    id: rtttl_out

substitutions:
  name: tab-m5stack-dial
  friendly_name: M5Stack Dial
  wifi_ssid: !secret wifi_ssid
  wifi_password: !secret wifi_password

  alarm_panel_id: alarm_control_panel.alarme_maison
  climate_id: climate.heatpump_sdgs_ebusd
  door_bell_id: input_boolean.test
  garage_sensor_id: binary_sensor.io_frient_garage_09c6_input_1
  garage_door_sensor_id: binary_sensor.magnet_aqara_garage_door_contact
  gate_sensor_id: binary_sensor.tplt_gate_open_too_long
  lux_sensor_id: sensor.ip030_mmw_aqara_living_luminance
  window_group_id: binary_sensor.windows_upstairs
  light_01_id: light.shelly_one_cour
  window_01_id: binary_sensor.magnet_aqara_bedroom_north_contact
  window_02_id: binary_sensor.magnet_aqara_kitchen_contact
  window_03_id: binary_sensor.magnet_aqara_attic_contact
  window_04_id: binary_sensor.magnet_aqara_bedroom_south_contact
  window_05_id: binary_sensor.magnet_aqara_bay_contact

# ======================================================================================
# ======================================================================================
# ========================================================================== text sensor

text_sensor:
  - platform: homeassistant
    id: alarm_text # armed_away / armed_home / pending etc....
    entity_id: $alarm_panel_id
    on_value:
      then:
        - display.page.show: !lambda |-
            auto selector = id(page_selector).state;
            if (selector == "page_off" or selector == "page_01") {
              return id(page_a1);
            } else {
              return nullptr;
            }
        - component.update: screen
  - platform: homeassistant
    id: gate_text # closed / open / alert
    entity_id: $gate_sensor_id
    attribute: esphome_text_sensor
    <<: &gate_value
      on_value:
        then:
          - display.page.show: !lambda |-
              auto selector = id(page_selector).state;
              auto gate = id(gate_text).state;
              if (selector == "page_off" or selector == "page_01") {
                if (gate == "open" or gate == "alert") {
                  return id(page_b1);
                } else {
                  return nullptr;
                }
              } else {
                return nullptr;
              }
          - component.update: screen
  - platform: homeassistant
    id: garage_text # off / on
    entity_id: $garage_sensor_id
    on_value:
      then:
        - display.page.show: !lambda |-
            auto selector = id(page_selector).state;
            if (selector == "page_off" or selector == "page_01") {
              if (id(garage_text).state == "on") {
                return id(page_b2);
              } else {
                return nullptr;
              }
            } else {
              return nullptr;
            }
        - component.update: screen
  - platform: homeassistant
    id: garage_door_text # off / on
    entity_id: $garage_door_sensor_id
    on_value:
      then:
        - display.page.show: !lambda |-
            auto selector = id(page_selector).state;
            if (selector == "page_off" or selector == "page_01") {
              if (id(garage_door_text).state == "on") {
                return id(page_b2);
              } else {
                return nullptr;
              }
            } else {
              return nullptr;
            }
        - component.update: screen
  - platform: homeassistant
    id: climate_mode_text # auto / heat / off
    entity_id: $climate_id
  - platform: homeassistant
    id: door_bell_text # off / on
    entity_id: $door_bell_id
    <<: *gate_value
  - platform: homeassistant
    id: light_01_text # off / on
    entity_id: $light_01_id
  - platform: homeassistant
    id: window_group_text # off / on
    entity_id: $window_group_id
  - platform: homeassistant
    id: window_01_text # off / on
    entity_id: $window_01_id
  - platform: homeassistant
    id: window_02_text # off / on
    entity_id: $window_02_id
  - platform: homeassistant
    id: window_03_text # off / on
    entity_id: $window_03_id
  - platform: homeassistant
    id: window_04_text # off / on
    entity_id: $window_04_id
  - platform: homeassistant
    id: window_05_text # off / on
    entity_id: $window_05_id

# ======================================================================================
# ======================================================================================
# ================================================================================ light

light:
  - platform: monochromatic
    id: backlight
    name: "Backlight"
    output: lcdbacklight
    default_transition_length: 500ms

# ======================================================================================
# ======================================================================================
# =============================================================================== select

select:
  - platform: template
    name: Page Selector
    icon: "mdi:book-open-page-variant-outline"
    id: page_selector
    options:
     - "page_off"
     - "page_01"
     - "page_02"
     - "page_a1"
     - "page_b1"
     - "page_b2"
     - "page_c1"
     - "page_d1"
    initial_option: "page_01"
    optimistic: true
    on_value:
      - if:
          condition:
            - lambda: 'return id(page_selector).state == "page_off";'
          then:
            - display.page.show: page_off
            - lambda: 'id(lcdbacklight).set_level(0.1);'
            - delay: 8s
            - light.turn_off: backlight
          else:
            - if:
                condition:
                  - light.is_off: backlight
                then:
                  - light.turn_on: backlight
            - display.page.show: !lambda |-
                auto selector = id(page_selector).state;
                if (selector == "page_01") {
                  return id(page_01);
                } else if (selector == "page_02") {
                  return id(page_02);
                } else if (selector == "page_a1") {
                  return id(page_a1);
                } else if (selector == "page_b1") {
                  return id(page_b1);
                } else if (selector == "page_b2") {
                  return id(page_b2);
                } else if (selector == "page_c1") {
                  return id(page_c1);
                } else if (selector == "page_d1") {
                  return id(page_d1);
                } else {
                  return nullptr;
                }
            - component.update: screen

# ======================================================================================
# ======================================================================================
# ====================================================================== display + pages

display:
  - platform: ili9xxx
    model: gc9a01a
    reset_pin: GPIO8
    id: screen
    cs_pin: GPIO7
    dc_pin: GPIO4
    dimensions:
      height: 240
      width: 240
    on_page_change:
      - to: page_off
        then:
          - select.set:
              id: page_selector
              option: page_off
          - component.update: screen
      - to: page_01
        then:
          - select.set:
              id: page_selector
              option: page_01
          - component.update: screen
      - to: page_02
        then:
          - select.set:
              id: page_selector
              option: page_02
          - component.update: screen
      - to: page_a1
        then:
          - select.set:
              id: page_selector
              option: page_a1
          - component.update: screen
      - to: page_b1
        then:
          - select.set:
              id: page_selector
              option: page_b1
          - component.update: screen
      - to: page_b2
        then:
          - select.set:
              id: page_selector
              option: page_b2
          - component.update: screen
      - to: page_c1
        then:
          - select.set:
              id: page_selector
              option: page_c1
          - component.update: screen
      - to: page_d1
        then:
          - select.set:
              id: page_selector
              option: page_d1
          - component.update: screen
    pages:

      # ------------------------------------------------------------ qrcode page
      - id: page_off
        lambda: |-
          // variables =========================================================
          float screenwidth = it.get_width();
          float screenheight = it.get_height();
          float halfscreenwidth = screenwidth /2;
          float halfscreenheight = screenheight / 2;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, COLOR_ON);
          // content ===========================================================
          it.print(halfscreenwidth, 15, id(roboto_20_bold), blue_color, TextAlign::CENTER, "SSID:");
          it.printf(halfscreenwidth, 35, id(roboto_20_bold), blue_color, TextAlign::CENTER, "${wifi_ssid}");
          it.image(halfscreenwidth, halfscreenheight + 10, img_off, ImageAlign::CENTER);

      # ----------------------------------------------------------- welcome page
      - id: page_01
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto gate = id(gate_text).state;
          auto garage = id(garage_text).state;
          auto garage_door = id(garage_door_text).state;
          auto mode = id(climate_mode_text).state;
          auto current = id(climate_current_temperature).state;
          auto target = id(climate_target_temperature).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          it.line(0, halfscreenheight, screenwidth, halfscreenheight, off_color);
          it.line(halfscreenwidth, 0, halfscreenwidth, screenheight, off_color);
          // icons =============================================================
          // alarm icon --------------------------------------------------------
          if (id(alarm_text).state == "armed_away") {
            it.image(65, 75, icon_shield_lock, ImageAlign::CENTER, nova_color);
          } else if (id(alarm_text).state == "armed_night") {
            it.image(65, 75, icon_shield_moon, ImageAlign::CENTER, nova_color);
          } else if (id(alarm_text).state == "armed_home") {
            it.image(65, 75, icon_shield_account, ImageAlign::CENTER, blue_color);
          } else if (id(alarm_text).state == "arming") {
            it.image(65, 75, icon_shield_sync, ImageAlign::CENTER, text_color);
          } else if (id(alarm_text).state == "pending") {
            it.image(65, 75, icon_shield_lock_open, ImageAlign::CENTER, yellow_color);
          } else if (id(alarm_text).state == "triggered") {
            it.image(65, 75, icon_shield_alert, ImageAlign::CENTER, red_color);
          } else {
            it.image(65, 75, icon_shield_off, ImageAlign::CENTER, off_color);
          }
          // openings icon -----------------------------------------------------
          if (gate == "alert") {
            it.image(175, 75, icon_gate_alert, ImageAlign::CENTER, red_color);
          } else if (garage == "on" or garage_door == "on") {
            it.image(175, 75, icon_garage_open, ImageAlign::CENTER, yellow_color);
          } else if (gate == "open") {
            it.image(175, 75, icon_gate_open, ImageAlign::CENTER, blue_color);
          } else {
            it.image(175, 75, icon_gate_closed, ImageAlign::CENTER, text_color);
          }
          // thermostat icon ---------------------------------------------------
          if (mode == "auto") {
            it.image(65, 165, icon_temperature_auto, ImageAlign::CENTER, green_color);
          } else if (mode == "heat") {
            if (current < target) {
              it.image(65, 165, icon_temperature_heat, ImageAlign::CENTER, red_color);
            } else {
              it.image(65, 165, icon_temperature_cool, ImageAlign::CENTER, blue_color);
            }
          } else {
            it.image(65, 165, icon_temperature_off, ImageAlign::CENTER, text_color);
          }
          // light icon --------------------------------------------------------
          it.image(175, 165, icon_light_on, ImageAlign::CENTER, text_color);
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.strftime(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "%d/%m %X", id(rtc_time).now());
          // bottom text =======================================================
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 QRCODE");

      # ----------------------------------------------------------- windows page
      - id: page_02
        lambda: |-
          // variables =========================================================
          float screenwidth = it.get_width();
          float screenheight = it.get_height();
          float halfscreenwidth = screenwidth /2;
          float halfscreenheight = screenheight / 2;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // icons =============================================================
          if (id(window_01_text).state == "off") {
            it.image(60, 70, icon_bedroom_north_closed, ImageAlign::CENTER, text_color);
          } else {
            it.image(60, 70, icon_bedroom_north_open, ImageAlign::CENTER, blue_color);
          }
          if (id(window_02_text).state == "off") {
            it.image(180, 70, icon_kitchen_closed, ImageAlign::CENTER, text_color);
          } else {
            it.image(180, 70, icon_kitchen_open, ImageAlign::CENTER, blue_color);
          }
          if (id(window_03_text).state == "off") {
            it.image(halfscreenwidth, halfscreenheight, icon_velux, ImageAlign::CENTER, text_color);
          } else {
            it.image(halfscreenwidth, halfscreenheight, icon_velux, ImageAlign::CENTER, blue_color);
          }
          if (id(window_04_text).state == "off") {
            it.image(60, 170, icon_bedroom_south_closed, ImageAlign::CENTER, text_color);
          } else {
            it.image(60, 170, icon_bedroom_south_open, ImageAlign::CENTER, blue_color);
          }
          if (id(window_05_text).state == "off") {
            it.image(180, 170, icon_dining_closed, ImageAlign::CENTER, text_color);
          } else {
            it.image(180, 170, icon_dining_open, ImageAlign::CENTER, blue_color);
          }
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "FENETRES");
          // bottom text =======================================================
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");

      # ------------------------------------------------------------- alarm page
      - id: page_a1
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto alarm = id(alarm_text).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // main icons ========================================================
          if (alarm == "armed_home") {
            it.image(60, 85, big_icon_shield_account, ImageAlign::CENTER, blue_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
          } else if (alarm == "armed_night") {
            it.image(60, 85, big_icon_shield_moon, ImageAlign::CENTER, nova_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
          } else if (alarm == "disarmed") {
            it.image(60, 85, big_icon_shield_off, ImageAlign::CENTER, off_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
          } else {
            if (alarm == "armed_away") {
              it.image(halfscreenwidth, 85, big_icon_shield_lock, ImageAlign::CENTER, nova_color);
            } else if (alarm == "arming") {
              it.image(halfscreenwidth, 85, big_icon_shield_sync, ImageAlign::CENTER, text_color);
            } else if (alarm == "pending") {
              it.image(halfscreenwidth, 85, big_icon_shield_lock_open, ImageAlign::CENTER, yellow_color);
            } else if (alarm == "triggered") {
              it.image(halfscreenwidth, 85, big_icon_shield_alert, ImageAlign::CENTER, red_color);
            }
          }
          if (alarm == "armed_home") {
            it.image(180, 85, big_icon_shield_moon, ImageAlign::CENTER, text_color);
          } else if (alarm == "armed_night" or alarm == "disarmed") {
            it.image(180, 85, big_icon_shield_account, ImageAlign::CENTER, text_color);
          }
          // main text =========================================================
          if (alarm == "armed_home") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Armer mode nuit");
            it.print(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "\U000F0741 CONFIRMER");
          } else if (alarm == "armed_night" or alarm == "disarmed") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Armer mode presence");
            it.print(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "\U000F0741 CONFIRMER");
          } else {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Etat actuel:");
            if (alarm == "armed_away") {
              it.print(halfscreenwidth, 180, id(roboto_20_bold), nova_color, TextAlign::CENTER, "ABSENTS");
            } else if (alarm == "arming") {
              it.print(halfscreenwidth, 180, id(roboto_20_bold), text_color, TextAlign::CENTER, "ARMEMENT");
            } else if (alarm == "pending") {
              it.print(halfscreenwidth, 180, id(roboto_20_bold), yellow_color, TextAlign::CENTER, "EN SUSPENS");
            } else if (alarm == "triggered") {
              it.print(halfscreenwidth, 180, id(roboto_20_bold), red_color, TextAlign::CENTER, "DECLENCHEE");
            }
          }
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "ALARME");
          // bottom text =======================================================
          if (alarm == "armed_home" or alarm == "armed_night" or alarm == "disarmed") {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 ANNULER");
          } else {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");
          }

      # ---------------------------------------------------------- openings page
      # ____________________________________________________ gate
      - id: page_b1
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto gate = id(gate_text).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // main icons ========================================================
          if (gate == "closed") {
            it.image(60, 85, big_icon_gate_closed, ImageAlign::CENTER, text_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
            it.image(180, 85, big_icon_gate_open, ImageAlign::CENTER, yellow_color);
          } else if (gate == "open") {
            it.image(halfscreenwidth, 85, big_icon_gate_open, ImageAlign::CENTER, yellow_color);
          } else {
            it.image(halfscreenwidth, 85, big_icon_gate_alert, ImageAlign::CENTER, red_color);
          }
          // main text =========================================================
          if (gate == "closed") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Ouvrir le portail?");
          } else if (gate == "open") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Portail ouvert");
          } else {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Portail a controler!");
          }
          // + tap text --------------------------------------------------------
          if (gate == "closed") {
            it.print(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "\U000F0741 CONFIRMER");
          }
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F1999 CHOIX");
          // bottom text =======================================================
          if (gate == "closed") {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 ANNULER");
          } else {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");
          }
      # ____________________________________________________ garage
      - id: page_b2
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto garage = id(garage_text).state;
          auto garage_door = id(garage_door_text).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // main icons ========================================================
          if (garage == "off") {
            if (garage_door == "on") {
              it.image(halfscreenwidth, 85, big_icon_door_open, ImageAlign::CENTER, yellow_color);
            } else {
              it.image(60, 85, big_icon_garage_closed, ImageAlign::CENTER, text_color);
              it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
              it.image(180, 85, big_icon_garage_open, ImageAlign::CENTER, yellow_color);
            }
          } else {
            it.image(60, 85, big_icon_garage_open, ImageAlign::CENTER, yellow_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
            it.image(180, 85, big_icon_garage_closed, ImageAlign::CENTER, text_color);
          }
          // main text =========================================================
          if (garage == "off") {
            if (garage_door == "on") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Garage ouvert!");
            } else {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Ouvrir le garage?");
            }
          } else {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Fermer le garage?");
          }
          // + tap text --------------------------------------------------------
          it.print(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "\U000F0741 CONFIRMER");
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F1999 CHOIX");
          // bottom text =======================================================
          if (garage == "off") {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 ANNULER");
          } else {
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");
          }

      # ------------------------------------------------------- temperature page
      - id: page_c1
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto mode = id(climate_mode_text).state;
          auto current = id(climate_current_temperature).state;
          auto target = id(new_target_temperature).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          if (mode == "auto") {
            it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "THERMOSTAT");
          } else {
            it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F1999 CONSIGNE");
          }
          // main icon =========================================================
          if (mode == "auto") {
            it.image(75, 85, big_icon_temperature_auto, ImageAlign::CENTER, green_color);
          } else if (mode == "heat") {
            if (current < target) {
              it.image(75, 85, big_icon_temperature_heat, ImageAlign::CENTER, red_color);
            } else {
              it.image(75, 85, big_icon_temperature_cool, ImageAlign::CENTER, blue_color);
            }
          } else {
            it.image(75, 85, big_icon_temperature_off, ImageAlign::CENTER, off_color);
          }
          it.print(165, 85, id(roboto_20_regular), orange_color, TextAlign::CENTER, "\U000F0741 MODE");
          // main text =========================================================
          if (mode == "auto") {
            it.printf(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Consigne: %2.1f°C", target);
          } else if (mode == "heat") {
            it.printf(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Consigne: %2.1f°C", target);
          } else {
            it.printf(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Consigne: %2.1f°C", target);
          }
          it.printf(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "Sonde: %2.1f°C", current);
          // bottom text =======================================================
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");

      # ------------------------------------------------------------ lights page
      - id: page_d1
        lambda: |-
          // variables =========================================================
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth /2;
          auto cour = id(light_01_text).state;
          // background draws ==================================================
          it.filled_rectangle(0, 0, screenwidth, screenheight, pri_color);
          // main icons ========================================================
          if (cour == "on") {
            it.image(60, 85, big_icon_light_on, ImageAlign::CENTER, yellow_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
            it.image(180, 85, big_icon_light_off, ImageAlign::CENTER, text_color);
          } else {
            it.image(60, 85, big_icon_light_off, ImageAlign::CENTER, text_color);
            it.image(halfscreenwidth, 85, icon_arrow_left, ImageAlign::CENTER, text_color);
            it.image(180, 85, big_icon_light_on, ImageAlign::CENTER, yellow_color);
          }
          // main text =========================================================
          if (cour == "on") {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Eteindre la cour?");
          } else {
            it.print(halfscreenwidth, 140, id(roboto_24_regular), text_color, TextAlign::CENTER, "Allumer la cour?");
          }
          // + tap text --------------------------------------------------------
          it.print(halfscreenwidth, 180, id(roboto_20_bold), blue_color, TextAlign::CENTER, "\U000F0741 CONFIRMER");
          // foreground draws ==================================================
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight -220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.filled_regular_polygon(halfscreenwidth, halfscreenheight +220, 144, EDGES_OCTAGON, VARIATION_FLAT_TOP, sec_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight -220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          it.regular_polygon(halfscreenwidth, halfscreenheight +220, 145, EDGES_OCTAGON, VARIATION_FLAT_TOP, off_color);
          // top text ==========================================================
          it.print(halfscreenwidth, 20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F1999 CHOIX");
          // bottom text =======================================================
          it.print(halfscreenwidth, screenheight -20, id(roboto_16_bold), orange_color, TextAlign::CENTER, "\U000F0046 RETOUR");

# ======================================================================================
# ======================================================================================
# ============================================================================== sensors

sensor:

  # -------------------------------------------------------------------- climate
  - platform: homeassistant
    id: climate_target_temperature
    entity_id: $climate_id
    attribute: temperature
    on_value:
      - lambda: |-
          id(new_target_temperature).publish_state(x);
      - logger.log: "nouvelle valeur : TEST new target temperature"
  - platform: homeassistant
    id: climate_current_temperature
    entity_id: $climate_id
    attribute: current_temperature

  - platform: template
    id: new_target_temperature
    name: Target Temperature
    icon: mdi:thermometer-lines

  # ----------------------------------------------------------------- lux sensor
  - platform: homeassistant
    entity_id: $lux_sensor_id
    name: "Lux Sensor"
    id: sensor_lux
    accuracy_decimals: 0
    on_value:
      - logger.log: 
          format: "$lux_sensor_id: %.0f"
          args: [ 'id(sensor_lux).state' ]
      - if:
          condition:
            - light.is_on: backlight
          then:
            - lambda: |- 
                float lux = id(sensor_lux).state;
                if (lux < 10) { 
                  id(lcdbacklight).set_level(0.1);
                }
                else if (lux < 40) {
                  id(lcdbacklight).set_level(0.3);
                }
                else if (lux < 80) {
                  id(lcdbacklight).set_level(0.5);
                }
                else {
                  id(lcdbacklight).set_level(0.7);
                }

  # ------------------------------------------------------------- rotary encoder
  - platform: rotary_encoder
    name: Rotary Encoder
    id: rotaryencoder
    resolution: 1
    pin_a:
      number: GPIO40
      mode:
       input: true
       pullup: true
    pin_b:
      number: GPIO41
      mode:
       input: true
       pullup: true
    accuracy_decimals: 0
    # accuracy_decimals: 1
    on_clockwise:
      - logger.log: "rotary_encoder : _____________________ turned_clockwise"
      - if:
          <<: &select_off
            condition:
              - lambda: 'return id(page_selector).state == "page_off";'
            then:
              - select.set:
                  id: page_selector
                  option: page_01
              - component.update: screen
          else:
            # ____________________________________________ 0 pages
            - if:
                <<: &01_02
                  condition:
                    - lambda: 'return id(page_selector).state == "page_01";'
                  then:
                    - select.set:
                        id: page_selector
                        option: page_02
                    - component.update: screen
                else:
                  - if:
                      <<: &02_01
                        condition:
                          - lambda: 'return id(page_selector).state == "page_02";'
                        then:
                          - select.set:
                              id: page_selector
                              option: page_01
                          - component.update: screen
            # ____________________________________________ B pages
            - if:
                <<: &b1_b2
                  condition:
                    - lambda: 'return id(page_selector).state == "page_b1";'
                  then:
                    - select.set:
                        id: page_selector
                        option: page_b2
                    - component.update: screen
                else:
                  - if:
                      <<: &b2_b1
                        condition:
                          - lambda: 'return id(page_selector).state == "page_b2";'
                        then:
                          - select.set:
                              id: page_selector
                              option: page_b1
                          - component.update: screen
            # ____________________________________________ c pages
            - if:
                condition:
                  - lambda: 'return id(page_selector).state == "page_c1";'
                then:
                  - lambda: |-
                      return id(new_target_temperature).publish_state(id(new_target_temperature).state + 0.5);
              
    on_anticlockwise:
      - logger.log: "rotary_encoder : _____________________ turned_ANTIclockwise"
      - if:
          <<: *select_off
          else:
            # ____________________________________________ 0 pages
            - if:
                <<: *01_02
                else:
                  - if:
                      <<: *02_01
                      else:
            # ____________________________________________ B pages
            - if:
                <<: *b1_b2
                else:
                  - if:
                      <<: *b2_b1
                      else:
            # ____________________________________________ c pages
            - if:
                condition:
                  - lambda: 'return id(page_selector).state == "page_c1";'
                then:
                  - lambda: |-
                      return id(new_target_temperature).publish_state(id(new_target_temperature).state - 0.5);

                # id(new_target_temperature).publish_state(id(climate_target_temperature).state - 0.5);
# ======================================================================================
# ======================================================================================
# ======================================================================= binary sensors

binary_sensor:

  # --------------------------------------------------------------------- button
  - platform: gpio
    pin:
      number: GPIO42
      inverted: true
    name: M5 Button
    on_press:
      - logger.log: "button_pushed _____________________ button_pushed"
      - if:
          condition:
            - lambda: 'return id(page_selector).state == "page_01";'
          then:
            - select.set:
                id: page_selector
                option: page_off
          else:
            - select.set:
                id: page_selector
                option: page_01
            - component.update: screen

# ================================================================= touch inputs
  # -------------------------------------------------------------- welcome
  - platform: touchscreen
    id: touch_01_tl
    internal: true
    x_min: 0
    x_max: 118
    y_min: 0
    y_max: 118
    page_id: page_01
    on_release:
      - logger.log: "touch_input OVER page_01 : _____________________ top_left"
      - if:
          condition:
            - light.is_on: backlight
          then:
            - display.page.show: page_a1
            - component.update: screen
  - platform: touchscreen
    id: touch_01_tr
    internal: true
    x_min: 122
    x_max: 240
    y_min: 0
    y_max: 118
    page_id: page_01
    on_release:
      - logger.log: "touch_input OVER page_01 : _____________________ top_right"
      - if:
          condition:
            - light.is_on: backlight
          then:
            - lambda: |-
                // function ====================================================
                auto call = id(page_selector).make_call();
                // conditions ==================================================
                if (id(garage_text).state == "on") {
                call.set_option("page_b2");
                } else {
                call.set_option("page_b1");
                }
                // function call ===============================================
                call.perform();
            - component.update: screen
  - platform: touchscreen
    id: touch_01_bl
    internal: true
    x_min: 0
    x_max: 118
    y_min: 122
    y_max: 240
    page_id: page_01
    on_release:
      - logger.log: "touch_input OVER page_01 : _____________________ bottom_left"
      - if:
          condition:
            - light.is_on: backlight
          then:
            - display.page.show: page_c1
            - component.update: screen
  - platform: touchscreen
    id: touch_01_br
    internal: true
    x_min: 122
    x_max: 240
    y_min: 122
    y_max: 240
    page_id: page_01
    on_release:
      - logger.log: "touch_input OVER page_01 : _____________________ bottom_right"
      - if:
          condition:
            - light.is_on: backlight
          then:
            - display.page.show: page_d1
            - component.update: screen

  # -------------------------------------------------------------- A pages
  - platform: touchscreen
    id: touch_a1
    page_id: page_a1
    <<: &touch_full
      internal: true
      x_min: 0
      x_max: 240
      y_min: 0
      y_max: 240
    on_press:
      - if:
          condition:
            - light.is_on: backlight
          then:
            - if:
                condition:
                  or: 
                    - lambda: 'return id(alarm_text).state == "disarmed";'
                then:
                  - <<: &bip
                      rtttl.play: 'one_short:d=32,o=4,b=900:a'
                  - homeassistant.service:
                      service: input_button.press
                      data_template:
                        entity_id: input_button.alarm_arm_home
            - if:
                condition:
                  - lambda: 'return id(alarm_text).state == "armed_home";'
                then:
                  - <<: *bip
                  - homeassistant.service:
                      service: input_button.press
                      data_template:
                        entity_id: input_button.alarm_arm_night
            - if:
                condition:
                  or: 
                    - lambda: 'return id(alarm_text).state == "disarmed";'
                    - lambda: 'return id(alarm_text).state == "armed_night";'
                then:
                  - <<: *bip
                  # TEST #############################################################
                  - homeassistant.service:
                      service: input_boolean.toggle
                      data_template:
                        entity_id: input_boolean.test
                  # TEST #############################################################

  # -------------------------------------------------------------- B pages
  - platform: touchscreen
    id: touch_b1
    page_id: page_b1
    <<: *touch_full
    on_press:
      - if:
          condition:
            - light.is_on: backlight
          then:
            - <<: *bip
            - homeassistant.service:
                service: lock.unlock
                data_template:
                  entity_id: lock.gate

  - platform: touchscreen
    id: touch_b2
    page_id: page_b2
    <<: *touch_full
    on_press:
      - if:
          condition:
            - light.is_on: backlight
          then:
            - <<: *bip
            # TEST #############################################################
            - homeassistant.service:
                service: input_boolean.toggle
                data_template:
                  entity_id: input_boolean.test
            # TEST #############################################################

  # -------------------------------------------------------------- C pages
  - platform: touchscreen
    id: touch_c1
    page_id: page_c1
    <<: *touch_full
    on_press:
      - if:
          condition:
            - light.is_on: backlight
          then:
            - if:
                condition:
                  - lambda: 'return id(climate_mode_text).state == "off";'
                then:
                  - <<: *bip
                  - homeassistant.service:
                      service: climate.set_hvac_mode
                      data_template:
                        entity_id: climate.heatpump_sdgs_ebusd
                        hvac_mode: heat
            - if:
                condition:
                  or: 
                    - lambda: 'return id(climate_mode_text).state == "heat";'
                then:
                  - <<: *bip
                  - homeassistant.service:
                      service: climate.set_hvac_mode
                      data_template:
                        entity_id: climate.heatpump_sdgs_ebusd
                        hvac_mode: auto
            - if:
                condition:
                  or: 
                    - lambda: 'return id(climate_mode_text).state == "auto";'
                then:
                  - <<: *bip
                  - homeassistant.service:
                      service: climate.set_hvac_mode
                      data_template:
                        entity_id: climate.heatpump_sdgs_ebusd
                        hvac_mode: "off"

  # -------------------------------------------------------------- D pages
  - platform: touchscreen
    id: touch_d1
    page_id: page_d1
    <<: *touch_full
    on_press:
      - if:
          condition:
            - light.is_on: backlight
          then:
            - <<: *bip
            - homeassistant.service:
                service: light.toggle
                data_template:
                  entity_id: light.shelly_one_cour
images_and_icons.yaml
image:
  # ============================================================= images
  - id: img_off
    file: m5dial_files/qrcode_wifi.png
    type: GRAYSCALE
    resize: 160x160

  # ======================================================= little icons
  - id: icon_arrow_left
    file: mdi:arrow-right
    resize: 36x36

  # ============================================================== icons
  - id: icon_light_on
    file: mdi:lightbulb-group-outline
    resize: 48x48
  - id: icon_shield_lock
    file: mdi:shield-lock
    resize: 48x48
  - id: icon_shield_moon
    file: mdi:shield-moon-outline
    resize: 48x48
  - id: icon_shield_account
    file: mdi:shield-account
    resize: 48x48
  - id: icon_shield_sync
    file: mdi:shield-sync
    resize: 48x48
  - id: icon_shield_lock_open
    file: mdi:shield-lock-open
    resize: 48x48
  - id: icon_shield_alert
    file: mdi:shield-alert
    resize: 48x48
  - id: icon_shield_off
    file: mdi:shield-off
    resize: 48x48
  - id: icon_door_locked
    file: mdi:door-closed-lock
    resize: 48x48
  - id: icon_door_open
    file: mdi:door-open
    resize: 48x48
  - id: icon_garage_closed
    file: mdi:garage-variant
    resize: 48x48
  - id: icon_garage_open
    file: mdi:garage-open-variant
    resize: 48x48
  - id: icon_garage_alert
    file: mdi:garage-alert
    resize: 48x48
  - id: icon_gate_closed
    file: mdi:gate
    resize: 48x48
  - id: icon_gate_open
    file: mdi:gate-open
    resize: 48x48
  - id: icon_gate_alert
    file: mdi:gate-alert
    resize: 48x48
  - id: icon_temperature_auto
    file: mdi:thermostat-auto
    resize: 48x48
  - id: icon_temperature_heat
    file: mdi:thermometer-chevron-up
    resize: 48x48
  - id: icon_temperature_cool
    file: mdi:thermometer-chevron-down
    resize: 48x48
  - id: icon_temperature_off
    file: mdi:thermometer-off
    resize: 48x48
  - id: icon_window_closed
    file: mdi:window-closed-variant
    resize: 48x48
  - id: icon_window_open
    file: mdi:window-open-variant
    resize: 48x48
  - id: icon_velux
    file: mdi:home-roof
    resize: 48x48
  - id: icon_bedroom_north_closed
    file: mdi:bed-king
    resize: 48x48
  - id: icon_bedroom_north_open
    file: mdi:bed-king-outline
    resize: 48x48
  - id: icon_bedroom_south_closed
    file: mdi:bed-single
    resize: 48x48
  - id: icon_bedroom_south_open
    file: mdi:bed-single-outline
    resize: 48x48
  - id: icon_kitchen_closed
    file: mdi:fridge
    resize: 48x48
  - id: icon_kitchen_open
    file: mdi:fridge-top
    resize: 48x48
  - id: icon_dining_closed
    file: mdi:silverware-variant
    resize: 48x48
  - id: icon_dining_open
    file: mdi:silverware-fork-knife
    resize: 48x48

  # ========================================================== big icons
  - id: big_icon_light_off
    file: mdi:lightbulb-outline
    resize: 72x72
  - id: big_icon_light_on
    file: mdi:lightbulb-on
    resize: 72x72
  - id: big_icon_shield_lock
    file: mdi:shield-lock
    resize: 72x72
  - id: big_icon_shield_moon
    file: mdi:shield-moon-outline
    resize: 72x72
  - id: big_icon_shield_account
    file: mdi:shield-account
    resize: 72x72
  - id: big_icon_shield_sync
    file: mdi:shield-sync
    resize: 72x72
  - id: big_icon_shield_lock_open
    file: mdi:shield-lock-open
    resize: 72x72
  - id: big_icon_shield_alert
    file: mdi:shield-alert
    resize: 72x72
  - id: big_icon_shield_off
    file: mdi:shield-off
    resize: 72x72
  - id: big_icon_temperature_auto
    file: mdi:thermostat-auto
    resize: 72x72
  - id: big_icon_temperature_heat
    file: mdi:thermometer-chevron-up
    resize: 72x72
  - id: big_icon_temperature_cool
    file: mdi:thermometer-chevron-down
    resize: 72x72
  - id: big_icon_temperature_off
    file: mdi:thermometer-off
    resize: 72x72
  - id: big_icon_garage_closed
    file: mdi:garage-variant
    resize: 72x72
  - id: big_icon_garage_open
    file: mdi:garage-open-variant
    resize: 72x72
  - id: big_icon_door_open
    file: mdi:door-open
    resize: 72x72
  - id: big_icon_gate_closed
    file: mdi:gate
    resize: 72x72
  - id: big_icon_gate_open
    file: mdi:gate-open
    resize: 72x72
  - id: big_icon_gate_alert
    file: mdi:gate-alert
    resize: 72x72
colors_and_fonts.yaml
color:
  # Nova Colors
  - id: nova_color # pink
    hex: "e38de3"
  - id: pri_color # light (mantle)
    hex: "24273a"
  - id: sec_color # dark (crust)
    hex: "181926"
  - id: text_color
    hex: "cad3f5"
  - id: off_color
    hex: "5b6078"

  # Blue Colors
  - id: blue_color
    hex: "6b93e3"
  - id: green_color
    hex: "a6da95"
  - id: yellow_color
    hex: "ffd17a"
  - id: orange_color
    hex: "e0752b"
  - id: red_color
    hex: "de455c"


font:
  - id: roboto_16_bold
    file:
      type: gfonts
      family: Roboto
      weight: bold
    size: 16
    <<: &extras
      extras:
        - file: "fonts/materialdesignicons-webfont.ttf"
          glyphs: [
            "\U000F1999", # mdi-rotate-360
            "\U000F0741", # mdi-gesture-tap
            "\U000F0046", # mdi-arrow-down-thick
            ]
  - id: roboto_20_regular
    file:
      type: gfonts
      family: Roboto
      weight: regular
    size: 20
    <<: *extras
  - id: roboto_20_bold
    file:
      type: gfonts
      family: Roboto
      weight: bold
    size: 20
    <<: *extras
  - id: roboto_24_regular
    file: 
      type: gfonts
      family: Roboto
      weight: regular
    size: 24
    <<: *extras
  - id: roboto_24_bold
    file: 
      type: gfonts
      family: Roboto
      weight: bold
    size: 24
    <<: *extras
HA Automation
alias: Remote / M5 Dial / Test
description: Remote / M5Dial
trigger:
  - platform: state
    entity_id:
      - select.tab_m5stack_dial_page_selector
    to: page_01
    for: "00:00:10"
    id: auto_off
  - platform: template
    value_template: >-
      {{ not
      is_state('select.tab_m5stack_dial_page_selector',['page_off','page_01'])
      }}
    for: "00:00:20"
    id: auto_welcome
  - platform: state
    entity_id:
      - binary_sensor.pir_sonoff_hall_door_occupancy
    to: "on"
    id: auto_on
  - platform: state
    entity_id:
      - sensor.tab_m5stack_dial_target_temperature
    for: "00:00:05"
    id: target_temp
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - auto_off
        sequence:
          - service: select.select_option
            target:
              entity_id: select.tab_m5stack_dial_page_selector
            data:
              option: page_off
      - conditions:
          - condition: trigger
            id:
              - auto_welcome
        sequence:
          - service: select.select_option
            target:
              entity_id: select.tab_m5stack_dial_page_selector
            data:
              option: page_01
      - conditions:
          - condition: trigger
            id:
              - auto_on
          - condition: state
            entity_id: select.tab_m5stack_dial_page_selector
            state: page_off
        sequence:
          - service: select.select_option
            target:
              entity_id: select.tab_m5stack_dial_page_selector
            data:
              option: page_01
      - conditions:
          - condition: trigger
            id:
              - target_temp
        sequence:
          - service: climate.set_temperature
            target:
              entity_id: climate.heatpump_sdgs_ebusd
            data:
              temperature: "{{ states('sensor.tab_m5stack_dial_target_temperature') }}"
mode: parallel
max: 2
1 « J'aime »