M5Stack Dial - ESP32-S3 Smart Rotary Knob

Great thank you for the explication :slight_smile:

Is there any way to try test and include this device with the simple functions in the HA with a yaml file?

Thank you

Brilliant; thank you for the API info.

Yeh, I figured as much but the only way I can see me figuring it out is to play with a working file and changing things to see what they do, then hopefully getting to a point I can make my own.

My goal is to have it be exclusively a climate control device so the home screen is where I select the room and then the climate. I think these files are a great starting point, but I think I’m going to fire up a dummy HA instance on a VM and just play with it.

If I ever get to the point of having a barebone template file, I’ll post it here.

1 Like

This is brilliant!
This with the pages from atomic10’s code will get me exactly where I need to be.

Great work!

1 Like

Looks good, a bit better looking than my climate interface
 look forward to seeing the yaml you used.

It’s done.

my custome knob climate is finish.
It allow to toggle my light.

https://youtube.com/shorts/YyUqwTbqZxg?feature=share

Thanks for youre help :slight_smile:

3 Likes

Nice indeed. That display, is a card from HA or ESP specific?

esp specific.

i make it with the display icon and button

Look very nice.

Can you share the code?

How did you make the plate for the knob. It this made form an existing plate from a switch?

Yeah, I’d like to see the yaml code - particularly for the slider/temp selector bit

Hi,

you can find my knob yaml.
It’s a little fat :smiley:

If you have any question about it, don’t hesitate

script:
  - id: touchscreen_display_on_script
    mode: single
    then:
      - lambda: |-
          id(mode).publish_state("lights");
      - light.turn_on:
          id: touchscreen_back_lighting
          brightness: !lambda |-
            return id(touchscreen_display_brightness).state / 100;
      - sensor.rotary_encoder.set_value:
          id: touchscreen_rotary
          value: 0
      - sensor.template.publish:
          id: climate_new_temperature
          state: !lambda |-
            return id(climate_target_temperature).state;
      - delay: 500ms
      - lambda: |-
          id(touchscreen_display_on).publish_state(true);
  - id: touchscreen_display_off_script
    mode: single
    then:
      - light.turn_off:
          id: touchscreen_back_lighting
      - lambda: |-
          id(touchscreen_display_on).publish_state(false);
      - script.execute:
          id: climate_apply_new_temperature
  - id: touchscreen_display_set_countdown
    mode: single
    then:
      - number.set:
          id: touchscreen_display_countdown
          value: !lambda |-
            return id(touchscreen_display_delay).state;
  - id: touchscreen_display_change_mode
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && id(touchscreen_button_freeze_countdown).state == 0;
          then:
            - lambda: |-
                if (strcmp(id(mode).state.c_str(), "lights") == 0) {
                  id(mode).publish_state("climate");
                } else if (strcmp(id(mode).state.c_str(), "climate") == 0) {
                  id(mode).publish_state("lights");
                } else {
                  id(mode).publish_state("lights");
                }
  - id: change_display_page
    mode: single
    then:
      - display.page.show: !lambda |-
          if (strcmp(id(mode).state.c_str(), "lights") == 0) {
            return id(lights);
          } else if (strcmp(id(mode).state.c_str(), "climate") == 0) {
            return id(climate);
          } else {
            return id(lights);
          }
      - component.update: touchscreen_lcd
  - id: lights_toggle_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state;
          then:
            - homeassistant.service:
                service: switch.toggle
                data:
                  entity_id: switch.lumieres_salle_a_manger
            - delay: 500ms
  - id: climate_apply_new_temperature
    mode: single
    then:
      - delay: 500ms
      - if:
          condition:
            - lambda: |-
                return !id(touchscreen_display_on).state && id(climate_new_temperature).state >= 10;
          then:
            - homeassistant.service:
                service: climate.set_temperature
                data:
                  entity_id: climate.thermostat_principal
                  temperature: !lambda |-
                    return id(climate_new_temperature).state;
  - id: climate_new_temperature_auto_mode
    mode: single
    then:
      - lambda: |-
          if (id(climate_new_temperature).state <= id(climate_away_temperature).state) {
            id(climate_away_script).execute();
          } else if (id(climate_new_temperature).state > id(climate_away_temperature).state && id(climate_new_temperature).state <= id(climate_sleep_temperature).state) {
            id(climate_sleep_script).execute();
          } else if (id(climate_new_temperature).state > id(climate_sleep_temperature).state && id(climate_new_temperature).state <= id(climate_home_temperature).state) {
            id(climate_home_script).execute();
          } else if (id(climate_new_temperature).state > id(climate_home_temperature).state) {
            id(climate_comfort_script).execute();
          }
  - id: climate_new_temperature_up_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - number.set: 
                id: touchscreen_button_freeze_countdown
                value: 2
            - lambda: |-
                return id(climate_new_temperature).publish_state(id(climate_new_temperature).state + 0.5);
            - lambda: |-
                return id(climate_new_temperature).publish_state((id(climate_new_temperature).state < id(climate_max_temperature).state) ? id(climate_new_temperature).state : id(climate_max_temperature).state);
            - script.execute:
                id: climate_new_temperature_auto_mode
            - component.update: touchscreen_lcd
  - id: climate_new_temperature_down_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - number.set: 
                id: touchscreen_button_freeze_countdown
                value: 2
            - lambda: |-
                return id(climate_new_temperature).publish_state(id(climate_new_temperature).state - 0.5);
            - lambda: |-
                return id(climate_new_temperature).publish_state((id(climate_new_temperature).state > id(climate_min_temperature).state) ? id(climate_new_temperature).state : id(climate_min_temperature).state);
            - script.execute:
                id: climate_new_temperature_auto_mode
            - component.update: touchscreen_lcd
  - id: climate_away_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - text_sensor.template.publish:
                id: climate_mode
                state: away
  - id: climate_sleep_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - text_sensor.template.publish:
                id: climate_mode
                state: sleep
  - id: climate_home_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - text_sensor.template.publish:
                id: climate_mode
                state: home
  - id: climate_comfort_script
    mode: single
    then:
      - if:
          condition:
            - lambda: |-
                return id(touchscreen_display_on).state && (strcmp(id(mode).state.c_str(), "climate") == 0);
          then:
            - text_sensor.template.publish:
                id: climate_mode
                state: comfort
            - number.set:
                id: climate_comfort_countdown
                value: !lambda |-
                  return id(climate_comfort_duration).state * 60;
  - id: climate_runtime
    mode: single
    then:
      - if:
          condition: 
            - lambda: |-
                return !id(touchscreen_display_on).state && id(climate_comfort_countdown).state == 0 && strcmp(id(climate_mode).state.c_str(), "away") != 0;
          then:
            - lambda: |- 
                // Variables          
                float hours = id(homeassistant_time).now().hour;
                float minutes = id(homeassistant_time).now().minute;
                hours = hours + minutes / 60;
                int day = id(homeassistant_time).now().day_of_week;

                // Change climate mode                
                if (hours > 6 and hours < 20 and (day == 1 or day == 2 or hours < 8.5 or hours > 15.5)) {
                  id(climate_mode).publish_state("home");
                } else {
                  id(climate_mode).publish_state("sleep");
                }

