Midea branded AC’s with ESPhome (no cloud)

There’s a toggle to turn it off, but it looks like you need an IR blaster maybe? You could try putting it in your yaml and see if it works. Unfortunately it’s a toggle, so doesn’t an explicit off if it does work. I personally couldn’t get it to work on mine.

# Example configuration entry

remote_transmitter:
  pin: GPIO13                       # For iot-uni-stick.
  carrier_duty_percent: 100%        # 50% for IR LED, 100% for direct connect to TSOP IR receiver output.

sensor:
  - platform: homeassistant
    entity_id: sensor.room_sensor   # Sensor from HASS
    internal: true
    filters:
      - throttle: 10s
      - heartbeat: 2min             # Maximum interval between updates.
      - debounce: 1s
    on_value:
      midea_ac.follow_me:
        temperature: !lambda "return x;"
        beeper: false               # Optional. Beep on update.

# template buttons for sending display control command and swing step actions
button:
  - platform: template
    name: Display Toggle
    icon: mdi:theme-light-dark
    on_press:
      midea_ac.display_toggle:
  - platform: template
    name: Swing Step
    icon: mdi:tailwind
    on_press:
      midea_ac.swing_step:

Esphome makes a guess about the device’s network, and sometimes it guesses wrong. You can fix this by using:

use_address (Optional, string): Manually override what address to use to connect to the ESP. Defaults to auto-generated value. Example, if you have changed your static IP and want to flash OTA to the previously configured IP address.

Example:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: <your devices IP or DNS name here>
  ap:
    ssid: "${friendly_name} Fallback"
    password: !secret wifi_password
  power_save_mode: HIGH # for ESP8266 LOW/HIGH are mixed up, esphome/issues/issues/1532

More info:

ah, ill give it a try, i suppose technically Icould get the bond bridge and integrate that into HA to get the those parameters in maybe? A bit silly for just one or two buttons at the Bond’s price point.

Nothing, I abandoned the project for now due lack of time.

any ideas why my esp01 is dropping from the network nearly ever minute or so and then back on?

That would be the part with follow me.
According to the documentation, u either have to set up a led sender in front of the unit or u wire a lead from your gpioxyz to the the signal leg of the tsop inside.
I am at that spot right now but as soon i connect the lead to the signal leg, remote is frozen/unresponsive to my esp commands and the original remote…
So i am prob missing something but…
If you figure it out, let me know

I just realized what exactly the follow me is supposed to do, and realized I have something similar. Basically if I understand it right there’s a temp sensor in the remote, and it replaces the temp sensor in the heat pump.

Instead of the remote though, I’m using an ESP8266 with a Dallas temp sensor. The basic idea is when the dallas sensor gets a new value, connect to the heatpump esp chip and set a template number to have that value. Then in an automation treat the template number as a thermometer and handle it like you like.

Here’s an example:

In the heatpump ESP chip yaml add this:

globals:
   - id: auto_mode
     type: bool
     restore_value: false
     initial_value: 'false'


switch:
  - platform: template
    name: ${friendly_node_name} Auto Mode
    id: ${node_id}_auto_mode
    icon: mdi:car-turbocharger
    optimistic: true
    lambda: return id(auto_mode);  
    turn_on_action:
        - lambda: |-
            id(auto_mode) = true;
            id(${node_id}_automation_lambda).press();
    turn_off_action:
        - lambda: |-
            id(auto_mode) = false;
