ESP Haier: Haier Air Conditioner + ESP Home + Wemos D1 mini

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.

1 Like

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.


4 Likes

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… :frowning_face:

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]’ ]

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!