font:
  - file: "gfonts://Roboto"
    id: roboto20
    size: 20

  - file: "gfonts://Roboto"
    id: roboto40
    size: 40

#############
# Variables #
#############
time:
  - platform: homeassistant
    id: homeassistant_time
    on_time: 
      - seconds: 0
        minutes: /1
        then:
          - script.execute:
              id: climate_runtime
      - seconds: /1
        then:
          - if:
              condition:
                - number.in_range:
                    id: touchscreen_display_countdown
                    above: 1
              then:
                - number.decrement:
                    id: touchscreen_display_countdown
                    cycle: false
          - if:
              condition:
                - number.in_range:
                    id: touchscreen_button_freeze_countdown
                    above: 1
              then:
                - number.decrement:
                    id: touchscreen_button_freeze_countdown
                    cycle: false
          - if:
              condition:
                - number.in_range:
                    id: climate_comfort_countdown
                    above: 1
              then:
                - number.decrement:
                    id: climate_comfort_countdown
                    cycle: false

number:
  # Public

  - platform: template
    id: touchscreen_display_delay
    name: Durée rétro-éclairage
    icon: mdi:wrench-clock
    optimistic: true
    min_value: 0
    max_value: 60
    step: 5
    initial_value: 10

  - platform: template
    id: touchscreen_display_brightness
    name: Luminosité
    icon: mdi:brightness-6
    optimistic: true
    min_value: 0
    max_value: 100
    step: 5
    initial_value: 50

  - platform: template
    id: climate_away_temperature
    name: Température du mode "Absent"
    icon: mdi:thermometer-low
    optimistic: true
    min_value: 10
    max_value: 22
    step: 1
    initial_value: 10

  - platform: template
    id: climate_sleep_temperature
    name: Température du mode "Couché"
    icon: mdi:thermometer
    optimistic: true
    min_value: 10
    max_value: 22
    step: 1
    initial_value: 15

  - platform: template
    id: climate_home_temperature
    name: Température du mode "Maison"
    icon: mdi:thermometer
    optimistic: true
    min_value: 10
    max_value: 22
    step: 1
    initial_value: 19.5

  - platform: template
    id: climate_comfort_duration
    name: Durée du mode "Boost"
    icon: mdi:wrench-clock
    optimistic: true
    min_value: 30
    max_value: 120
    step: 5
    initial_value: 60

  - platform: template
    id: climate_comfort_temperature
    name: Température du mode "Boost"
    icon: mdi:thermometer-high
    optimistic: true
    min_value: 10
    max_value: 22
    step: 1
    initial_value: 22

  # Private

  - platform: template
    id: touchscreen_display_countdown
    internal: true
    optimistic: true
    min_value: 0
    max_value: 60
    step: 1
    initial_value: 1
    on_value_range:
      - above: 1
        then: 
          - script.execute:
              id: touchscreen_display_on_script
      - below: 0
        then: 
          - script.execute:
              id: touchscreen_display_off_script

  - platform: template
    id: touchscreen_button_freeze_countdown
    internal: true
    optimistic: true
    min_value: 0
    max_value: 2
    step: 1
    initial_value: 1

  - platform: template
    id: pi
    internal: true
    optimistic: true
    min_value: 3.14159265359
    max_value: 3.14159265360
    step: 0.00000000001
    initial_value: 3.14159265359

  - platform: template
    id: climate_icon_distance_radius
    internal: true
    optimistic: true
    min_value: 0
    max_value: 1
    step: 0.01
    initial_value: 0.6

  - platform: template
    id: climate_icon_separation_angle
    internal: true
    optimistic: true
    min_value: 30
    max_value: 60
    step: 1
    initial_value: 55

  - platform: template
    id: climate_bottom_gauge_angle
    internal: true
    optimistic: true
    min_value: 30
    max_value: 180
    step: 1
    initial_value: 70

  - platform: template
    id: climate_temperature_distance_from_center
    internal: true
    optimistic: true
    min_value: 0
    max_value: 40
    step: 1
    initial_value: 20

  - platform: template
    id: climate_comfort_countdown
    internal: true
    optimistic: true
    min_value: 0
    max_value: 10000
    step: 1
    initial_value: 1

