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

Yep, being using all my SmartAir2 and h0n AC’s via mqtt control from external smart home hub.

Here is my SmartAir2 yaml with mqtt, you can adopt it for your device:

substitutions:
  device_name: "haier-guestroom" # change this
  device_friendly: "Haier Guestroom" # change this
  device_id: ac_guestroom # change this
  uart_id: haier_uart # change this
  topic_prefix: haier/smartair 
  send_wifi: "false"

  ipstatic: !YOUR_IP! # change this

esphome:
  name: ${device_name}
  friendly_name: ${device_friendly}

esp8266:
    board: d1_mini

logger:
  level: WARN
  baud_rate: 0 #Important. You can't use serial port
  hardware_uart: UART0

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  #important, otherwise the IP could change and then the entity is unavailable from home assistant.
  manual_ip:
    static_ip: ${ipstatic}
    gateway: !YOUR_GATEWAY!
    subnet: 255.255.255.0

# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${device_friendly}
    password: !secret ap_wifi_pass
captive_portal:

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_key

ota:

web_server:

mqtt:
# Haier
  broker: !secret ha_mqtt_ip
  username: !secret ha_mqtt_user
  password: !secret ha_mqtt_pass
  discovery: false
  client_id: ${device_id} # What you want to call your device in your MQTT broker
  topic_prefix: ${topic_prefix}/${device_id}
  
uart:
  baud_rate: 9600
  tx_pin: 1
  rx_pin: 3
  id: ${uart_id}

globals:
  - id: last_on_mode
    type: uint8_t
    restore_value: yes
    initial_value: CLIMATE_MODE_AUTO

climate:
  - platform: haier
    id: ${device_id}
    name: ${device_name}
    protocol: smartAir2
    wifi_signal: ${send_wifi}
    uart_id: ${uart_id}
    supported_modes:            # Optional, can be used to disable some modes if you don't need them
      - 'OFF'
      - HEAT_COOL
      - COOL
      - HEAT
      - DRY
      - FAN_ONLY
    supported_swing_modes: []
    supported_presets: []
    visual:                     # Optional, you can use it to limit min and max temperatures in UI (not working for remote!)
      min_temperature: 16 °C
      max_temperature: 30 °C
      temperature_step: 0.5 °C
    current_temperature_state_topic: ${topic_prefix}/${device_id}/cur_temp
    mode_state_topic: ${topic_prefix}/${device_id}/mode/state
    mode_command_topic: ${topic_prefix}/${device_id}/mode/set
    fan_mode_state_topic: ${topic_prefix}/${device_id}/fan/state
    fan_mode_command_topic: ${topic_prefix}/${device_id}/fan/set
    target_temperature_state_topic: ${topic_prefix}/${device_id}/temp/state
    target_temperature_command_topic: ${topic_prefix}/${device_id}/temp/set
#    on_state:
#      then:
#        lambda: |-
#          uint8_t cmode =  id(${device_id}).mode;
#          if (cmode != CLIMATE_MODE_OFF)
#            id(last_on_mode) = (uint8_t)cmode;    

button:
  # Common
  - platform: restart
    name: "ESP Restart"
  - platform: safe_mode
    name: "ESP Restart (Safe Mode)"

sensor:
  # Common
  - platform: wifi_signal
    name: "ESP WiFi RSSI"
    id: wifi_signal_rssi
    update_interval: 60s
    entity_category: "diagnostic"     

text_sensor:
  # Common
  - platform: wifi_info
    ip_address:
      name: "ESP WiFi IP"
      icon: mdi:ip-network
    ssid:
      name: "ESP WiFi SSID"
      icon: mdi:wifi
    mac_address:
      name: "ESP WiFi Mac"
      icon: mdi:ip-network

binary_sensor:
  - platform: template
    name: "Fan Active"
    lambda: |-
      if (id(${device_id}).fan_mode != 2 ) {
        return true;
      } else {
        return false;
      }
    device_class: power
    state_topic: ${topic_prefix}/${device_id}/fan/active

