Nothing, I abandoned the project for now due lack of time.
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.
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:
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 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.
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)
EDIT: according to diagram the xy-017 RS485 module already have 120om resistor
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
( 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:
perhaps this is the difference, I will try asap.
That is also what I tried as first with exactly the same result, garbage 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.
glad to report full success 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
@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
Hello and thx alot for your reply, but the variable question was meant for @netsplit64, since his code uses a good amount.
I am pretty good with c and c++ but i havent seen so far how to combine yaml with it so i am unaware where he did define them.
I did play with substitutes for friendly_node_name and node_id which seemed to work, but the variable id alone in the on press clause is still a mystery for me.
Thx anyway.
So basically what my post described is using a Dallas temperature sensor on a different esp chip (Dallas Temperature Sensor — ESPHome) to connect to my heatpump controller and update a number template value for an automation. The connection happens over wifi. My temp sensor is plugged into a usb wall outlet by the bed. You could power one by battery to make it portable. If I were to do that, I’d find/male a suitable looking, suitably sized box, drill a hole just big enough to mount the temp probe, and use a small usb power bank.
The automation simply demonstrates setting the temperature mode based on the input number which the separate esp/dallas unit keeps updated.
as for substitutions this might help: Configuration Types — ESPHome
Substitutions are ultimately plain text that gets replaced with a specified value when the firmware is compiled.
and for lambdas (c code) : Automations and Templates — ESPHome
It can be a bit of a learning curve, but it’s worth it.
Hello, thx for answering…
I added the substitution for “friendly_node_name” and “node_id” already and got the point where he is complaining about the variable contents of " id(${node_id}_my_climate).target_temperature - id(${node_id}_room_temperature_c).state;".
Debugging it shows that he tries to build a string “Button1_my_climate” and “Button1__room_temperature_c” that he cannot find anywhere defined…
My code is down below…
So what i would like to know is what you are using as substituitions and globals so that i can change it to my xiaomi blue tooth temp sensor as the temp source…which is known in HASS as “sensor.ble_temperature_schlafzimmer_a4c13888d685”, so no second esphome code for that possible.
Hope you can help me out, cause my hard ware dongle does not work and this ukrainin gentleman does have other isues right now than sending me a pre made one…
By the way…“node_id” became value Button1 without reason, just to fill it since i did not know what it expects in there…
globals:
- id: auto_mode
type: bool
restore_value: false
initial_value: 'false'
substitutions:
friendly_node_name: BED ROOM AC
node_id: Button1
#test ac from here down
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°C, target: %f°C, room: %f°C",
(tempDifference * 1.8),
(id(${node_id}_my_climate).target_temperature),
(id(${node_id}_room_temperature_c).state)
);
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();