############
# Settings #
############

external_components:
  - source: github://dgaust/esphome@gc9a01
    components: 
      - gc9a01
      - ft3267
    refresh: 0s
  - source: "github://pr#6096"
    components:
      - display
    refresh: 0s

spi:
  mosi_pin: GPIO5
  clk_pin: GPIO6

i2c:
  - id: bus_internal
    sda: GPIO11
    scl: GPIO12
  - id: bus_porta
    sda: 13
    scl: 15

display:
  - platform: gc9a01
    id: touchscreen_lcd
    reset_pin: GPIO8
    cs_pin: GPIO7
    dc_pin: GPIO4
    rotation: 90
    update_interval: 1h
    pages:
      - id: lights
        lambda: |-
          // Variables
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth / 2;
          it
            .image(
              halfscreenwidth, 
              halfscreenheight,
              lights_icon, 
              ImageAlign::CENTER,
              (id(lights_switch).state) ? id(activated_button_color) : id(desactivated_button_color));

          // Display the swith menu
          it.filled_circle(halfscreenwidth -6, 225, 3);
          it.circle(halfscreenwidth +6, 225, 3);

      - id: climate
        lambda: |-
          // Variables
          float screenheight = it.get_height();
          float screenwidth = it.get_width();
          float halfscreenheight = screenheight / 2;
          float halfscreenwidth = screenwidth / 2;
          float currentTemperatureCircleAngle = (360 - id(climate_bottom_gauge_angle).state) * ((id(climate_current_temperature).state - id(climate_min_temperature).state) / (id(climate_max_temperature).state - id(climate_min_temperature).state));
          float targetTemperatureCircleAngle = (360 - id(climate_bottom_gauge_angle).state) * ((id(climate_new_temperature).state - id(climate_min_temperature).state) / (id(climate_max_temperature).state - id(climate_min_temperature).state));
          float startAngle = id(climate_bottom_gauge_angle).state / 2;
          float firstStepAngle = (currentTemperatureCircleAngle < targetTemperatureCircleAngle) ? currentTemperatureCircleAngle : targetTemperatureCircleAngle;
          float secondStepAngle = (currentTemperatureCircleAngle > targetTemperatureCircleAngle) ? firstStepAngle : targetTemperatureCircleAngle;
          float endAngle = 360 - id(climate_bottom_gauge_angle).state;

          // Display temperature arc circle
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle) * id(pi).state / 180), 
              5, 
              id(dark_orange));
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + endAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + endAngle) * id(pi).state / 180), 
              5, 
              id(gray));

          for (int i = startAngle; i <= startAngle + firstStepAngle; i++) {
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(dark_orange));
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(dark_orange));
          }
          for (int i = startAngle + firstStepAngle; i <= startAngle + secondStepAngle; i++) {
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(orange));
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(orange));
          }
          for (int i = startAngle + secondStepAngle; i <= startAngle + endAngle; i++) {
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(gray));
            it
              .filled_triangle(
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180), 
                halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180), 
                id(gray));
          }

          // Current temperature round
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + currentTemperatureCircleAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + currentTemperatureCircleAngle) * id(pi).state / 180), 
              2, 
              id(white));

          // Start of the second step
          if (firstStepAngle < secondStepAngle) {
            it
              .filled_circle(
                halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + firstStepAngle) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + firstStepAngle) * id(pi).state / 180), 
                5, 
                id(orange));
            it
              .filled_circle(
                halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + firstStepAngle) * id(pi).state / 180),
                halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + firstStepAngle) * id(pi).state / 180), 
                2, 
                id(dark_orange));
          } 

          // Target temperature round
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180), 
              7, 
              id(orange));
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180), 
              5, 
              id(white));

          // Dislay icons
          it
            .image(
              halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 - 1.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180), 
              halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 - 1.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180), 
              climate_away_mode_icon, 
              ImageAlign::CENTER,
              (strcmp(id(climate_mode).state.c_str(), "away") == 0) ? id(activated_button_color) : id(desactivated_button_color));
          it
            .image(
              halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 - 0.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180), 
              halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 - 0.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180), 
              climate_sleep_mode_icon, 
              ImageAlign::CENTER,
              (strcmp(id(climate_mode).state.c_str(), "sleep") == 0) ? id(activated_button_color) : id(desactivated_button_color));
          it
            .image(
              halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 + 0.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180), 
              halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 + 0.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180), 
              climate_home_mode_icon, 
              ImageAlign::CENTER,
              (strcmp(id(climate_mode).state.c_str(), "home") == 0) ? id(activated_button_color) : id(desactivated_button_color));
          it
            .image(
              halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 + 1.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180), 
              halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 + 1.5 * id(climate_icon_separation_angle).state)*id(pi).state / 180), 
              climate_comfort_mode_icon, 
              ImageAlign::CENTER,
              (strcmp(id(climate_mode).state.c_str(), "comfort") == 0) ? id(activated_button_color) : id(desactivated_button_color));
 
          // Display temperature
          it.printf(halfscreenwidth, halfscreenheight - id(climate_temperature_distance_from_center).state, id(roboto40), TextAlign::TOP_CENTER, "%2.1f", id(climate_new_temperature).state, id(white));
          it.printf(halfscreenwidth, halfscreenheight - id(climate_temperature_distance_from_center).state + 40, id(roboto20), TextAlign::TOP_CENTER, "%2.1f", id(climate_current_temperature).state, id(white));
          it
            .image(
              halfscreenwidth - 40, 
              halfscreenheight - id(climate_temperature_distance_from_center).state + 42, 
              climate_thermometer_icon, 
              ImageAlign::TOP_LEFT,
              id(white));
          it
            .image(
              halfscreenwidth + 20, 
              halfscreenheight - id(climate_temperature_distance_from_center).state + 42, 
              climate_celcius_icon, 
              ImageAlign::TOP_LEFT,
              id(white));
          it
            .image(
              halfscreenwidth, 
              halfscreenheight - id(climate_temperature_distance_from_center).state + 92, 
              climate_fire_icon, 
              ImageAlign::CENTER,
              (id(climate_new_temperature).state > id(climate_current_temperature).state) ? id(red) : id(gray));

          // Display the swith menu
          it.circle(halfscreenwidth - 6, 225, 3);
          it.filled_circle(halfscreenwidth + 6, 225, 3);