#switch:
#  - platform: template
#    id: ${device_id}_climate_power
#    name: ${device_id} power on/off
#    icon: mdi:power
#    lambda: |-
#      return id(${device_id}).mode != CLIMATE_MODE_OFF;
#    turn_on_action:
#      then:
#        lambda: |-          
#          auto call = id(${device_id}).make_call();
#          call.set_mode((ClimateMode)id(last_on_mode));
#          call.perform();
#    turn_off_action:
#      then:
#        lambda: |-          
#          auto call = id(${device_id}).make_call();
#          call.set_mode(CLIMATE_MODE_OFF);
#          call.perform();
#    state_topic: ${topic_prefix}/${device_id}/power/state
#    command_topic: ${topic_prefix}/${device_id}/power/set

If you are using h0n integration it’s a bit wider, you can tell me and i’ll share it’s example of mine

thank you for your reply.
edit: I have only h0n devices with esphome and if this differs from the sample above, your example would be very nice. thanks

No problem, here is my h0n yaml with mqtt.
It also includes “display, beeper, cleaning” options of Haier AC as well. And “FanActive” entity needed for correct Homekit intagration.
Substitutions are bit mixed in my example because i’m running one esp32s2 for two uart devices at once.

substitutions:
  
  esp_name: haier-presence-childroom # change this
  esp_friendly: "Haier Presence Childroom" # change this

  haier_name: "AC Childroom" # change this
  haier_id: ac_childroom # change this
  haier_uart: haier_uart
  haier_topic_prefix: "haier/hon"

  ipstatic: !!!YOUR_STATIC_IP_ADRESS!!! # change this

esphome:
  name: ${esp_name}
  friendly_name: ${esp_friendly}

esp32:
  board: lolin_s2_mini
  variant: esp32s2

logger:
  level: WARN
  baud_rate: 0 #Important. You can't use serial port
#  hardware_uart: UART0

debug:
  update_interval: 30s

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 10min

  #important, otherwise the IP could change and then the entity is unavailable from home assistant.
  manual_ip:
    static_ip: ${ipstatic}
    gateway: !!!YOUR_GATEWAY!!!
    subnet: 255.255.255.0

# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${esp_friendly}
    password: !secret ap_wifi_pass
captive_portal:

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_key
    
ota:

# Web config
web_server:
  include_internal: true
  ota: false

mqtt:
# Haier
  broker: !secret ha_mqtt_ip
  username: !secret ha_mqtt_user
  password: !secret ha_mqtt_pass
  discovery: false
  client_id: ${esp_name} # What you want to call your device in your MQTT broker
  topic_prefix: ${haier_topic_prefix}/${haier_id}

uart:
  # Haier
  - id: ${haier_uart}
    baud_rate: 9600
    tx_pin: GPIO39
    rx_pin: GPIO40

text_sensor:
  # Haier
  - platform: template
    name: "AC cleaning status"
    icon: mdi:spray-bottle
    lambda: return id(${haier_id}).get_cleaning_status_text();
    state_topic: ${haier_topic_prefix}/${haier_id}/self_clean/state    

binary_sensor:
  # Haier
  - platform: template
    name: "AC Fan Active"
    icon: mdi:fan-alert
    lambda: |-
      if (id(${haier_id}).fan_mode != 2 ) {
        return true;
      } else {
        return false;
      }
    device_class: power
    state_topic: ${haier_topic_prefix}/${haier_id}/fan/active    

switch:
  # Haier
  - platform: template
    id: ${haier_id}_display_switch
    name: "AC display"
    restore_mode: RESTORE_DEFAULT_ON
    icon: mdi:led-on
    entity_category: config
    lambda: |-
      return id(${haier_id}).get_display_state();
    turn_on_action:
      climate.haier.display_on: ${haier_id}
    turn_off_action:
      climate.haier.display_off: ${haier_id}
    state_topic: ${haier_topic_prefix}/${haier_id}/display/state
    command_topic: ${haier_topic_prefix}/${haier_id}/display/set  
  - platform: template
    id: ${haier_id}_beeper_switch
    entity_category: config
    name: "AC beeper"
    restore_mode: RESTORE_DEFAULT_OFF
    icon: mdi:volume-high
    lambda: |-
      return id(${haier_id}).get_beeper_state();
    turn_on_action:
      climate.haier.beeper_on: ${haier_id}
    turn_off_action:
      climate.haier.beeper_off: ${haier_id}
    state_topic: ${haier_topic_prefix}/${haier_id}/beeper/state
    command_topic: ${haier_topic_prefix}/${haier_id}/beeper/set 
  - platform: template
    id: ${haier_id}_health_mode
    name: "AC health mode"
    restore_mode: RESTORE_DEFAULT_OFF
    icon: mdi:leaf
    lambda: |-
      return id(${haier_id}).get_health_mode();
    turn_on_action:
      climate.haier.health_on: ${haier_id}
    turn_off_action:
      climate.haier.health_off: ${haier_id}
    state_topic: ${haier_topic_prefix}/${haier_id}/health_mode/state
    command_topic: ${haier_topic_prefix}/${haier_id}/health_mode/set

