I wondered the same thing.
Seen on Aliexpress there is a very cheap clone of the Dr Smart Tool . Thought about buying one just to see how it worked. I figure whatever a Dr Smat Tool could display should be able to be displayed on an esp32/rs485 if you could just figure out the holding addresses of each entity. I’m not smart enough to figure it out,though.
To anyone using @mdrobnak’s code, have you seen behavior like this? Every night at the same time, the follow me temp of the air handler controller stops updating. It’s quite unusual
also to clarify, this graph shows the temp being reported by the esphome as the current indoor temp, and the sensor that is being fed into it for the follow me temperature itself. I suppose it’s possible that the heat pump isn’t calling for heat because the temp @ the coils * 0.3 + the indoor temp * 0.7 is still @ the set point (ie the house is heat soaked) and since the system doesn’t feel like it needs to heat, it isn’t reporting the follow me temp anymore.
After the temp gets down to 64.4F (which is the nearest whole celsius degree), the system recovers. Also the yaml I’m using is as follows:
substitutions:
name: air-handler-controller
friendly_name: Air Handler Controller
esphome:
name: ${name}
friendly_name: ${friendly_name}
esp32:
variant: esp32
framework:
type: arduino
# Enable Home Assistant API
api:
encryption:
key: SECRET
services:
- service: follow_me
variables:
temperature: float
then:
midea_ac.follow_me:
temperature: !lambda "return temperature;"
beeper: false
ota:
- platform: esphome
password: SECRET
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Air-Handler-Controller"
password: SECRET
captive_portal:
logger:
logs:
midea_xye: WARN
external_components:
- source: github://mdrobnak/esphome@delays_updated # haven't updated to latest yet
components: [midea_xye]
# UART settings for RS485 converter dongle (required)
uart:
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 4800
# debug: #If you want to help reverse engineer
# direction: BOTH
#dummy_receiver: true
#after:
# delimiter: [0x55]
# Main settings
climate:
- platform: midea_xye
name: Heatpump
period: 1s # Optional. Defaults to 1s
timeout: 200ms # Optional. Defaults to 100ms
beeper: false # Optional. Beep on commands.
#default_target_temperature_low: 18°C
#default_target_temperature_high: 24°C
#custom_auto: true
use_fahrenheit: true
visual: # Optional. Example of visual settings override.
min_temperature: 17 °C # min: 17
max_temperature: 30 °C # max: 30
temperature_step: 0.5 °C # min: 0.5
supported_modes: # Optional.
- FAN_ONLY
- HEAT_COOL
- COOL
- HEAT
# - DRY
# supported_presets: # Optional
# - BOOST
outdoor_temperature:
name: Outside Temp
temperature_2a:
name: Inside Coil Inlet Temp
temperature_2b:
name: Inside Coil Outlet Temp
temperature_3:
name: Outside Coil Temperature
error_flags:
name: Error Flags
protect_flags:
name: Protect Flags
# static_pressure: # I don't wanna mess with this
# name: Static Pressure
# min_value: 0
# timer_start: # since ours is a central heat pump, I never do this
# name: Timer Start
# timer_stop:
# name: Timer Stop
sensor:
- platform: homeassistant
entity_id: sensor.living_room_temperature
id: living_room_thermostat_follow_me
name: "Living Room Temperature Sensor"
filters:
- throttle: 10s # the aranet only reports every minute at best so realistically, we never need to throttle but whatever
- heartbeat: 1min
- debounce: 1s # this probably isn't necessary but for safety I like not overwhelming the follow me functionality
- lambda: return (x - 32.0) * (5.0/9.0); # aranet is in F so we convert to C
on_value:
midea_ac.follow_me:
temperature: !lambda "return x;"
- platform: wifi_signal
name: ${friendly_name} Wi-Fi Signal
update_interval: 5min
Hey all, I am trying to diagnose an issue with my Midea EvoX heatpump. If anyone who has the XYE instrumentation done on their unit could share data of the T1/T2/T3 and T4 temps while heating to compare to mine, I’d be very grateful. Ideally, it should be from another R454B refrigerant unit. Even better if you use grafana, and you share a few hours worth of snapshot.
I have a Midea EvoX Gen2 30k (2.5ton) heatpump. I’d love to compare my data with someone else’s similar Midea or rebrand. Thank you!
That’s a really interesting find. The Dr Smart Inverter Diagnostic Tool video changes how I’m thinking about some of this.
Up until now, I’ve been referring to the bus in my system as “S-Comms,” but based on what’s shown there, it’s possible what I’m seeing is actually PQE (non-S communication) over S1/S2. I hadn’t considered that distinction before.
For context, I’ve been working on a passive sniffer for the S1/S2 lines to monitor inverter behavior (separate from XYE control). The goal isn’t control — just visibility into real operating metrics. I have my current progress documented here if anyone is curious.
What really caught my attention in that video is the use of the “test port.” If that port is consistently populated across these units and operating at a 5V logic level (as suggested for non-S communication outdoor units), that could be a much cleaner and safer place to monitor traffic.
Compared to tapping directly into S1/S2 — where many installations have mains voltage present and significant noise/spikes — a 5V diagnostic interface would be a major improvement for safe, local sniffing.
I haven’t physically scoped the test port yet, so this is still theory. But combining:
Passive monitoring via a low-voltage diagnostic port
Yeah I had the same idea with the Testport. It also has power so could just put a ESP32 hanging from there for a continuous monitoring device that sees both indoor and outdoor data. One thing though to note: in the Dr Smart tool manual it says the testport pins are 5V, GND, SCL and SDA. I wonder if SCL and SDA actually mean I2C communications or they just mislabeled for the manual. I have the tool, I’d just need time to play with it…
Another odd behavior I’m observing (which is actually a pretty significant problem) is that randomly, the follow me temperature is being reported as the minimum allowable setpoint (62F) randomly. This causes the unit to suddenly call for very high heating and I can’t figure out what is causing it. Is anyone else experiencing this? I’ve tried a variety of filter tweaks on the follow me HA sensor but I actually think the issue is down the a communication failure between the AHU and the ESP32 as I stop seeing climate debug logs when this happens.
That said, if for some reason HA is down, and can’t get a value to HA, I’ll see the system go nuts. Otherwise it does report it pretty well…
One thing to note is that you can’t send a follow-me at a 5 minute interval…the system will not respect it. I think it is once a minute is the wired controller behavior.
I guess I need to put some more input validation here / hold onto the last value…
Heya @mdrobnak; yeah I assumed the frequency of heartbeating mattered so I kept it @ 1 minute. I tried other frequencies and other filter options but none seem to prevent this. I’ve since set up an automation that yells at me if the {{ states.climate.air_handler_controller.attributes.current_temperature | int }} is less than the actual device I’m using for follow me.
I definitely think the behavior you described of as if not HA_follow_me_value then previous_temp would be a really nice improvement. If you’re willing to give me a little guidance one where/how to implement that I’d be really keen to help.
Hey thanks so much for this project!! Amazing, I’ve been wanting to integrate my Vulcano duct units for years now and just stumbled on your amazing piece of work after figuring out the USB method wouldn’t work.
I’m using an M5Stack ATOM-Lite and Tail485 connected to the XYE port inside my machine and it’s working beautifully. I first had some issues with the follow me temperature until I realised the YAML earlier in the thread had a conversion to farenheit included in it!
This is my YAML for anyone who wants a ready made Celcius version, just replace with your own secret names and also the follow me entity_id with your own temperature sensor, or comment out that sensor entirely.
substitutions:
name: "dining-room-aircon"
friendly_name: "Dining Room Aircon"
comment: "ESPHome flashed M5Stack Atom with Tail485 attached to dining room aircon"
esphome:
name: ${name}
name_add_mac_suffix: false
friendly_name: ${friendly_name}
comment: ${comment}
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging (but not via UART)
logger:
#baud_rate: 0
#logs:
# component: ERROR
# Enable Home Assistant API
api:
encryption:
key: !secret aircon_encryption_key
services:
- service: follow_me
variables:
temperature: float
then:
midea_ac.follow_me:
temperature: !lambda "return temperature;"
beeper: false
ota:
- platform: esphome
password: !secret ota_password
# Enable wifi
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: 192.168.1.80
manual_ip:
# Set this to the IP of the ESP
static_ip: 192.168.1.80
# Set this to the IP address of the router. Often ends with .1
gateway: 192.168.1.1
# The subnet of the network. 255.255.255.0 works for most home networks.
subnet: 255.255.255.0
ap:
ssid: "Air-Handler-Controller"
password: !secret access_point_password
captive_portal:
# Optionally enables the ESP web server
web_server:
port: 80
auth:
username: !secret web_server_username
password: !secret web_server_password
external_components:
- source: github://mdrobnak/[email protected]
components: [midea_xye]
refresh: 0s
# UART settings for RS485 converter dongle (required)
uart:
tx_pin: GPIO26
rx_pin: GPIO32
baud_rate: 4800
debug: #If you want to help reverse engineer
direction: BOTH
#dummy_receiver: true
#after:
# delimiter: [0x55]
# Main settings
climate:
- platform: midea_xye
name: Heatpump
id: heatpump
period: 1s # Optional. Defaults to 1s
timeout: 200ms # Optional. Defaults to 100ms
beeper: true # Optional. Beep on commands.
#default_target_temperature_low: 18°C
#default_target_temperature_high: 24°C
#custom_auto: true
use_fahrenheit: false
defrost:
name: Defrost Active
visual: # Optional. Example of visual settings override.
min_temperature: 19 °C # min: 17
max_temperature: 23 °C # max: 30
temperature_step: 1 °C # min: 0.5
supported_modes: # Optional.
- FAN_ONLY
- HEAT_COOL
- COOL
- HEAT
- DRY
supported_presets: # Optional
- BOOST
outdoor_temperature: # Optional. Outdoor temperature sensor
name: Outside Temp
temperature_2a: # Optional. Inside coil temperature
name: Inside Coil Inlet Temp
temperature_3:
name: Outside Coil Temperature
timer_start: # Optional. On timer duration
name: Timer Start
timer_stop: # Optional. Off timer duration
name: Timer Stop
error_flags: # Optional.
name: Error Flags
fan_speed:
name: Fan Speed
protect_flags: # Optional.
name: Protect Flags
static_pressure:
name: Static Pressure
min_value: 0
sensor:
- platform: homeassistant
entity_id: sensor.dining_room_temperature_humidity_temperature_2
id: dining_room_aircon_follow_me
#attribute: current_temperature
name: "Dining Room Temperature Sensor"
filters:
- throttle: 10s
- heartbeat: 1min
- debounce: 1s
- lambda: return x;
on_value:
midea_ac.follow_me:
temperature: !lambda "return x;"
beeper: false
- platform: wifi_signal
name: ${friendly_name} Wi-Fi Signal
update_interval: 60s
- platform: uptime
name: "Uptime"
id: uptime_sec
internal: true
- platform: template
name: ${friendly_name} Uptime Days
lambda: |-
return (id(uptime_sec).state/60)/60/24;
icon: mdi:clock-start
unit_of_measurement: days
update_interval: 60s
switch:
- platform: midea_xye
midea_ac_id: heatpump
use_fahrenheit:
name: Use Fahrenheit
Oh, one thing I’ve noticed is that my “beeper: true” seems to be doing nothing. I tried both the XYE port on the machine itself and the connector going to the existing wall panel (wall panel not plugged in while I was testing that)
Ill have a few commits for this repository as soon as I get my unit working.
Currently getting “Received incorrect message length from AC for Command C0”. I’m getting 15 bytes by the looks of it. This is with the unit off.
Any ideas?
Received byte AA
Received byte C0
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 00
Received byte 3F
Received byte 01
I switched to a different module and now I’m getting some results!
[20:42:02.881][D][uart_debug:113]: >>> AA:C0:00:00:00:00:00:00:00:00:00:00:00:3F:01:55
[20:42:02.914][W][midea_xye:220]: Received 33 bytes for Command C0, using first 32
[20:42:03.025][D][uart_debug:113]: <<< AA:C0:00:00:00:00:E0:00:00:00:11:4F:4B:4C:FF:00:00:00:00:00:00:08:00:00:00:00:00:23:FF:FF:41:55:FE
[20:42:03.887][D][uart_debug:113]: >>> AA:C4:00:00:00:00:00:00:00:00:00:00:00:3B:01:55
[21:21:02.344][D][uart_debug:113]: >>> AA:C4:00:00:00:00:00:00:00:00:00:00:00:3B:01:55
[21:21:02.375][W][midea_xye:220]: Received 33 bytes for Command C4, using first 32
[21:21:02.410][D][climate:049]: 'Heatpump' - Setting
[21:21:02.414][D][climate:053]: Mode: DRY
[21:21:02.419][D][climate:438]: 'Heatpump' >>
[21:21:02.423][D][climate:441]: Mode: DRY
[21:21:02.428][D][climate:443]: Action: OFF
[21:21:02.432][D][climate:446]: Fan Mode: LOW
[21:21:02.435][D][climate:452]: Preset: NONE
[21:21:02.439][D][climate:461]: Current Temperature: 19.00°C
[21:21:02.446][D][climate:468]: Target Temperature: 21.00°C
[21:21:02.487][D][uart_debug:113]: <<< AA:C4:00:00:00:00:E0:00:00:81:11:4D:4C:4B:FF:00:00:00:00:00:00:0C:00:80:00:00:00:23:FF:FF:3A:55:FE
[21:21:03.345][D][uart_debug:113]: >>> AA:C3:00:00:00:00:82:04:15:00:00:00:00:3C:66:55
[21:21:03.376][W][midea_xye:220]: Received 33 bytes for Command C3, using first 32
[21:21:03.490][D][uart_debug:113]: <<< AA:C3:00:00:00:00:E0:00:82:81:11:4D:4C:4B:FF:00:00:00:00:00:00:0C:00:80:00:00:00:23:FF:FF:B9:55:FE
[21:21:04.284][I][midea_xye:276]: Sent Follow-Me data.
[21:21:04.359][D][uart_debug:113]: >>> AA:C3:00:00:00:00:82:04:15:00:00:00:00:3C:66:55
[21:21:04.385][W][midea_xye:220]: Received 33 bytes for Command C6, using first 32
[21:21:04.495][D][uart_debug:113]: <<< AA:C3:00:00:00:00:E0:00:82:81:15:4D:4C:4B:FF:00:00:00:00:08:00:0C:00:80:00:00:00:23:FF:FF:AD:55:FE
[21:21:05.354][D][uart_debug:113]: >>> AA:C0:00:00:00:00:00:00:00:00:00:00:00:3F:01:55
[21:21:05.385][W][midea_xye:220]: Received 33 bytes for Command C0, using first 32
[21:21:05.388][D][climate:438]: 'Heatpump' >>
[21:21:05.392][D][climate:441]: Mode: DRY
[21:21:05.395][D][climate:443]: Action: FAN
[21:21:05.399][D][climate:446]: Fan Mode: LOW
[21:21:05.402][D][climate:452]: Preset: NONE
[21:21:05.406][D][climate:461]: Current Temperature: 18.50°C
[21:21:05.410][D][climate:468]: Target Temperature: 21.00°C
[21:21:05.489][D][uart_debug:113]: <<< AA:C0:00:00:00:00:E0:00:82:81:15:4D:4C:4B:FF:00:00:00:00:08:00:0C:00:80:00:00:00:23:FF:FF:B0:55:FE
[21:21:06.362][D][uart_debug:113]: >>> AA:C4:00:00:00:00:00:00:00:00:00:00:00:3B:01:55
[21:21:06.393][W][midea_xye:220]: Received 33 bytes for Command C4, using first 32
[21:21:06.500][D][uart_debug:113]: <<< AA:C4:00:00:00:00:E0:00:00:81:11:4D:4C:4B:FF:00:00:00:00:08:00:0C:00:80:00:00:00:23:FF:FF:32:55:FE
[21:21:07.370][D][uart_debug:113]: >>> AA:C0:00:00:00:00:00:00:00:00:00:00:00:3F:01:55
[21:21:07.401][W][midea_xye:220]: Received 33 bytes for Command C0, using first 32
[21:21:07.404][D][climate:438]: 'Heatpump' >>
[21:21:07.408][D][climate:441]: Mode: OFF
[21:21:07.411][D][climate:443]: Action: OFF
[21:21:07.415][D][climate:446]: Fan Mode: LOW
[21:21:07.418][D][climate:452]: Preset: NONE
[21:21:07.422][D][climate:461]: Current Temperature: 18.50°C
[21:21:07.426][D][climate:468]: Target Temperature: 21.00°C
[21:21:07.501][D][uart_debug:113]: <<< AA:C0:00:00:00:00:E0:00:00:81:11:4D:4C:4B:FF:00:00:00:00:00:00:0C:00:80:00:00:00:23:FF:FF:3E:55:FE
Now after setting any climate mode the unit runs (if it has time) for a couple of cycles before turning off.
I get no responses to C6 commands. The controller indicates follow me support and allows the setting of static pressure so I’m guessing the frame is invalid
I required some patches to ignore an additional byte that is present on the line in communication from the AC. It is currently unknown if this is an artifact of my RS485 hardware, wiring or unit etc.
Wired controller has 7 fan modes and describes in the settings a constant fan mode. I have not worked out how to get information on this.
Sending 0xC4 is not allowed on my unit. It results in the unit turning off.
I have inside colil inlet temp & current temperature. Outside coil temperature is 0xFF
I intend to contrbute some patches once I’ve worked out this unit completely.
Does anyone have any information on sniffing the higher voltage X1/X2 protocol? Is it framed the same. Level shifted TTL? Or level shifted RS485?
Hi all
I’m joininig after reading this topic.
It seems you are going into lot of trouble to get data that might be already available from the USB port with the Midea dongle.
I have personally found several hidden inputs that I needed and I was able to add them to the midea-ac-lan code. Among those inputs are T1,T2,T3,T4,TP, defrost state, outdoor unit power, outdoor unit fan speed, indoor unit fan speed, indoor unit louver angles, etc. I can monitor all of them in HA without fiddling with any circuit board or special interface.
Also midea-msmart (the python script used by midea-ac-lan from mill1000) contains original source code reference from Midea itself, with comments in Chinese.This code can be useful to reverse engineer the protocol and the various responses from the device.
See:
Just an FYI, I recently upgraded to esphome 2026.3 and started having weird issues with this add-on. My deleted post had a bunch of theories none of which panned out. I thought I’d fixed it by simply re-installing but I just had the same issue happen where the follow me temp gets queued but is never delivered to the AHU. This leads to the system thinking it’s very cold in my house and the heat pump switches to stage 2 heating which is suboptimal. I’m currently rolling back esphome to the previous version to see if it fixes the problem. There were changes to a few things which could be related but I couldn’t definitively figure out the cause. cc @mdrobnak
So it’s queued but never delivered: usually you get a second log that says Sent Follow-Me data so it does seem UART related. There were some changes to how flush works in this version but at a glance the change doesn’t look like it would be contract-breaking.
the discovery of the T1,T2,… are great news! Thank you for your work!
Now that winter is over and I finally had time for some debugging, I wanted to share my progress on this topic.
I connected a logic analyzer to the display board of my Midea Xtreme Save Blue and started tracing the serial interface between the display board and the mainboard. The R/T pin is wired to an HA/HB adapter board (I also have an XYE module, which I will add tomorrow), as well as the IR receiver and the Wi-Fi dongle.
Last year I mentioned that the XYE module contains a hidden “Follow Me” function. Now comes the interesting part:
It appears that the R/T pin, where the XYE or HA/HB adapter is connected, uses the same protocol as the Wi-Fi dongle (with a wrapper). I am not sure whether this is already known in the community. So the HA/HB bus at least is converted to the UART-R/T protocol and not directly forwarded to the display board
For the Xtreme Save Blue, the communication path looks like this: Room Module → HA/HB Adapter Board (HA/HB to R/T single pin) → single-wire communication → Display Board.
My assumption is that the serial protocol contains additional flags, possibly for the Follow Me temperature and other features that currently rely on IR.
Can you explain in more detail how you are reading outdoor unit power,and the other entities you have found?
What is the yaml you are using along with Midea-AC-LAN?
TIA
I had to modify the python scripts to support new group responses and map the inputs.
I am using my own forks from the mill1000/midea-ac-py repo and mill1000/midea-msmart (officially named Midea Smart AC in HACS)
YMMV. I have only tested with my device, and the changes are experimental. My fork is not intended to be used officially, it’s mainly for my own usage and it’s not ready to be merged into the main repo. I let the maintainer take care of it.
This is my fork, you can use it directly from HACS by adding a custom repository:
This also uses my own midea-msmart fork (which does most of the protocol logic, if you’re interested in seeing the code, but it’s taken automatically once you install the above integration).
Once installed you should see the new inputs as entities:
Next 0xC6 the thorn in my side. If anyone has any guesses I would much apreciate it as I havent made much progress on getting follow me to be accepted.
The controller engineering menu states its supported (and set to the source). I have tested every value for temperature from 1-255 with no responses.