touchscreen:
  platform: ft3267
  i2c_id:  bus_internal
  on_update:
    - then:
      - script.execute:
          id: touchscreen_display_set_countdown

binary_sensor:
  - platform: gpio
    pin: GPIO42
    name: Bouton
    internal: true
    filters: 
      - invert: 
    on_state: 
      - then:
        - script.execute:
            id: touchscreen_display_set_countdown
    on_press: 
      - then:
        - script.execute:
            id: touchscreen_display_change_mode

  - platform: template
    id: touchscreen_display_on
    internal: true
        
  - platform: touchscreen
    id: lights_toggle_touchscreen_button
    internal: true
    x_min: 85
    x_max: 165
    y_min: 85
    y_max: 165
    page_id: lights
    on_state: 
      then:
        - script.execute:
            id: lights_toggle_script

  - platform: homeassistant
    id: lights_switch
    entity_id: switch.lumieres_salle_a_manger
    on_state:
      then:
        - component.update: touchscreen_lcd

  - platform: touchscreen
    id: climate_away_touchscreen_button
    internal: true
    x_min: 31
    x_max: 71
    y_min: 95
    y_max: 135
    page_id: climate
    on_state: 
      then:
        - script.execute:
            id: climate_away_script
        - sensor.template.publish:
            id: climate_new_temperature
            state: !lambda |-
              return id(climate_away_temperature).state;

  - platform: touchscreen
    id: climate_sleep_touchscreen_button
    internal: true
    x_min: 70
    x_max: 110
    y_min: 38
    y_max: 78
    page_id: climate
    on_state: 
      then:
        - script.execute:
            id: climate_sleep_script
        - sensor.template.publish:
            id: climate_new_temperature
            state: !lambda |-
              return id(climate_sleep_temperature).state;

  - platform: touchscreen
    id: climate_home_touchscreen_button
    internal: true
    x_min: 140
    x_max: 180
    y_min: 38
    y_max: 78
    page_id: climate
    on_state: 
      then:
        - script.execute:
            id: climate_home_script
        - sensor.template.publish:
            id: climate_new_temperature
            state: !lambda |-
              return id(climate_home_temperature).state;

  - platform: touchscreen
    id: climate_comfort_touchscreen_button
    internal: true
    x_min: 179
    x_max: 219
    y_min: 95
    y_max: 135
    page_id: climate
    on_state: 
      then:
        - script.execute:
            id: climate_comfort_script
        - sensor.template.publish:
            id: climate_new_temperature
            state: !lambda |-
              return id(climate_comfort_temperature).state;