#  - platform: template
#    id: ${device_id}_climate_power
#    name: ${device_id} power on/off
#    icon: mdi:power
#   lambda: |-
#      return id(${device_id}).mode != CLIMATE_MODE_OFF;
#    turn_on_action:
#      climate.haier.power_on: ${device_id}
#    turn_off_action:
#      climate.haier.power_off: ${device_id}
#    state_topic: ${topic_prefix}/${device_name}/power/state
#    command_topic: ${topic_prefix}/${device_name}/power/set

button:
  # Haier
  - platform: template
    name: "AC start 56°C steri-cleaning"
    icon: mdi:spray-bottle
    on_press:
    - climate.haier.start_steri_cleaning: ${haier_id}
    command_topic: ${haier_topic_prefix}/${haier_id}/self_clean/set
  - platform: template
    name: "AC start self cleaning"
    icon: mdi:spray-bottle
    on_press:
    - climate.haier.start_self_cleaning: ${haier_id}
    command_topic: ${haier_topic_prefix}/${haier_id}/self_clean/set  

##### Haier Climate hOn CONFIG

climate:
  # Haier
  - platform: haier
    id: ${haier_id}
    name: ${haier_name}
    uart_id: ${haier_uart}
    protocol: hOn
    wifi_signal: true
    beeper: false
    supported_modes:            # Optional, can be used to disable some modes if you don't need them
      - 'OFF'
      - HEAT_COOL
      - COOL
      - HEAT
      - DRY
      - FAN_ONLY
    supported_swing_modes:      # Optional, can be used to disable some swing modes if your AC does not support it
      - 'OFF'
      - VERTICAL
      - HORIZONTAL
      - BOTH
    visual:                     # Optional, you can use it to limit min and max temperatures in UI (not working for remote!)
      min_temperature: 16 °C
      max_temperature: 30 °C
      temperature_step: 1 °C

    # MQTT topics
    current_temperature_state_topic: ${haier_topic_prefix}/${haier_id}/cur_temp
    mode_state_topic: ${haier_topic_prefix}/${haier_id}/mode/state
    mode_command_topic: ${haier_topic_prefix}/${haier_id}/mode/set
    fan_mode_state_topic: ${haier_topic_prefix}/${haier_id}/fan/state
    fan_mode_command_topic: ${haier_topic_prefix}/${haier_id}/fan/set
    target_temperature_state_topic: ${haier_topic_prefix}/${haier_id}/temp/state
    target_temperature_command_topic: ${haier_topic_prefix}/${haier_id}/temp/set
    swing_mode_state_topic: ${haier_topic_prefix}/${haier_id}/swing/state
    swing_mode_command_topic: ${haier_topic_prefix}/${haier_id}/swing/set
    preset_state_topic: ${haier_topic_prefix}/${haier_id}/preset/state
    preset_command_topic: ${haier_topic_prefix}/${haier_id}/preset/set

I see this “gap” but I don’t see any cable sticking out…
By the way, should I buy a Wemos D1 or an ESP32 board (I’m looking for it on AliExpress)?

Thank you OwlBawl, works great.

1 Like

Wemos d1 mini esp8266 is just enough for haier.
Had 4 of them working 100% reliably for about 2 years

@mot
First of all, keep in mind that opening AC will require you to have at least basic knowledge about electronics and promotions. Also, all you doing is at your own risk.
If you keep reading after warning :smile: and are willing to take risks you will need to disconnect power from your AC internal block. Open a panel from the photo I showed you (it should be just 1 screw) and very carefully pull the board behind it. You should find the connector which has +5v GND TXD and RXD pins. Usually, it is marked as CN34. It should be like this:


It is possible in your case that it is not available, in this case, you probably can’t control your AC. If you find it and it looks like mine (and that is what I expect) you can use a 4-pin connector like this: https://www.aliexpress.com/item/1005003374938897.html
to make a wire to connect your ESP
And like @OwlBawl said Wemos D1 mini is enough if you using it just for AC.

1 Like

