Unable to upload code due to an error

Hello,

I am getting the below error when trying to upload my changed code, also below:

Error:

INFO ESPHome 2023.8.0
INFO Reading configuration /config/esphome/sop-power-monitor.yaml...
WARNING GPIO0 is a Strapping PIN and should be avoided.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
WARNING GPIO4 is a Strapping PIN and should be avoided.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Detected timezone 'Australia/Sydney'
ERROR Unexpected exception while reading configuration:
Traceback (most recent call last):
  File "/usr/local/bin/esphome", line 33, in <module>
    sys.exit(load_entry_point('esphome', 'console_scripts', 'esphome')())
  File "/esphome/esphome/__main__.py", line 1023, in main
    return run_esphome(sys.argv)
  File "/esphome/esphome/__main__.py", line 1001, in run_esphome
    config = read_config(dict(args.substitution) if args.substitution else {})
  File "/esphome/esphome/config.py", line 986, in read_config
    res = load_config(command_line_substitutions)
  File "/esphome/esphome/config.py", line 840, in load_config
    return _load_config(command_line_substitutions)
  File "/esphome/esphome/config.py", line 828, in _load_config
    result = validate_config(config, command_line_substitutions)
  File "/esphome/esphome/config.py", line 756, in validate_config
    result.run_validation_steps()
  File "/esphome/esphome/config.py", line 125, in run_validation_steps
    task.step.run(self)
  File "/esphome/esphome/config.py", line 507, in run
    validated = schema(self.conf)
  File "/esphome/esphome/voluptuous_schema.py", line 34, in __call__
    res = super().__call__(data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/validators.py", line 229, in _run
    return self._exec(self._compiled, value, path)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/validators.py", line 353, in _exec
    v = func(path, v)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
  File "/esphome/esphome/voluptuous_schema.py", line 34, in __call__
    res = super().__call__(data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/validators.py", line 229, in _run
    return self._exec(self._compiled, value, path)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/validators.py", line 353, in _exec
    v = func(path, v)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
  File "/esphome/esphome/voluptuous_schema.py", line 148, in validate_mapping
    cval = cvalue(key_path, value)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
  File "/esphome/esphome/voluptuous_schema.py", line 34, in __call__
    res = super().__call__(data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.9/dist-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
  File "/esphome/esphome/components/image/__init__.py", line 174, in _file_schema
    return validate_file_shorthand(value)
  File "/esphome/esphome/components/image/__init__.py", line 130, in validate_file_shorthand
    validate_cairosvg_installed(value)
  File "/esphome/esphome/components/image/__init__.py", line 80, in validate_cairosvg_installed
    import cairosvg
  File "/usr/local/lib/python3.9/dist-packages/cairosvg/__init__.py", line 26, in <module>
    from . import surface  # noqa isort:skip
  File "/usr/local/lib/python3.9/dist-packages/cairosvg/surface.py", line 9, in <module>
    import cairocffi as cairo
  File "/usr/local/lib/python3.9/dist-packages/cairocffi/__init__.py", line 47, in <module>
    cairo = dlopen(
  File "/usr/local/lib/python3.9/dist-packages/cairocffi/__init__.py", line 44, in dlopen
    raise OSError(error_message)  # pragma: no cover
OSError: no library called "cairo-2" was found
no library called "cairo" was found
no library called "libcairo-2" was found
cannot load library 'libcairo.so.2': libcairo.so.2: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called 'libcairo.so.2'
cannot load library 'libcairo.2.dylib': libcairo.2.dylib: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called 'libcairo.2.dylib'
cannot load library 'libcairo-2.dll': libcairo-2.dll: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called 'libcairo-2.dll'

Code:

esphome:
  name: sop-power-monitor
  friendly_name: sop-power-monitor

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "XXX"

ota:
  password: "XXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Sop-Power-Monitor"
    password: "XXX"

captive_portal:


color:
  - id: my_red
    red: 100%
    green: 0%
    blue: 0%
  - id: my_yellow
    red: 100%
    green: 100%
    blue: 0%
  - id: my_green
    red: 0%
    green: 100%
    blue: 0%
  - id: my_blue
    red: 23.92%
    green: 65.1%
    blue: 84.71%
  - id: my_gray
    red: 50%
    green: 50%
    blue: 50%

binary_sensor:
  - platform: status
    name: "Node Status"
    id: system_status
  - platform: gpio
    pin:
      number: GPIO0
      inverted: true
      mode:
        input: true
        pullup: true
    name: "T-Display Button Input 0"
    id: tdisplay_button_input_0
  - platform: gpio
    pin:
      number: GPIO35
      inverted: true
    name: "T-Display Button Input 1"
    id: tdisplay_button_input_1

# We can still control the backlight independently
switch:
  - platform: gpio
    pin: GPIO4
    name: "Backlight"
    id: backlight

time:
  - platform: homeassistant
    id: esptime

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO19

font:
  - file: "gfonts://Audiowide"
    id: audiowide_48
    size: 48
  - file: "gfonts://Audiowide"
    id: audiowide_20
    size: 20
  - file: "gfonts://Audiowide"
    id: audiowide_18
    size: 18
  - file: "gfonts://Audiowide"
    id: audiowide_14
    size: 14
  - file: "gfonts://Audiowide"
    id: audiowide_12
    size: 12
    

image:
  - file: "bck_gauge.png"
    id: background
    type: RGB24
  - file: mdi:lan-connect
    id: connected
    resize: 20x20
  - file: mdi:wifi-remove
    id: disconnected
    resize: 20x20

display:
  - platform: st7789v
    model: TTGO TDisplay 135x240
    backlight_pin: GPIO4
    cs_pin: GPIO5
    dc_pin: GPIO16
    reset_pin: GPIO23
    rotation: 90
    pages:
      - id: home
        lambda: |-
          it.image(0, 0, id(background));

          // Header
          it.print(2, 5, id(audiowide_14), id(my_gray), TextAlign::TOP_LEFT, "Smart Power-meter");
          it.strftime(215, 5, id(audiowide_14), id(my_gray), TextAlign::TOP_RIGHT, "%H:%M", id(esptime).now());
              if (id(system_status).state) {
              it.image(240, 5, id(connected), ImageAlign::TOP_RIGHT);
          } else {
              it.image(240, 5, id(disconnected), ImageAlign::TOP_RIGHT);
          }

          // Values of current and daily consumed power
          it.printf(5, 50 + 5, id(audiowide_20), id(my_gray), TextAlign::TOP_LEFT, "%.1fW", id(current_power).state*1000.0);
          it.printf(5, 80 + 5, id(audiowide_20), id(my_gray), TextAlign::TOP_LEFT, "%.2fkW/h", id(daily_power).state);
          it.printf(5, 110 + 5, id(audiowide_20), id(my_gray), TextAlign::TOP_LEFT, "%.2fAUD", id(daily_cost).state);

          // Real time consumption indicator
          float pi = 3.141592653589793;
          float alpha = 4.71238898038469; // Defined as the gauge angle in radians (270deg)
          float beta = 2*pi - alpha;
          int radius = 42;              // Radius of the gauge in pixels
          int thick = 7;                // Size of the marker 
          int needle_radius= 9;

          int min_range = 0; 
          int max_range = 10;
          int xc = 180;
          int yc = 85;
          
          float measured = id(current_power).state;
          
          if (measured < min_range) {
            measured = min_range;
          } 
          if (measured > max_range) {
            measured = max_range;
          } 
          
          float val = (measured - min_range) / abs(max_range - min_range) * alpha;
          
          int xc0 = static_cast<int>(xc);
          int yc0 = static_cast<int>(yc);
          int x0 = static_cast<int>(xc + radius * cos(pi / 2 + beta / 2 + val));
          int y0 = static_cast<int>(yc + radius * sin(pi / 2 + beta / 2 + val));
          int x1 = static_cast<int>(xc + needle_radius * cos(pi / 2 + beta / 2 + val + 0.1));
          int y1 = static_cast<int>(yc + needle_radius * sin(pi / 2 + beta / 2 + val + 0.1));
          int x2 = static_cast<int>(xc + needle_radius * cos(pi / 2 + beta / 2 + val - 0.1));
          int y2 = static_cast<int>(yc + needle_radius * sin(pi / 2 + beta / 2 + val - 0.1));
          int x3 = static_cast<int>(xc + needle_radius * cos(pi / 2 + beta / 2 + val + 0.2));
          int y3 = static_cast<int>(yc + needle_radius * sin(pi / 2 + beta / 2 + val + 0.2));
          int x4 = static_cast<int>(xc + needle_radius * cos(pi / 2 + beta / 2 + val - 0.2));
          int y4 = static_cast<int>(yc + needle_radius * sin(pi / 2 + beta / 2 + val - 0.2));
          int x5 = static_cast<int>(xc + needle_radius * cos(pi / 2 + beta / 2 + val));
          int y5 = static_cast<int>(yc + needle_radius * sin(pi / 2 + beta / 2 + val));
          it.line(x0, y0, x1, y1, id(my_blue));
          it.line(x0, y0, x2, y2, id(my_blue));
          it.line(x0, y0, x3, y3, id(my_blue));
          it.line(x0, y0, x4, y4, id(my_blue));
          it.line(x0, y0, x5, y5, id(my_blue));
          


      
sensor:
  - platform: homeassistant
    id: daily_cost
    name: "Daily cost"
    entity_id: sensor.total_daily_power_cost

  - platform: homeassistant
    id: daily_cost
    name: "Daily cost"
    entity_id: sensor.total_daily_power_cost

  - platform : homeassistant
    id: rms_volts
    name: RMS Voltage
    entity_id: sensor.esp_ble_10_pzem_004t_pzem_004t_v3_voltage

  - platform : homeassistant
    id: current_power
    name: SOP Power
    entity_id: sensor.esp_ble_10_pzem_004t_pzem_004t_v3_power


#  - platform: adc
#    pin: A0
#    id: LDR
#    name: "LDR"
#    update_interval: 5s
#    on_value_range:
#      - above: 0.1
#        then:
#          - switch.turn_on: backlight
#      - below: 0.1
#        then:
#          - switch.turn_off: backlight
    
  - platform: adc
    pin: A3
    id: Input_1
    attenuation: 11db
    update_interval: 1s
    
  - platform: adc
    pin: A4
    id: Input_2
    attenuation: 11db
    update_interval: 1s
    
  - platform: adc
    pin: A5
    id: Input_3
    attenuation: 11db
    update_interval: 1s
   
  - platform: ct_clamp
    sensor: Input_1
    id: Probe_1
    name: "Probe 1"
    sample_duration: 200ms
    update_interval: 1s
    filters:
      - calibrate_linear:
          - 0 -> 0
          - 0.042 -> 2.72
   
  - platform: ct_clamp
    sensor: Input_2
    name: "Probe 2"
    id: Probe_2
    sample_duration: 200ms
    update_interval: 1s
    filters:
      - calibrate_linear:
          - 0 -> 0
          - 0.033 -> 1.07
   
  - platform: ct_clamp
    sensor: Input_3
    name: "Probe 3"
    id: Probe_3
    sample_duration: 200ms
    update_interval: 1s
    filters:
      - calibrate_linear:
          - 0 -> 0
          - 0.022 -> 0.66
    
  - platform: total_daily_energy
    name: "Total Daily Power"
    power_id: current_power
    id: daily_power

#  - platform: template
#    id: current_power
#    name: "Measured Power"
#    lambda: return (id(Probe_1).state + id(Probe_2).state + id(Probe_3).state) * 230.0 / 1000; #Power = Current * Voltage 
#    unit_of_measurement: 'kW'
#    update_interval: 5s

I have tried reading through but I cannot see what is wrong, can someone please assist me ?

Thank you

I’m having the same problem on Esphome 2023.8.0
Try posting on Esphome github page

They just dropped 8.1. Didn’t pay attention to the notes, but maybe it fixed it?

Still happening on 8.1

Did you post on Github for solution?

found yours

Having the same issue…

I had a similar missing libcairo-2 issue with material design icons but in my case it was because I’m using Windows to compile esphome.

I found the answer here: https://stackoverflow.com/questions/73637315/oserror-no-library-called-cairo-2-was-found-from-custom-widgets-import-proje

Solution was a simple as:

pip install pipwin
pipwin install cairocffi