sensor:
  - platform: rotary_encoder
    id: touchscreen_rotary
    internal: true
    pin_a: 
      number: GPIO40
      mode:
       input: true
       pullup: true
    pin_b: 
      number: GPIO41
      mode:
       input: true
       pullup: true
    accuracy_decimals: 0
    on_value: 
      - then:
        - script.execute:
            id: touchscreen_display_set_countdown
    on_clockwise: 
      - then:
        - script.execute:
            id: climate_new_temperature_up_script
    on_anticlockwise: 
      - then:
        - script.execute:
            id: climate_new_temperature_down_script
        
  - platform: template
    id: climate_new_temperature
    name: Nouvelle temperature

  - platform: homeassistant
    id: climate_target_temperature
    entity_id: climate.thermostat_principal
    attribute: temperature
    on_value:
      then:
        - component.update: touchscreen_lcd

  - platform: homeassistant
    id: climate_current_temperature
    entity_id: climate.thermostat_principal
    attribute: current_temperature
    on_value:
      then:
        - component.update: touchscreen_lcd

  - platform: homeassistant
    id: climate_min_temperature
    entity_id: climate.thermostat_principal
    attribute: min_temp
    on_value:
      then:
        - component.update: touchscreen_lcd

  - platform: homeassistant
    id: climate_max_temperature
    entity_id: climate.thermostat_principal
    attribute: max_temp
    on_value:
      then:
        - component.update: touchscreen_lcd

text_sensor:
  - platform: template
    id: climate_mode
    name: Mode du thermostat
    on_value:
      then:
        - component.update: touchscreen_lcd

  - platform: template
    id: mode
    name: Mode
    on_value:
      then:
        - script.execute:
            id: change_display_page

button:
  - platform: template
    id: climate_away_button
    name: Mode Absent
    on_press:
      then:
        - script.execute:
            id: climate_away_script

  - platform: template
    id: climate_sleep_button
    name: Mode Couché
    on_press:
      then:
        - script.execute:
            id: climate_sleep_script

  - platform: template
    id: climate_home_button
    name: Mode Maison
    on_press:
      then:
        - script.execute:
            id: climate_home_script

  - platform: template
    id: climate_comfort_button
    name: Mode Boost
    on_press:
      then:
        - script.execute:
            id: climate_comfort_script


light:
  - platform: monochromatic
    id: touchscreen_back_lighting
    name: Retro eclairage
    internal: true
    output: touchscreen_back_lighting_output
    default_transition_length: 500ms