If it helps i can add that the full name of 4 pin connector used on board is
Molex mini-SPOX (4 pin) code MX-5264-04 + 4 pins for welding code MX-5263-PBTL.
But if you can find and buy it with wires already like @paveldn proposed with Ali link it can be much easier (5264 terminal 4 pin with cables 150mm+ on Aliexpress)

1 Like


I opened the flap and see the built-in ESP32. Will Wemos be needed?

on @paveldn github there is manual for stock esp32 firmware change if you are sure in your abilities and don’t afraid of bricking it.
Another way is to change it with wemos like board and leave this one as is for some cases.

@Hombard I agree with @OwlBawl Better keep your original module and use Wemos. I done a lot of experiments with my original Haier module and never had any problems. But some of new AC models have flash encrypted. If you try to use this module there is good chance you will brick it. So it you will decide to try first make a full flash backup. But if you will use Wemos you always can revert everything back.

1 Like

Thanks, what about disconnecting cables?
Can I reconnect them to Haier esp32 later?

You want to cut off the pin connector on the dongle side? Or you want to find the another cable that will fit this connector ? Can’t understand the request.

I want to cut the cables to connect the Wemos D1, at the same time, I would like to leave the possibility of connecting the original ESP32 in the future. Would I then have to extend the cables somehow?

that’s really strange question. If you cut it and then restore it (welding or smth) would this cable lose it’s cableness? the only thing is to correctly restore it.

@paveldn - thanks for this integration. I’ve installed but can’t interface with the AC. It was using the white wifi dongle with smart2air.

The esp frames say frame sent type 61 and frame found type 62;

|16:05:55|[D]|[haier.protocol:019]|Sending frame: type 61, data: 00 07|
| --- | --- | --- | --- |
|16:05:57|[D]|[haier.protocol:019]|Sending frame: type 61, data: 00 07|
|16:05:57|[D]|[haier.protocol:019]|Frame found: type 62, data: 45 2B 2B 32 2E 31 38 00 31 37 30 36 32 36 30 30 F1 00 00 31 37 30 35 32 36 30 30 01 55 2D 41 43 00 00 00 00 00 04|
|16:05:57|[D]|[haier.protocol:019]|Sending frame: type 01, data: 4D 01|
|16:05:59|[D]|[haier.protocol:019]|Sending frame: type 01, data: 4D 01|
|16:06:02|[D]|[haier.protocol:019]|Sending frame: type 01, data: 4D 01|
|16:06:02|[I]|[haier.climate:095]|Answer timeout for command 01, phase SENDING_FIRST_STATUS_REQUEST|

My config looks like this:

substitutions:
  device_name: Haier AC
  device_id: haier_climate
  uart_id: ac_port
  send_wifi: "true"

api:
  encryption:
    key: "HIDDEN"
    
esphome:
  name: haier
  name_add_mac_suffix: true

esp8266:
  board: esp12e

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    # Set this to the IP of the ESP
    static_ip: HIDDEN
    # Set this to the IP address of the router. Often ends with .1
    gateway: HIDDEN
    # The subnet of the network. 255.255.255.0 works for most home networks.
    subnet: 255.255.255.0
  ap:
    ssid: "HIDDEN"
    password: "HIDDEN"

uart:
  - id: ${uart_id}  
    baud_rate: 9600
    tx_pin: 1
    rx_pin: 3

logger:
  level: DEBUG
  baud_rate: 0
      
web_server:

packages:
  remote_package:
    url: https://github.com/paveldn/haier-esphome
    ref: master
    files:
      - .haier-smartair2-base.yaml

external_components:
  - source: github://esphome/esphome@dev
    components: [ haier ]

@homeassist2,
From what I see from your logs your AC should speak hOn, try to use: .haier-hon-base.yaml instead of .haier-smartair2-base.yaml it should help.

Thank you! That worked straight away. I just assumed that I was on the smart2air platform as that’s the app I used.
Great work - really appreciate it :slight_smile:

1 Like

Hi all, i would ask if someone try to use ESP32 usb dongle development board https://vi.aliexpress.com/item/1005006123996200.html to flash there esphome. I found it on Aliexpress. No soldering, just plug and play. What do you think?

Do you want to use it with Haier AC? Just flashing ESPHome should be no problem at all but I doubt it would be possible to use with Haier AC. The thing is that Haier just uses a USB connector for the UART connection. So dev boards that use USB will not work.