button:
  - platform: template
    internal: true
    id: ${node_id}_automation_lambda
    on_press:
        - lambda: |-
                  if (id(auto_mode)) {
                       float tempDifference = id(${node_id}_my_climate).target_temperature - id(${node_id}_room_temperature_c).state;
                      ESP_LOGW(
                              "climate_temp", "difference: %f°F,  target: %f°F, room: %f°F", 
                              (tempDifference * 1.8), 
                              (id(${node_id}_my_climate).target_temperature * 1.8 + 32),
                              (id(${node_id}_room_temperature_c).state * 1.8 + 32)
                      );
                       if(tempDifference > $heat_on_below_set_temp) {
                          ESP_LOGW("climate_mode", "Mode: [%s]","heat");
                           if (ClimateMode::CLIMATE_MODE_HEAT != id(${node_id}_my_climate).mode) {
                              ESP_LOGW("climate_mode", "Mode: [%s]","setting mode heat");
                              id(${node_id}_my_climate).make_call().set_mode(ClimateMode::CLIMATE_MODE_HEAT).perform();
                           }
                           delay(2000);
                           if(tempDifference > $heat_turbo_on_below_set_temp) {
                              ESP_LOGW("climate_preset",    "Preset: [%s]", "boost");
                               if (ClimatePreset::CLIMATE_PRESET_BOOST !=  id(${node_id}_my_climate).preset.value()) {
                                  ESP_LOGW("climate_preset",    "Preset: [%s]", " setting boost heat");
                                  id(${node_id}_my_climate).make_call().set_preset(ClimatePreset::CLIMATE_PRESET_BOOST).perform();
                               } else if (tempDifference < -$heat_turbo_off_above_set_temp) {
                              ESP_LOGW("climate_preset",    "Preset: [%s]", "none");
                               if (ClimatePreset::CLIMATE_PRESET_NONE !=   id(${node_id}_my_climate).preset.value()) {
                                  ESP_LOGW("climate_preset",    "Preset: [%s]", " setting none heat");
                                  id(${node_id}_my_climate).make_call().set_preset(ClimatePreset::CLIMATE_PRESET_NONE).perform();
                               }
                              }
                           }
                      } else if(tempDifference < -$cool_on_above_set_temp) {
                          ESP_LOGW("climate_mode", "Mode: [%s]", "cool");
                           if (ClimateMode::CLIMATE_MODE_COOL != id(${node_id}_my_climate).mode) {
                              ESP_LOGW("climate_mode", "Mode: [%s]", "setting mode cool");
                              id(${node_id}_my_climate).make_call().set_mode(ClimateMode::CLIMATE_MODE_COOL).perform();
                           }
                           delay(2000);
                           if (tempDifference < -$cool_turbo_on_above_set_temp) {
                              ESP_LOGW("climate_preset",    "Preset: [%s]", "boost");
                               if (ClimatePreset::CLIMATE_PRESET_BOOST !=  id(${node_id}_my_climate).preset.value()) {
                                  ESP_LOGW("climate_preset",    "Preset: [%s]", " setting boost cool");
                                  id(${node_id}_my_climate).make_call().set_preset(ClimatePreset::CLIMATE_PRESET_BOOST).perform();
                               } else if  (tempDifference > $cool_turbo_off_below_set_temp) {
                              ESP_LOGW("climate_preset",    "Preset: [%s]", "none");
                               if (ClimatePreset::CLIMATE_PRESET_NONE !=   id(${node_id}_my_climate).preset.value()) {
                                  ESP_LOGW("climate_preset",    "Preset: [%s]", " setting none cool");
                                  id(${node_id}_my_climate).make_call().set_preset(ClimatePreset::CLIMATE_PRESET_NONE).perform();
                               }
                              }
                           }
                       }
                  }
number:
  - platform: template
    name: ${friendly_node_name} Room Temperature °C
    id: ${node_id}_room_temperature_c
    optimistic: true
    min_value: -40
    max_value: 100
    restore_value: true
    step: 0.1
    on_value:
      then:
        - lambda: |-
            id(${node_id}_automation_lambda).press();

in the Dallas Esp chip yaml have it include this:


http_request:
  id: http_request_data
  useragent: esphome/device
  timeout: 10s
  esp8266_disable_ssl_support: true

dallas:
  - pin: ${dallas_pin}
    id: ${device_name}_pin
    update_interval: ${dallas_update}

sensor:
  - platform: dallas
    address: ${dallas_address}
    name: ${friendly_name}
    id: ${device_name}
    dallas_id: ${device_name}_pin
    on_value:
      then:
      - http_request.post: !lambda |- 
              return "http://some-heatpump.lan/number/some_heatpump_room_tempreture_c/set?value=" + std::to_string(x);

Net result is a pure wifi and ESP replacement for follow me.

1 Like

Hi!

Did you find a solution? Did you setup the USB connector and integrate it into HA?

Maybe someone has experience with this type of fan-coil unit?

Thanks in advance
Balazs

Hello Balázs!

I haven’t got enough time for this topic. My workaround will be (at least for now) is an ESP8285 based IR module. As far as I know there is Midea compatible IR module in ESPHome.
But the last weeks I’ve checked this topic and searched in Google and found this. My fan-coil have XYE port and it looks like it is usable. Sadly I’m far from expert, so I need much more time to find something that will be able to use this RS485 port.

I hope this will help!
My units XYE port:

Anyone following this with a heat pump might be interested in the good work going on on this other forum:

1 Like

interesting!
I have also found ready HA integration based on similar idea:

Surprisingly, worked for me out of the box
unfortunately same limited data as on mobile app

Hi all,

I got quite some progress on our Airwell (Midea clone) heat pump with modbus. I am able to read all the modbus registers and also am able to write (I changed the value of the temperature of the DHW tank).

My current setup is as follow: I have a raspberry pi with a USB/RS485 adapter that is attached to the internal unit of the heat pump. It took me some time to understand that I had to use the H1/H2 connection on the back of the display :slight_smile: On the rpi I have a small python script that I wrote that reads all the registers and uploads that info into MQTT, where Home Assistant reads it from.

Btw, I had to place a 120 ohm resistor between H1 and H2 before I was able to read info.