output:
  - id: touchscreen_back_lighting_output
    platform: ledc
    pin: GPIO09
    max_power: 1
    min_power: 0
````Preformatted text`
4 Likes

I make a 3d adaptateur for the french “leGrand” switch plate.
And i print it with my 3d printer

A minor bug in that code I think is that when the current temperature is above the setpoint temperature (i.e. cooling rather than heating), the gap is not shown. The bar is only shown when the current temp is less than the target temp.

I’m sure it’s an easy fix, but haven’t looked at it in great detail - it took me a little while to figure out what was going on in the first place :smiley:

Nope i have the same behavior than the home assistant climate.

I make a capture of my video when the target temperature is lesser then the actual temperature.

It was colours
 have to remember to change the hex code when you tweak the colours :man_facepalming:

1 Like

Anyone using this as kitchen timer?

Hi @Squall290586 ,

Thnx for the code

I got errors on the colors. Do you have someting in your config that you can share

(venv) [richard@X360-G8 ~]$ esphome run m5dial.yaml
INFO ESPHome 2024.2.2
INFO Reading configuration m5dial.yaml...
INFO Updating https://github.com/dgaust/esphome.git@gc9a01
INFO Updating https://github.com/esphome/esphome.git@pull/6096/head
INFO Detected timezone 'Europe/Amsterdam'
Failed config

display.gc9a01: [source m5dial.yaml:494]
  platform: gc9a01
  id: touchscreen_lcd
  reset_pin:
    number: 8
    mode:
      output: True
      input: False
      open_drain: False
      pullup: False
      pulldown: False
    inverted: False
    ignore_strapping_warning: False
    drive_strength: 20.0
  cs_pin:
    number: 7
    mode:
      output: True
      input: False
      open_drain: False
      pullup: False
      pulldown: False
    inverted: False
    ignore_strapping_warning: False
    drive_strength: 20.0
  dc_pin:
    number: 4
    mode:
      output: True
      input: False
      open_drain: False
      pullup: False
      pulldown: False
    inverted: False
    ignore_strapping_warning: False
    drive_strength: 20.0
  rotation: 90
  update_interval: 1h
  pages:  [source m5dial.yaml:501]
    - id: lights

      Couldn't find ID 'activated_button_color'. Please check you have defined an ID with that name in your configuration.
      lambda: !lambda |-
        // Variables
        float screenheight = it.get_height();
        float screenwidth = it.get_width();
        float halfscreenheight = screenheight / 2;
        float halfscreenwidth = screenwidth / 2;
        it
          .image(
            halfscreenwidth,
            halfscreenheight,
            lights_icon,
            ImageAlign::CENTER,
            (id(lights_switch).state) ? id(activated_button_color) : id(desactivated_button_color));

        // Display the swith menu
        it.filled_circle(halfscreenwidth -6, 225, 3);
        it.circle(halfscreenwidth +6, 225, 3);
    - [source m5dial.yaml:501]
      id: climate

      Couldn't find ID 'dark_orange'. Please check you have defined an ID with that name in your configuration.
      lambda: !lambda |-
        // Variables
        float screenheight = it.get_height();
        float screenwidth = it.get_width();
        float halfscreenheight = screenheight / 2;
        float halfscreenwidth = screenwidth / 2;
        float currentTemperatureCircleAngle = (360 - id(climate_bottom_gauge_angle).state) * ((id(climate_current_temperature).state - id(climate_min_temperature).state) / (id(climate_max_temperature).state - id(climate_min_temperature).state));
        float targetTemperatureCircleAngle = (360 - id(climate_bottom_gauge_angle).state) * ((id(climate_new_temperature).state - id(climate_min_temperature).state) / (id(climate_max_temperature).state - id(climate_min_temperature).state));
        float startAngle = id(climate_bottom_gauge_angle).state / 2;
        float firstStepAngle = (currentTemperatureCircleAngle < targetTemperatureCircleAngle) ? currentTemperatureCircleAngle : targetTemperatureCircleAngle;
        float secondStepAngle = (currentTemperatureCircleAngle > targetTemperatureCircleAngle) ? firstStepAngle : targetTemperatureCircleAngle;
        float endAngle = 360 - id(climate_bottom_gauge_angle).state;

        // Display temperature arc circle
        it
          .filled_circle(
            halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle) * id(pi).state / 180),
            halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle) * id(pi).state / 180),
            5,
            id(dark_orange));
        it
          .filled_circle(
            halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + endAngle) * id(pi).state / 180),
            halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + endAngle) * id(pi).state / 180),
            5,
            id(gray));

        for (int i = startAngle; i <= startAngle + firstStepAngle; i++) {
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(dark_orange));
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(dark_orange));
        }
        for (int i = startAngle + firstStepAngle; i <= startAngle + secondStepAngle; i++) {
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(orange));
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(orange));
        }
        for (int i = startAngle + secondStepAngle; i <= startAngle + endAngle; i++) {
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(gray));
          it
            .filled_triangle(
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + i) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + i) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 5) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 5) * sin((90 + (i + 1)) * id(pi).state / 180),
              halfscreenwidth + (halfscreenwidth - 15) * cos((90 + (i + 1)) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 15) * sin((90 + (i + 1)) * id(pi).state / 180),
              id(gray));
        }

        // Current temperature round
        it
          .filled_circle(
            halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + currentTemperatureCircleAngle) * id(pi).state / 180),
            halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + currentTemperatureCircleAngle) * id(pi).state / 180),
            2,
            id(white));

        // Start of the second step
        if (firstStepAngle < secondStepAngle) {
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + firstStepAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + firstStepAngle) * id(pi).state / 180),
              5,
              id(orange));
          it
            .filled_circle(
              halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + firstStepAngle) * id(pi).state / 180),
              halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + firstStepAngle) * id(pi).state / 180),
              2,
              id(dark_orange));
        }

        // Target temperature round
        it
          .filled_circle(
            halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
            halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
            7,
            id(orange));
        it
          .filled_circle(
            halfscreenwidth + (halfscreenwidth - 10) * cos((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
            halfscreenheight + (halfscreenheight - 10) * sin((90 + startAngle + targetTemperatureCircleAngle) * id(pi).state / 180),
            5,
            id(white));

        // Dislay icons
        it
          .image(
            halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 - 1.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180),
            halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 - 1.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180),
            climate_away_mode_icon,
            ImageAlign::CENTER,
            (strcmp(id(climate_mode).state.c_str(), "away") == 0) ? id(activated_button_color) : id(desactivated_button_color));
        it
          .image(
            halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 - 0.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180),
            halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 - 0.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180),
            climate_sleep_mode_icon,
            ImageAlign::CENTER,
            (strcmp(id(climate_mode).state.c_str(), "sleep") == 0) ? id(activated_button_color) : id(desactivated_button_color));
        it
          .image(
            halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 + 0.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180),
            halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 + 0.5 * id(climate_icon_separation_angle).state) *id(pi).state / 180),
            climate_home_mode_icon,
            ImageAlign::CENTER,
            (strcmp(id(climate_mode).state.c_str(), "home") == 0) ? id(activated_button_color) : id(desactivated_button_color));
        it
          .image(
            halfscreenwidth + halfscreenwidth * id(climate_icon_distance_radius).state * cos((-90 + 1.5 * id(climate_icon_separation_angle).state) * id(pi).state / 180),
            halfscreenheight + halfscreenheight * id(climate_icon_distance_radius).state * sin((-90 + 1.5 * id(climate_icon_separation_angle).state)*id(pi).state / 180),
            climate_comfort_mode_icon,
            ImageAlign::CENTER,
            (strcmp(id(climate_mode).state.c_str(), "comfort") == 0) ? id(activated_button_color) : id(desactivated_button_color));

        // Display temperature
        it.printf(halfscreenwidth, halfscreenheight - id(climate_temperature_distance_from_center).state, id(roboto40), TextAlign::TOP_CENTER, "%2.1f", id(climate_new_temperature).state, id(white));
        it.printf(halfscreenwidth, halfscreenheight - id(climate_temperature_distance_from_center).state + 40, id(roboto20), TextAlign::TOP_CENTER, "%2.1f", id(climate_current_temperature).state, id(white));
        it
          .image(
            halfscreenwidth - 40,
            halfscreenheight - id(climate_temperature_distance_from_center).state + 42,
            climate_thermometer_icon,
            ImageAlign::TOP_LEFT,
            id(white));
        it
          .image(
            halfscreenwidth + 20,
            halfscreenheight - id(climate_temperature_distance_from_center).state + 42,
            climate_celcius_icon,
            ImageAlign::TOP_LEFT,
            id(white));
        it
          .image(
            halfscreenwidth,
            halfscreenheight - id(climate_temperature_distance_from_center).state + 92,
            climate_fire_icon,
            ImageAlign::CENTER,
            (id(climate_new_temperature).state > id(climate_current_temperature).state) ? id(red) : id(gray));

        // Display the swith menu
        it.circle(halfscreenwidth - 6, 225, 3);
        it.filled_circle(halfscreenwidth + 6, 225, 3); [source m5dial.yaml:522]
  auto_clear_enabled: True
  width: 240
  height: 240
  offset_y: 0
  offset_x: 0
  eight_bit_color: False
Couldn't find ID 'dark_orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'dark_orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'gray'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'gray'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'dark_orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'orange'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'activated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'desactivated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'activated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'desactivated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'activated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'desactivated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'activated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'desactivated_button_color'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'white'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'red'. Please check you have defined an ID with that name in your configuration.

Couldn't find ID 'gray'. Please check you have defined an ID with that name in your configuration.

The warnings relate to color definitions, make sure you define colours and they’re correctly referenced.

I added the colors. Now I have some other errors

m5dial.yaml: In lambda function:
m5dial.yaml:526:11: error: 'lights_icon' was not declared in this scope
m5dial.yaml:526:11: note: suggested alternative: 'lights'
m5dial.yaml: In lambda function:
m5dial.yaml:666:11: error: 'climate_away_mode_icon' was not declared in this scope
m5dial.yaml:666:11: note: suggested alternative: 'climate_away_button'
m5dial.yaml:673:11: error: 'climate_sleep_mode_icon' was not declared in this scope
Compiling .pioenvs/m5dial/lib445/ESPmDNS/ESPmDNS.cpp.o
m5dial.yaml:673:11: note: suggested alternative: 'climate_sleep_button'
m5dial.yaml:680:11: error: 'climate_home_mode_icon' was not declared in this scope
m5dial.yaml:680:11: note: suggested alternative: 'climate_home_button'
m5dial.yaml:687:11: error: 'climate_comfort_mode_icon' was not declared in this scope
m5dial.yaml:687:11: note: suggested alternative: 'climate_comfort_duration'
m5dial.yaml:698:11: error: 'climate_thermometer_icon' was not declared in this scope
m5dial.yaml:698:11: note: suggested alternative: 'climate_home_button'
m5dial.yaml:705:11: error: 'climate_celcius_icon' was not declared in this scope
m5dial.yaml:705:11: note: suggested alternative: 'climate_comfort_button'
m5dial.yaml:712:11: error: 'climate_fire_icon' was not declared in this scope
m5dial.yaml:712:11: note: suggested alternative: 'climate_home_button'
Compiling .pioenvs/m5dial/lib1c7/Update/HttpsOTAUpdate.cpp.o
Compiling .pioenvs/m5dial/lib1c7/Update/Updater.cpp.o
Compiling .pioenvs/m5dial/libf34/SPI/SPI.cpp.o
Compiling .pioenvs/m5dial/liba4d/Wire/Wire.cpp.o
Compiling .pioenvs/m5dial/FrameworkArduino/Esp.cpp.o
Archiving .pioenvs/m5dial/lib445/libESPmDNS.a
Archiving .pioenvs/m5dial/libf34/libSPI.a
Archiving .pioenvs/m5dial/lib405/libWiFi.a
Indexing .pioenvs/m5dial/lib445/libESPmDNS.a
Indexing .pioenvs/m5dial/libf34/libSPI.a
Indexing .pioenvs/m5dial/lib405/libWiFi.a
Compiling .pioenvs/m5dial/FrameworkArduino/FirmwareMSC.cpp.o
Compiling .pioenvs/m5dial/FrameworkArduino/FunctionalInterrupt.cpp.o
Compiling .pioenvs/m5dial/FrameworkArduino/HWCDC.cpp.o
Compiling .pioenvs/m5dial/FrameworkArduino/HardwareSerial.cpp.o
*** [.pioenvs/m5dial/src/main.cpp.o] Error 1

I would suggest if you’re trying to implement this, you investigate the errors yourself. Use it as a good learning opportunity.

The error messages are pretty clear on what the issue is.

2 Likes

Hello,

I’m currently attempting to compile the YAML code for my M5Dial. I’ve referenced the icons using the image component and MDI reference.

Following the ESPHome instructions, I’ve installed Pillow and CairoSVG add-ons in my Python environment. However, I’m encountering compilation errors due to the following:

no library called “cairo” was found
no library called “libcairo-2” was found

I’ve tried searching for a solution, but so far, I haven’t had any luck. Does anyone have an idea how to fix this issue? I’m using ESPHome in a Windows environment.

EDIT 12-03-2024
I overcome the problem of missing DLL in my esphome compilation toolchain downloading the icon bmp image locally and not usign MDI reference in the Yaml

Now the code compiles but the result on the M5dial is messed up and inconsistent
@Squall290586 Would you mind to share the complete code so I can play around and try to compile correclty ?

Thank you, Davide