Hi @dark10
Have no idea what can cause your issue. It looks like there is some problem with libraries. I would recommend to use esp-idf framework instead of Arduino. I have 3 AC working with M5Stamp C3U with latest ESPHome in docker container no issues at all.
Hi, @dark10
Iâm facing the same issue as you but with HON protocol only, I could update my AC using SmartAir2 protocol without any issue. I created a ticket on the link below.
@dark10,
I got a reply from randybb to update the framework type to esp-isf, after the reinstallation, it worked as expected.
Hi guys. I would like to share a breakthrough with my latest home automation project. I recently bought a new Haier aircon, thinking I could connect it to Home Assistant like the old one. However, these newer models come with a built-in âesp32-for-haier,â which was a surprise for me.
Inspired by some amazing articles by MichaĹ GĂłral (thanks for the guide: goral.net.pl/post/replacing-haier-wifi-modules/), I set out to avoid snipping the original wires. But soldering JST connectors to DuPont cables is fiddly. Especially if, like me, you donât have a background in electronics.
So, I made a leap: I designed my own PCB on JLCPCB, complete with pinholes so my Lolin S2 Mini ESP can be soldered on easily and had the factory pre-solder the JST connector for me.
I am genuinely excited about how this turned out. It fits snugly and works perfectly with Home Assistant.
Like that?
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
Do I need to change board to:
board: m5stack-atoms3
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
This is solution for my problem
Hi,
I noticed while using the YAML below i canât controll the indoor temperature (the value read from the built-in sensor). After some research, I found out that this is possible with a Loxone system.
Is this also possible in ESPHome, or has anyone already implemented this successfully?
YAML
esphome:
name: haier-c3
friendly_name: haier-c3
platformio_options:
board_build.flash_mode: dio
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "very secret!"
services:
- service: turn_on
then:
- climate.haier.power_on: haier_ac
- service: turn_off
then:
- climate.haier.power_off: haier_ac
ota:
- platform: esphome
password: "very secret!"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
output_power: 17db
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Haier-C3 Fallback Hotspot"
password: "very secret!"
uart:
baud_rate: 9600
tx_pin: GPIO21
rx_pin: GPIO20
id: haier_uart
climate:
- platform: haier
id: haier_ac
protocol: hon
name: Haier hOn Climate
uart_id: haier_uart
wifi_signal: true
use_external_sensor: true # dit forceert AC om indoor temp van ons te nemen
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- BOOST
- SLEEP
on_alarm_start:
then:
- homeassistant.service:
service: logbook.log
data:
domain: climate
name: Haier hOn Climate
data_template:
message: "Alarm activated ({{ alarm_code }}): {{alarm_message}}"
variables:
alarm_message: !lambda "return message;"
alarm_code: !lambda "return code;"
- homeassistant.service:
service: notify.persistent_notification
data:
title: "Haier hOn Climate: alarm activated"
data_template:
message: "Code: {{ alarm_code }}, message: \"{{ alarm_message }}\""
variables:
alarm_message: !lambda "return message;"
alarm_code: !lambda "return code;"
on_alarm_end:
then:
- homeassistant.service:
service: logbook.log
data:
domain: climate
name: Haier hOn Climate
data_template:
message: "Alarm deactivated ({{ alarm_code }}): {{alarm_message}}"
variables:
alarm_message: !lambda "return message;"
alarm_code: !lambda "return code;"
button:
- platform: haier
haier_id: haier_ac
self_cleaning:
name: Haier hOn Climate start self cleaning
steri_cleaning:
name: Haier hOn Climate start 56°C steri-cleaning
text_sensor:
- platform: haier
haier_id: haier_ac
cleaning_status:
name: Haier hOn Climate cleaning status
protocol_version:
name: Haier hOn Climate protocol version
switch:
- platform: haier
beeper:
name: Haier hOn Climate beeper
health_mode:
name: Haier hOn Climate health mode
display:
name: Haier hOn Climate display
quiet_mode:
name: Haier hOn Climate quiet mode
select:
- platform: template
id: haier_ac_vertical_direction
name: Haier hOn Climate airflow vertical
entity_category: config
icon: mdi:arrow-expand-vertical
update_interval: 5s
options:
- Health Up
- Max Up
- Up
- Center
- Down
- Max Down
- Health Down
- Auto
lambda: >-
switch (id(haier_ac).get_vertical_airflow().value_or(esphome::haier::hon_protocol::VerticalSwingMode::CENTER))
{
case esphome::haier::hon_protocol::VerticalSwingMode::HEALTH_UP:
return std::string("Health Up");
case esphome::haier::hon_protocol::VerticalSwingMode::MAX_UP:
return std::string("Max Up");
case esphome::haier::hon_protocol::VerticalSwingMode::UP:
return std::string("Up");
default:
case esphome::haier::hon_protocol::VerticalSwingMode::CENTER:
return std::string("Center");
case esphome::haier::hon_protocol::VerticalSwingMode::DOWN:
return std::string("Down");
case esphome::haier::hon_protocol::VerticalSwingMode::MAX_DOWN:
return std::string("Max Down");
case esphome::haier::hon_protocol::VerticalSwingMode::HEALTH_DOWN:
return std::string("Health Down");
case esphome::haier::hon_protocol::VerticalSwingMode::AUTO:
case esphome::haier::hon_protocol::VerticalSwingMode::AUTO_SPECIAL:
return std::string("Auto");
}
set_action:
- climate.haier.set_vertical_airflow:
id: haier_ac
vertical_airflow: !lambda >-
if (x == "Health Up")
return esphome::haier::hon_protocol::VerticalSwingMode::HEALTH_UP;
else if (x == "Max Up")
return esphome::haier::hon_protocol::VerticalSwingMode::MAX_UP;
else if (x == "Up")
return esphome::haier::hon_protocol::VerticalSwingMode::UP;
else if (x == "Down")
return esphome::haier::hon_protocol::VerticalSwingMode::DOWN;
else if (x == "Max Down")
return esphome::haier::hon_protocol::VerticalSwingMode::MAX_DOWN;
else if (x == "Health Down")
return esphome::haier::hon_protocol::VerticalSwingMode::HEALTH_DOWN;
else if (x == "Auto")
return esphome::haier::hon_protocol::VerticalSwingMode::AUTO;
else
return esphome::haier::hon_protocol::VerticalSwingMode::CENTER;
- platform: template
id: haier_ac_horizontal_direction
name: Haier hOn Climate airflow horizontal
entity_category: config
icon: mdi:arrow-expand-horizontal
update_interval: 5s
options:
- Max Left
- Left
- Center
- Right
- Max Right
- Auto
lambda: >-
switch (id(haier_ac).get_horizontal_airflow().value_or(esphome::haier::hon_protocol::HorizontalSwingMode::CENTER))
{
case esphome::haier::hon_protocol::HorizontalSwingMode::MAX_LEFT:
return std::string("Max Left");
case esphome::haier::hon_protocol::HorizontalSwingMode::LEFT:
return std::string("Left");
default:
case esphome::haier::hon_protocol::HorizontalSwingMode::CENTER:
return std::string("Center");
case esphome::haier::hon_protocol::HorizontalSwingMode::RIGHT:
return std::string("Right");
case esphome::haier::hon_protocol::HorizontalSwingMode::MAX_RIGHT:
return std::string("Max Right");
case esphome::haier::hon_protocol::HorizontalSwingMode::AUTO:
return std::string("Auto");
}
set_action:
- climate.haier.set_horizontal_airflow:
id: haier_ac
horizontal_airflow: !lambda >-
if (x == "Max Left")
return esphome::haier::hon_protocol::HorizontalSwingMode::MAX_LEFT;
else if (x == "Left")
return esphome::haier::hon_protocol::HorizontalSwingMode::LEFT;
else if (x == "Right")
return esphome::haier::hon_protocol::HorizontalSwingMode::RIGHT;
else if (x == "Max Right")
return esphome::haier::hon_protocol::HorizontalSwingMode::MAX_RIGHT;
else if (x == "Auto")
return esphome::haier::hon_protocol::HorizontalSwingMode::AUTO;
else
return esphome::haier::hon_protocol::HorizontalSwingMode::CENTER;
sensor:
- platform: haier
haier_id: haier_ac
compressor_current:
name: Haier hOn Climate Compressor Current
compressor_frequency:
name: Haier hOn Climate Compressor Frequency
expansion_valve_open_degree:
name: Haier hOn Climate Expansion Valve Open Degree
humidity:
name: Haier hOn Climate Indoor Humidity
indoor_coil_temperature:
name: Haier hOn Climate Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier hOn Climate Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier hOn Climate Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier hOn Climate Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier hOn Climate Outdoor Out Air Temperature
outdoor_temperature:
name: Haier hOn Climate outdoor temperature
power:
name: Haier hOn Climate Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier hOn Climate Compressor Status
defrost_status:
name: Haier hOn Climate Defrost Status
four_way_valve_status:
name: Haier hOn Climate Four-way Valve Status
indoor_electric_heating_status:
name: Haier hOn Climate Indoor Electric Heating Status
indoor_fan_status:
name: Haier hOn Climate Indoor Fan Status
outdoor_fan_status:
name: Haier hOn Climate Outdoor Fan Status
captive_portal:
Loxone Template:
https://library.loxone.com/detail/haier-air-condition-ycj-a002-928/overview
I managed to find some time to assemble the connector and test this integration with my TUNDRA AS18TD2HRA and it works well.
The only annoying thing is the beep at each change from home assistant that canât be disabled with smartair2 protocol.
I was also trying to find a way to lock settings to avoid inappropriate use while not disconnecting the IR remote as it is a bit a radical solution. But it seems challenging.
Iâm having another issue. My esp32 seems to reboot many times but without an apparent regular pattern.
The main problem is that at each reboot the AC split emits a beep sound which is very annoying.
I think the wifi is not very stable near the AC but Iâve already tried to disable reboot_timeout with 0s value but it seems to happen the same.
Iâve configured it to work via mqtt broker and a ble tracker for another sensor in the same room.
I think i will disable haier debug logs as it spams constantly these types of logs and it is difficult to understand if thereâs some other problem.
Maybe should I play with keepalive and reboot_timeout for mqtt settings too? Because iâm having also:
e[0;33m[W][component:424]: Components should block for at most 30 mse[0m
Could share your project for PCB on JLCPCB, please.
Warnings after updating today⌠![]()
Warning: DEPRECATED: 'esptool.py' is deprecated. Please use 'esptool' instead. The '.py' suffix will be removed in a future major release.
Creating ESP32S3 image...
Successfully created ESP32S3 image.
Linking .pioenvs/esphome-web-f7c8bf/firmware.elf
usage: esp_idf_size [-h] [--format {table,text,tree,csv,json2,raw,dot}]
[--archives] [--archive-dependencies] [--dep-symbols]
[--dep-reverse] [--archive-details ARCHIVE_NAME] [--files]
[--diff MAP_FILE] [--no-abbrev] [--unify] [--show-unused]
[--show-unchanged] [--use-flash-size] [--lto] [-d]
[-o OUTPUT_FILE] [-s COLUMN] [-F PATTERN] [--sort-diff]
[--sort-reverse] [-q] [--no-color] [--force-terminal]
[--doc]
MAP_FILE
esp_idf_size: error: unrecognized arguments: --ng
Warning: esp-idf-size exited with code 2
RAM: [= ] 12.9% (used 42388 bytes from 327680 bytes)
Flash: [===== ] 47.4% (used 870050 bytes from 1835008 bytes)
Building .pioenvs/esphome-web-f7c8bf/firmware.bin
Warning: DEPRECATED: 'esptool.py' is deprecated. Please use 'esptool' instead. The '.py' suffix will be removed in a future major release.
I would like to share how finally I was able to make it work with below project from : paveldn â GitHub - paveldn/haier-esphome: Haier ac integration for ESPHome
and Haier ACâs (2 different types).
Initially I was using cheap esp8266 board from aliexpress. I had some old board: WeMos D1 Mini Pro V3.0 NodeMcu 4MB
and I was trying to upload soft there.
For this board i used below yaml config:
esphome:
name: ac-sypialnia
name_add_mac_suffix: true # optional, adds MAC to device name
friendly_name: AC_SYPIALNIA
esp8266:
board: d1_mini
Wi-Fi with fallback AP
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: âESP8266_Fallbackâ
password: âfallbackpasswordâ
Enable UART logging for debug
logger:
baud_rate: 0
level: DEBUG
OTA for future updates
ota:
- platform: esphome
API for Home Assistant
api:
Web server for testing
web_server:
UART for Haier AC communication
uart:
- id: ac_port
tx_pin: 1 # GPIO1 (hardware TX)
rx_pin: 3 # GPIO3 (hardware RX)
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
uart_id: ac_port
wifi_signal: true
display: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step: 1 °C
supported_modes:- âOFFâ
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes: - âOFFâ
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets: - AWAY
- BOOST
- SLEEP
on_alarm_start:
then:- logger.log:
level: WARN
format: âAlarm activated. Code: %d. Message: "%s"â
args: [ code, message ]
on_alarm_end:
then: - logger.log:
level: INFO
format: âAlarm deactivated. Code: %d. Message: "%s"â
args: [ code, message ]
on_status_message:
then: - logger.log:
level: INFO
format: âNew status message received, size=%d, subcmd=%02X%02Xâ
args: [ âdata_sizeâ, âdata[0]â, âdata[1]â ]
- logger.log:
Include local Haier component
packages:
local_haier: !include configs/external_components/local_haier.yaml
it worked like charm. When I was excited that it worked, I decided to equip the remaining air conditioning units with similar ESPs. However, for some reason, I bought slightly different ones this time â a newer model, version 4: WEMOS D1 Mini V4.0.0 TYPE-C.
âŚand thatâs where the problems began. I couldnât get any response from the AC at all.
[14:36:49.146][I][haier.climate:096]: Answer timeout for command 61, phase SENDING_INIT_1
[14:36:53.578][I][haier.climate:096]: Answer timeout for command 01, phase SENDING_FIRST_STATUS_REQUEST
Itâs worth noting here that at that time, my pin configuration in the YAML file was identical to the previous board â I was trying to use RX/TX.
I spent a lot of time experimenting, trying different pins, e.g. tx_pin: 15 and rx_pin: 13.
Sometimes it would start working, but only in certain situations. I had to perform a kind of âstartup procedure.â
When I connected only the ESP board to the computer via USB (without any AC wires), it powered up and connected to the router.
Only then could I connect the green and white wires from the air conditioner to pins 15 and 13. In that case, everything worked fine, and two-way communication was possible.
The problem appeared when I turned off the main power (circuit breakers), and the AC lost power. After turning it back on, the board wouldnât start in that configuration â it couldnât connect to the home network. I didnât understand why.
When I disconnected the wires from pins 13/15 and restarted it, it connected to Wi-Fi without any issue.
Thatâs when I came across this article:
Restrictions for the use of some pins
Some pins have special functions, so there are certain restrictions for them:
- D0 (GPIO 16): Needed to wake up from DeepSleep. It also outputs a short HIGH signal on boot.
- D3 (GPIO 0): If pulled LOW during boot, the ESP8266 enters firmware programming mode.
- D4 (GPIO 2): Must not be pulled LOW during boot.
- D8 (GPIO 15): Must not be pulled HIGH during boot.
And that turned out to be the reason why the board wouldnât start after power cycling when everything was connected.
So I reassigned the UART pins to D1 (GPIO5) and D2 (GPIO4):
# UART for Haier AC communication
uart:
- id: ac_port
tx_pin: 4
rx_pin: 5
baud_rate: 9600
âŚand it started working 100% perfectly.
Morning,
Since last week I get this error with updating Esp8266 for my 4 Haier ACâs with smartair2 protocol.
Can anyone sent me in the right direction?
Iâm a little confused and donât know where to look forâŚ
INFO ESPHome 2025.11.0
INFO Reading configuration /config/esphome/airco-ashley.yamlâŚ
INFO Updating https://github.com/robertklep/esphome-custom-component@None
INFO Updating https://github.com/esphome/esphome.git@pull/11388/head
ERROR Unexpected exception while reading configuration:
Traceback (most recent call last):
File â/usr/local/bin/esphomeâ, line 10, in
sys.exit(main())
^^^^^^
File â/esphome/esphome/main.pyâ, line 1490, in main
return run_esphome(sys.argv)
^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/main.pyâ, line 1465, in run_esphome
config = read_config(
^^^^^^^^^^^^
File â/esphome/esphome/config.pyâ, line 1302, in read_config
res = load_config(command_line_substitutions, skip_external_update)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/config.pyâ, line 1159, in load_config
return _load_config(command_line_substitutions, skip_external_update)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/config.pyâ, line 1147, in _load_config
return validate_config(config, command_line_substitutions, skip_external_update)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/config.pyâ, line 1038, in validate_config
target_platform = core_config.preload_core_config(config, result)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/core/config.pyâ, line 347, in preload_core_config
if _is_target_platform(domain):
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/core/config.pyâ, line 297, in _is_target_platform
return get_component(name, True).is_target_platform
^^^^^^^^^^^^^^^^^^^^^^^^^
File â/esphome/esphome/loader.pyâ, line 223, in get_component
return _lookup_module(domain, exception)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 ââ, line 1387, in _gcd_import
File ââ, line 1360, in _find_and_load
File ââ, line 1331, in _find_and_load_unlocked
File ââ, line 935, in _load_unlocked
File ââ, line 999, in exec_module
File ââ, line 488, in _call_with_frames_removed
File â/data/external_components/a879a32c/esphome/components/climate/init.pyâ, line 275, in
CLIMATE_SCHEMA.add_extra(cv.deprecated_schema_constant(âclimateâ))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module âesphome.config_validationâ has no attribute âdeprecated_schema_constantâ
If you donât want to mess with the ac board, you can use my guide to extract DeviceId & LocalKey
#https://github.com/paveldn/haier-esphome/
substitutions:
device_name: Airco Joost Izaura
device_id: joost_izaura_climate
uart_id: ac_joost_izaura
send_wifi: "true"
esphome:
name: airco-joost-izaura
#ota:
# - platform: esphome
esp8266:
board: d1_mini
wifi:
ssid: "***************"
password: "***********"
fast_connect: true
uart:
baud_rate: 9600
tx_pin: 1
rx_pin: 3
id: ${uart_id}
logger:
level: DEBUG
hardware_uart: uart1
# baud_rate: 0
web_server:
packages:
local_haier: !include configs/external_components/local_haier.yaml
haier_base: !include .haier-smartair2-base.yaml
button:
- platform: safe_mode
name: "Airco Joost Izaura Restart (Safe Mode)"
Hello everybody. This was a working yaml but is not updatable anymore.
I changed it to the following
substitutions:
device_name: Airco Joost Izaura
device_id: joost_izaura_climate
uart_id: ac_joost_izaura
send_wifi: "true"
esphome:
name: airco-joost-izaura
friendly_name: ${device_name}
esp8266:
board: d1_mini
wifi:
ssid: "***********"
password: "*************"
fast_connect: true
min_auth_mode: WPA2
api:
ota:
- platform: esphome
web_server:
uart:
id: ${uart_id}
baud_rate: 9600
tx_pin: 1 # GPIO1 (TX)
rx_pin: 3 # GPIO3 (RX)
debug:
direction: BOTH
dummy_receiver: true
logger:
level: DEBUG
hardware_uart: uart1
climate:
- platform: haier
id: ${device_id}
name: ${device_name}
protocol: smartair2
uart_id: ${uart_id}
wifi_signal: true
display: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step: 1 °C
supported_modes:
- "OFF"
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- "OFF"
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- COMFORT
button:
- platform: safe_mode
name: "Airco Joost Izaura Restart (Safe Mode)"
The yaml is valid and I uploaded it to the ESP.
The unit is not responding on any command.
Who can help me?
Thanks!
substitutions:
device_name: Airco Joost Izaura
device_id: joost_izaura_climate
uart_id: ac_joost_izaura
send_wifi: "true"
esphome:
name: airco-joost-izaura
friendly_name: ${device_name}
esp8266:
board: d1_mini
wifi:
ssid: "*************"
password: "**********"
fast_connect: true
min_auth_mode: WPA2
uart:
id: ${uart_id}
baud_rate: 9600
tx_pin: 1
rx_pin: 3
logger:
level: DEBUG
hardware_uart: uart1
baud_rate: 0 # belangrijk bij ESP8266 + UART op GPIO1/3
api:
ota:
- platform: esphome
web_server:
climate:
- platform: haier
id: ${device_id}
name: ${device_name}
wifi_signal: ${send_wifi}
display: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step: 1 °C
supported_modes:
- "OFF"
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- "OFF"
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
button:
- platform: safe_mode
name: "Airco Joost Izaura Restart (Safe Mode)"
This is working!





