Midea A/C via local XYE

@NyxVale63

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.

Dr Smart Tool demo Innovair

If you plug in the addresses into this app, will it help?

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
  • Active control via XYE

…could potentially be a very robust solution.

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.

I definitely don’t see that behavior.

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…

-Matt

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

1 Like

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.

Sensor data looks faulty too.

This is potentially the same issue as @jasonshearer

I tested mdrobnak-0.2.1 (did nothing at all) and units_switch (as reported)