The next steps I want to take is to create a ESPHome solution for it. Thus a more complete solution for others to use with a decent manual that describes how to attach it to the heat pump.

And since pictures are always more worth then words, two screenshots of my current heat pump dashboard


Most is in Dutch, so some translations:

  • warmtepomp = heat pump
  • binnen = internal
  • buiten = external
  • buffervat = water tank

On the screenshot you also see the energy usage stats and some thermostats. That info is coming from two Shelly devices (both the internal and external unit are attached to a Shelly to measure the energy usage) and my Tado thermostats.

Fun fact, with the combination of the energy info from the Shelly devices and the state of the heat pump, I am now also able to split the energy consumption based on the status. In other words, I can see how many energy is used for heating, cooling and dhw.

4 Likes

wow!
I was trying all weekend to connect my heat pump, even started receving some garbage and plenty of CRC errors but no real data… very likely termination resistor was missing (using rpi, xy-017 and mbpoll application)
image
EDIT: according to diagram the xy-017 RS485 module already have 120om resistor
image

I have verified first with simple power meter modbus enabled to make sure hardware is set up correctly SDM120M

Can you share some more details?
I know it’s relevant, how did you connect H1H2 to AB? did you connect GND?
can you tell communication settings? baud, parity, bits

I hope these Midea clones works the same way…

Hi,

I used the following connections:

  • B- == H1
  • A+ == H2
  • Ground == E

I started with the following code to test the connectivity, my current code is of course more complicated. Here you can also see the parameters I use for the connection.

#!/usr/bin/env python3

import minimalmodbus
import serial

instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1)  # port name, slave address (in decimal)
instrument.serial.baudrate = 9600
instrument.serial.bytesize = 8
instrument.serial.parity   = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout  = 1.00          # seconds

instrument.mode = minimalmodbus.MODE_RTU  
instrument.clear_buffers_before_each_transaction = True

## Read Water Tank Temperature
value = instrument.read_register(115, 0)  # Registernumber, number of decimals
print("Value: {}".format(value))

instrument.serial.close()

And these pictures should make it completely clear :slight_smile:

( small typo on the picture above, B1 should be B- )

great, thank you Mosibi.

pretty basic settings, I’m 100% sure was trying these.

But you say you have connected to display while I was trying directly to mainboard:
image
perhaps this is the difference, I will try asap.

That is also what I tried as first with exactly the same result, garbage :grinning_face_with_smiling_eyes: Those, as I learned later, are the modbus connectors to link to other heat pump units. So you should really have the H1 and H2 on the display, which on our unit is in the front panel of the internal unit

Btw, be gentle with the screws that are used for the display bracket, on our unit they are not of the highest quality.

1 Like

glad to report full success :slight_smile: even with esphome:

thanks again @Mosibi!

temporarirly used Raspberry Pico W, but probably ESP8266 would work fine

need to work on few values calculation, some are coded in two registers (low/high byte)

next step: put esp8266 and RS485 into display box
found already 3.3V on the board (CN6 or IC8), enough to power ESP8266

relevant esphome code, if somebody interested:

substitutions:
 heat_pump_name: rotenso

uart:
  rx_pin: GPIO5
  tx_pin: GPIO4
  baud_rate: 9600
  #these are defaults, just show for clarity
  stop_bits: 1
  parity: NONE
  data_bits: 8

modbus:
  id: modbus_heatpump

modbus_controller:
  - id: modbus_1
    ## the Modbus device addr
    address: 0x1
    modbus_id: modbus_heatpump
    setup_priority: -10
    update_interval: 15s

sensor:  
#by registry number, like : _100
  - platform: modbus_controller
    id: ${heat_pump_name}_100
    name: "hp_compressor_frequency"
    state_class: measurement
    register_type: holding
    address: 0x64 #dec 100
    unit_of_measurement: "Hz"
    value_type: S_WORD

  - platform: modbus_controller
    id: ${heat_pump_name}_102
    name: "hp_fan_speed_pwm"
    state_class: measurement
    register_type: holding
    address: 0x66
    unit_of_measurement: "pwm"
    value_type: S_WORD

  - platform: modbus_controller
    id: ${heat_pump_name}_104
    name: "hp_TW_in_Entering_Water_Temperature"
    state_class: measurement
    register_type: holding
    address: 0x68
    unit_of_measurement: "°C"
    value_type: S_WORD
1 Like

@netsplit64
Hello…

Where did you specify the variables?
Do you have variable definitioon table somewhere tyhat you missed to post?
Or is this extra held variable for the purpose of being a universal example?

hi, not sure which variables you have in mind
if modbus registers list then these are available in some other Midea clones manuals, like here:

I have just posted few examples but there are many more, like this one:
name: "hp_compressor_frequency"
state_class: measurement
register_type: holding
address: 0x64 #dec 100
unit_of_measurement: “Hz”
value_type: U_WORD