Hi all,
Some time ago a component of my Mitsubishi ac units was end of life and had to be replaced. This was fine after some changes but now I have an error again regarding the .yaml.
When I try to update I get the following error:
INFO ESPHome 2025.11.1
INFO Reading configuration /config/esphome/badkamer-airco.yaml...
ERROR Unable to load component custom.climate:
Traceback (most recent call last):
File "/esphome/esphome/loader.py", line 199, in _lookup_module
module = importlib.import_module(f"esphome.components.{domain}")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 999, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "/data/external_components/da3a5f72/components/custom/climate/__init__.py", line 14, in <module>
cv.Required(CONF_CLIMATES): cv.ensure_list(climate.CLIMATE_SCHEMA),
^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'esphome.components.climate' has no attribute 'CLIMATE_SCHEMA'. Did you mean: '_CLIMATE_SCHEMA'?
Failed config
Platform not found: 'climate.custom'
This is the .yaml:
substitutions:
# Unique device ID in HA
deviceid: "badkamer_airco" #deviceid: "mhi_woonkamer"
# Unique device name in HA (sensor names will be prefixed by this name)
devicename: "Badkamer airco" #devicename: "MHI-Woonkamer"
esphome:
name: badkamer-airco #name: mhi-woonkamer # Unique name (only change in small letters)
platformio_options:
# Run CPU at 160Mhz to fix mhi_ac_ctrl_core.loop error: -2
board_build.f_cpu: 160000000L
includes:
- mhi_ac_ctrl.h
- MHI-AC-Ctrl-core.h
- MHI-AC-Ctrl-core.cpp
esp8266:
board: d1_mini
framework:
version: recommended
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
#ssid: "hierjesidd"
#password: "hierjeww"
fast_connect: true # misschien hier een hekje voor zetten?
manual_ip:
# Set this to the IP of the ESP
static_ip: 192.168.1.88
# Set this to the IP address of the router. Often ends with .1
gateway: 192.168.1.1
# The subnet of the network. 255.255.255.0 works for most home networks.
subnet: 255.255.255.0
# Enable fallback hotspot (captive portal) in case wifi connection fails
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${devicename}"
password: "configesp"
captive_portal:
logger:
level: DEBUG
baud_rate: 0
globals:
- id: room_temp_api_timeout
type: int
restore_value: no
initial_value: '120'
ota:
- platform: esphome
web_server:
port: 80
external_components:
- source:
type: git
url: https://github.com/robertklep/esphome-custom-component
components: [ custom, custom_component ]
climate:
- platform: custom
lambda: |-
auto mhi_ac_ctrl = new MhiAcCtrl();
App.register_component(mhi_ac_ctrl);
return {mhi_ac_ctrl};
climates:
- name: "${devicename}"
id: ${deviceid}
api:
reboot_timeout: 0s
services:
# Call the set_api_room_temperature service from HA to override the room temperature
# If a new value has not been received after room_temp_api_timeout seconds, it will fall back to internal sensor
- service: set_api_room_temperature
variables:
value: float
then:
- lambda: |-
return ((MhiAcCtrl*)id(${deviceid}))->set_room_temperature(value);
# Call the set_vanes service from HA to set the vane position
# Needed because the ESPHome Climate class does not support this natively
# Possible values: 1-4: static positions, 5: swing, 0: unknown
- service: set_vanes
variables:
value: int
then:
- lambda: |-
return ((MhiAcCtrl*)id(${deviceid}))->set_vanes(value);
sensor:
- platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
name: ${devicename} WiFi Signal db
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy # Reports the WiFi signal strength in %
source_id: wifi_signal_db
name: ${devicename} WiFi Signal
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "%"
entity_category: diagnostic
- platform: uptime
name: ${devicename} Uptime
unit_of_measurement: days
update_interval: 3600s
accuracy_decimals: 1
filters:
- multiply: 0.000011574
- platform: custom
lambda: |-
return ((MhiAcCtrl*)id(${deviceid}))->get_sensors();
# Sensor names in HA, you can change these if you want
# Don't delete them or change their position in the list
sensors:
- name: ${devicename} error code
- name: ${devicename} outdoor temperature
- name: ${devicename} return air temperature
- name: ${devicename} outdoor unit fan speed
- name: ${devicename} indoor unit fan speed
- name: ${devicename} current power
- name: ${devicename} compressor frequency
- name: ${devicename} indoor unit total run time
- name: ${devicename} compressor total run time
- name: ${devicename} vanes
id: vanes_UD_received
on_value:
then:
- lambda: |-
float received_value = id(vanes_UD_received).state;
if (received_value == 1.0) {
id(fan_control_ud).publish_state("Up");
} else if (received_value == 2.0) {
id(fan_control_ud).publish_state("Up/Center");
} else if (received_value == 3.0) {
id(fan_control_ud).publish_state("Center/Down");
} else if (received_value == 4.0) {
id(fan_control_ud).publish_state("Down");
} else if (received_value == 5.0) {
id(fan_control_ud).publish_state("Swing");
}
- name: ${devicename} energy used
- name: ${devicename} Indoor (U-bend) HE temp 1
- name: ${devicename} Indoor (capillary) HE temp 2
- name: ${devicename} Indoor (suction header) HE temp 3
- name: ${devicename} Outdoor HE temp
- name: ${devicename} Outdoor unit exp. valve
- name: ${devicename} Outdoor unit discharge pipe
- name: ${devicename} Outdoor unit discharge pipe super heat
- name: ${devicename} Protection error state
- name: ${devicename} Vanes Left Right
id: vanes_LR_received
on_value:
then:
- lambda: |-
float received_value = id(vanes_LR_received).state;
if (received_value == 1.0) {
id(fan_control_lr).publish_state("Left");
} else if (received_value == 2.0) {
id(fan_control_lr).publish_state("Left/Center");
} else if (received_value == 3.0) {
id(fan_control_lr).publish_state("Center");
} else if (received_value == 4.0) {
id(fan_control_lr).publish_state("Center/Right");
} else if (received_value == 5.0) {
id(fan_control_lr).publish_state("Right");
} else if (received_value == 6.0) {
id(fan_control_lr).publish_state("Wide");
} else if (received_value == 7.0) {
id(fan_control_lr).publish_state("Spot");
} else if (received_value == 8.0) {
id(fan_control_lr).publish_state("Swing");
}
- name: ${devicename} 3D Auto
id: Dauto_received
on_value:
then:
- lambda: |-
bool received_value = id(Dauto_received).state;
if (received_value) {
ESP_LOGD("main", "received 3DAuto from AC");
id(fan_control_3Dauto).publish_state(true);
}
else {
ESP_LOGD("main", "received 3DAuto off from AC");
id(fan_control_3Dauto).publish_state(false);
}
binary_sensor:
- platform: custom
lambda: |-
return ((MhiAcCtrl*)id(${deviceid}))->get_binary_sensors();
binary_sensors:
- name: ${devicename} defrost
text_sensor:
- platform: version
name: ${devicename} ESPHome Version
- platform: wifi_info
ip_address:
name: ${devicename} IP
ssid:
name: ${devicename} SSID
bssid:
name: ${devicename} BSSID
- platform: custom
lambda: |-
return ((MhiAcCtrl*)id(${deviceid}))->get_text_sensors();
text_sensors:
- name: ${devicename} Protection error state
select:
- platform: template
name: ${devicename} Fan Control Left Right
id: fan_control_lr
icon: mdi:arrow-left-right
optimistic: true
options:
# - "3D Auto"
- "Left"
- "Left/Center"
- "Center"
- "Center/Right"
- "Right"
- "Wide"
- "Spot"
- "Swing"
on_value:
- lambda: |-
auto state = id(fan_control_lr).state.c_str();
ESP_LOGD("main", "Option of my select: %s", state);
uint8_t vanesLR = 0; // Initialize the vanesLR variable
if (id(fan_control_lr).state == "3D Auto") {
id(fan_control_3Dauto).publish_state(true);
} else if (id(fan_control_lr).state == "Left") {
vanesLR = 1;
} else if (id(fan_control_lr).state == "Left/Center") {
vanesLR = 2;
} else if (id(fan_control_lr).state == "Center") {
vanesLR = 3;
} else if (id(fan_control_lr).state == "Center/Right") {
vanesLR = 4;
} else if (id(fan_control_lr).state == "Right") {
vanesLR = 5;
} else if (id(fan_control_lr).state == "Wide") {
vanesLR = 6;
} else if (id(fan_control_lr).state == "Spot") {
vanesLR = 7;
} else if (id(fan_control_lr).state == "Swing") {
vanesLR = 8;
}
if ((vanesLR > 0) & (vanesLR < 9) & (vanesLR != id(vanes_LR_received).state)){
ESP_LOGD("main", "setting vanesLR to: %i", vanesLR);
return ((MhiAcCtrl*)id(${deviceid}))->set_vanesLR(vanesLR);
}
else {
ESP_LOGD("main", "Not setting vanesLR: %i", vanesLR);
}
- platform: template
name: ${devicename} Fan Control Up Down
id: fan_control_ud
icon: mdi:arrow-up-down
optimistic: true
options:
# - "3D Auto"
- "Up"
- "Up/Center"
- "Center/Down"
- "Down"
- "Swing"
on_value:
- lambda: |-
auto state = id(fan_control_lr).state.c_str();
ESP_LOGD("main", "Option of my select: %s", state);
uint8_t vanesUD = 0; // Initialize the vanesUD variable
if (id(fan_control_ud).state == "3D Auto") {
id(fan_control_3Dauto).publish_state(true);
} else if (id(fan_control_ud).state == "Up") {
vanesUD = 1;
} else if (id(fan_control_ud).state == "Up/Center") {
vanesUD = 2;
} else if (id(fan_control_ud).state == "Center/Down") {
vanesUD = 3;
} else if (id(fan_control_ud).state == "Down") {
vanesUD = 4;
} else if (id(fan_control_ud).state == "Swing") {
vanesUD = 5;
}
if ((vanesUD > 0) & (vanesUD < 6) & (vanesUD != id(vanes_UD_received).state)){
ESP_LOGD("main", "setting vanesUD to: %i", vanesUD);
return ((MhiAcCtrl*)id(${deviceid}))->set_vanes(vanesUD);
}
else {
ESP_LOGD("main", "Not setting vanesUD: %i", vanesUD);
}
switch:
- platform: template
name: ${devicename} 3D Auto
id: fan_control_3Dauto
icon: mdi:video-3d
optimistic: true
turn_on_action:
- lambda: |-
if (id(Dauto_received).state !=1){
ESP_LOGD("main", "Turn on 3DAuto");
return ((MhiAcCtrl*)id(${deviceid}))->set_3Dauto(1);
}
turn_off_action:
- lambda: |-
if (id(Dauto_received).state !=0){
ESP_LOGD("main", "Turn off 3DAuto");
return ((MhiAcCtrl*)id(${deviceid}))->set_3Dauto(0);
}
Can anyone point me in the right direction? I don’t like messing with the configuration too much unless I know exactly what I’m doing… Thanks a lot guys!