Midea VRF Air Conditioner - How to integrate with HA

[I am creating this topic to ask from everyone else who has similar system and could help understanding the system and integrate it with HA]

We recently installed a Midea VRF (Variable Refrigerant Flow) air conditioner (model is MDV-V200WN1), which includes one outdoor unit (ODU) and several indoor units (IDUs). Additionally, we added a Wi-Fi wall controller (WDC3-120T), connected to one of the indoor units. The indoor units (IDUs) are linked to each other in a daisy chain configuration (wifi controller is connected to IDU1, IDU1 is connected to IDU2, IDU2 is connected to IDU3 and so on; See 2nd figure below).

I successfully added the Wi-Fi controller to the SmartHome app (I think formerly known as MSmartHome / MSmartLife), and it works fine-ish.

However, I dislike relying on online solutions, and I haven’t been able to connect it to my Home Assistant.
Any advice would be greatly appreciated. I’ve attached some photos for reference.

I raised a question in media-ac-lan and no help there. In fact, I scanned the wifi controller’s ports and it looks like it’s not exposing the port that midea-ac-lan is expecting.
I Also looked at Midea-branded-ACs thread, and I don’t think it could directly help this system.
I will add more of my findings later on.

Hopefully this topic could attract more people to find a proper solution.

Here are some photos:

Wifi Controller:
wdc3-120t

Wifi Controller Wiring:


(Note that L1 is connected to the wall controller. We don’t have a 2nd wall controller, so L2 is not used. L3 is connected from first indoor unit (IDU) to 2nd IDU, and 2nd to third and so on.)

IDU and ODU example:

SmartHome app:

1 Like

X1X2 seem is home bus standard, like the P1P2 bus from Daikin, from their docs it include both power and data, the voltage between them is 18V. You can ask in opensource project P1P2MQTT.

1 Like

Yes thanks. It’s some sort of modulation on 18vdc. I’ll check that out. :+1:

Same issue, all my IDUs with individual WDC-86T works as expected in Midea SmartHome app, but still looking for solutions to integrate HA

Hello Friend!
Did you found a solution?

not a best solution, but WDC-XX wall panels can act as IR receiver.
I’m still looking for full bidirectional integration

Yeah the wall controller has ir receiver, however it will work globally. It means if I point the remote to the wall controller, it will turn on “all units” which is not what I want. In fact I disabled the ir on the wall controller.

At the moment I am sniffing RS485 bus on M1M2. It’s very busy and I’m yet to reverse engineer it.

Has someone got any success

Have you looked at this product?

SMARTLIGHT SLWF-01pro

You can get it for about $13 US I think.

There is no such usb ready port on the IDUs. In fact, as far as I understood, the IDUs are not supposed to be indivodually connected to the internet (through a wifi dongle, such as the hacky one that you mentioened). I did look at the IR board and couldn’t see any port that could hint a tx/rx capabilty. I’m sure there are many smart people who can eventually find a way to help me.

The wifi is for your system [e.g. Home Assistant] to communicate with it. It is not connected to any cloud service. For non-USB inputs there are people that show how to connect to this device or something you can make yourself that has basically the same ports. I have also seen messages about swapping the RX/TX ports. I am leaving this thread. Good luck other people.

1 Like

Hello everyone,

I work in Clivet’s after-sales support team.

All of our air conditioning units are rebranded Midea products.

If I can help you in any way, please let me know.

I currently have a WDC3-120T in my home office and will try to integrate it into Home Assistant over the next few days.

Best regards, Mark

2 Likes

Keep me updated please

You can send me private message, I have hardware support X1X2, but it is require additional work to decode it.

Intesis™ Midea-Modbus Interface (INMBSMID001I000) I wonder if this would help

I have been working to control my unit which supports both X1/X2 and D1/D2 (XYE).

I’d love any information people have worked out.

XYE is RS485 but X1X2 same like Daikin P1P2, you can take photo of the mainboard and find ICs handle the protocol.

I made an sniffing circuit on a bread board to sniff rs485 on the D1/D2 wires which is connected to all indoor units. I [think] I found the general messaging format, but I couldn’t reverse engineer the payload yet.
e.g.;

[17:34:08][D][text_sensor:069]: 'RS485 Message': Sending state AA 2F 00 00 04 00 01 00 C5 62 55 FE

[17:34:08][I][rs485_msg:075]: Received Message: AA 2F 04 00 00 00 1A 00 3D 06 01 02 00 01 0A 0A 97 00 02 00 00 04 30 56 11 04 04 0F 00 01 00 33 00 FF 92 55 FE

[17:34:08][D][text_sensor:069]: 'RS485 Message': Sending state AA 2F 04 00 00 00 1A 00 3D 06 01 02 00 01 0A 0A 97 00 02 00 00 04 30 56 11 04 04 0F 00 01 00 33 00 FF 92 55 FE

[17:34:08][I][rs485_msg:075]: Received Message: AA 20 04 00 04 00 07 00 FF 7F 03 00 FF 7F 8C E6 55 FE

[17:34:08][D][text_sensor:069]: 'RS485 Message': Sending state AA 20 04 00 04 00 07 00 FF 7F 03 00 FF 7F 8C E6 55 FE

[17:34:08][I][rs485_msg:075]: Received Message: AA 20 00 00 04 00 07 00 FF 7F 03 00 FF 7F 7D 29 55 FE

[17:34:08][D][text_sensor:069]: 'RS485 Message': Sending state AA 20 00 00 04 00 07 00 FF 7F 03 00 FF 7F 7D 29 55 FE

Protocol: RS485 (4800 baud, 8N1).
Master Node: In my case is 0x04 (this unit is connected to wall controller through X1X2 wires)
Slave Nodes: 0x00, 0x01, 0x02, 0x03, 0x05 (note that 0x04 is master)

The Query (Master asks specific unit):
Looking at e.g.: AA 20 00 00 04 00 07 ...

  • AA: Start Header.
  • 20: Command Type (Query/Status).
  • 00: Destination Address (Indoor Unit 0).
  • 04: Source Address (Master).
  • 00 07: Data Length (Short message, asking for info).

The Response (Slave node replies with data):
Looking at the immediate follow-up: AA 20 04 00 00 00 35 ...

  • AA: Start Header.
  • 20: Command Type.
  • 04: Destination Address (Back to Master).
  • 00: Source Address (From Unit 0).
  • 00 35: Data Length (Long message, 0x35 hex = 53 bytes of data).

And some more stuff is happening like detailed quarry, possibly asking for the current state, temperature, fan, etc.
Also there should be more payloads like for sending commands like change the the temperature, fan, working mode etc.

I am yet to figure out who’s who as I don’t work on it actively and more importantly I may need community’s help.

1 Like

Wait your unit controlling the AC results in an echo put onto the D1/D2 lines? Mine doesnt if thats the case you are incredibly lucky and thats likely exactly what I need to complete my reverse engineering.

Those packets though like mine also have an extra byte compared to standard XYE! So its not just my unit.

XYE is mostly reverse engineered and I’ve been working on getting my unit to work well with it in this thread https://community.home-assistant.io/t/midea-a-c-via-local-xye/

I’m still actively experimenting with control but I do have heat/cool/fan only and dry working (GitHub - splitice/esphome at units_fixy · GitHub). I do not have follow me (which is a must for my unit), static pressure control or access to fan speeds 1-7 (including constant fan speed)

Can you sniff more of your packets please. I have a particular interest in getting a capture of:

  1. Setting the static pressure in the controller
  2. Follow me data (temperature readings from the controller)
  3. Setting fan level 1-7
  4. General operational sequence (i.e series of packets it sends at what interval when in heat/cool mode)

If you can log what mode the unit is in + what you did along side a capture of the communication I can likely handle the reverse engineering.

Ok let’s start simple.
Below is a filtered communication between id 4 (master) and 1 (client node). I filtered the communication so it only captures messages between the two. Tell me what you see in the payload.
Before that, just adding/correcting to what I said before to figure out what the message is:

e.g. for this message: 
AA 2A 01 00 04 00 01 01 50 73 55 FE
AA -> start (preamble)
2A -> command
01 -> destination id
00 -> either reserved, or could be in pair with destination id to be 16 bits to support longer ids.
04 -> source (master) id
00 -> same as 00 above
01 -> payload length
01 -> payload (length is 1 in this example)
50 73 -> CRC-16/MODBUS (0x7350)
55 FE -> end (prologue)
[14:38:19.198] 'AA 2A 01 00 04 00 01 01 50 73 55 FE'
[14:38:19.259] 'AA 2A 04 00 01 00 09 01 00 00 00 00 00 00 00 00 CF 18 55 FE'
[14:38:22.211] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:22.380] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:23.995] 'AA 2A 01 00 04 00 01 02 10 72 55 FE'
[14:38:24.101] 'AA 2A 04 00 01 00 1D 02 39 01 00 00 00 00 00 00 00 00 00 00 AF 00 00 00 00 00 00 36 00 00 00 00 E1 08 00 00 56 1E 55 FE'
[14:38:25.199] 'AA 2E 01 00 04 00 01 00 D4 73 55 FE'
[14:38:25.394] 'AA 2E 04 00 01 00 42 01 17 05 FF FF 8C 70 8C 70 00 00 00 00 00 00 50 FF 00 7F FF 00 01 01 00 11 00 00 10 20 04 1E 40 02 65 00 80 00 01 03 35 35 00 00 FE 11 00 00 00 80 8C 60 00 FF FF 01 00 00 00 00 00 00 1A 00 C0 00 00 09 6F 55 FE'
[14:38:25.796] 'AA 2F 01 00 04 00 01 00 C4 B3 55 FE'
[14:38:25.898] 'AA 2F 04 00 01 00 1A 00 42 01 01 02 00 01 0A 0A 97 00 02 00 00 04 30 56 11 04 04 0F 00 01 00 33 18 00 BD 55 FE'
[14:38:29.410] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:29.579] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:31.197] 'AA 23 01 00 04 00 01 65 C8 98 55 FE'
[14:38:31.285] 'AA 23 04 00 01 00 15 65 02 80 7E 7E 7E 04 41 41 00 EE EE 0E 00 00 00 00 00 00 00 00 A2 85 55 FE'
[14:38:34.207] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:34.377] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:35.996] 'AA 2A 01 00 04 00 01 01 50 73 55 FE'
[14:38:36.057] 'AA 2A 04 00 01 00 09 01 00 00 00 00 00 00 00 00 CF 18 55 FE'
[14:38:39.006] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:39.174] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:40.789] 'AA 2A 01 00 04 00 01 02 10 72 55 FE'
[14:38:40.907] 'AA 2A 04 00 01 00 1D 02 39 01 00 00 00 00 00 00 00 00 00 00 AF 00 00 00 00 00 00 36 00 00 00 00 E1 08 00 00 56 1E 55 FE'
[14:38:41.992] 'AA 2E 01 00 04 00 01 00 D4 73 55 FE'
[14:38:42.190] 'AA 2E 04 00 01 00 42 01 17 05 FF FF 8C 70 8C 70 00 00 00 00 00 00 50 FF 00 7F FF 00 01 01 00 11 00 00 10 20 04 1E 40 02 65 00 80 00 01 03 35 35 00 00 FE 11 00 00 00 80 8C 60 00 FF FF 01 00 00 00 00 00 00 1A 00 C0 00 00 09 6F 55 FE'
[14:38:42.597] 'AA 2F 01 00 04 00 01 00 C4 B3 55 FE'
[14:38:42.698] 'AA 2F 04 00 01 00 1A 00 42 01 01 02 00 01 0A 0A 97 00 02 00 00 04 30 56 11 04 04 0F 00 01 00 33 18 00 BD 55 FE'
[14:38:43.810] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:43.966] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:45.590] 'AA 23 01 00 04 00 01 65 C8 98 55 FE'
[14:38:45.677] 'AA 23 04 00 01 00 15 65 02 80 7E 7E 7E 04 41 41 00 EE EE 0E 00 00 00 00 00 00 00 00 A2 85 55 FE'
[14:38:48.608] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:48.776] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:50.388] 'AA 2A 01 00 04 00 01 01 50 73 55 FE'
[14:38:50.454] 'AA 2A 04 00 01 00 09 01 00 00 00 00 00 00 00 00 CF 18 55 FE'
[14:38:53.403] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:53.570] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:55.195] 'AA 2A 01 00 04 00 01 02 10 72 55 FE'
[14:38:55.298] 'AA 2A 04 00 01 00 1D 02 39 01 00 00 00 00 00 00 00 00 00 00 AF 00 00 00 00 00 00 36 00 00 00 00 E1 08 00 00 56 1E 55 FE'
[14:38:56.395] 'AA 2E 01 00 04 00 01 00 D4 73 55 FE'
[14:38:56.580] 'AA 2E 04 00 01 00 42 01 17 05 FF FF 8C 70 8C 70 00 00 00 00 00 00 50 FF 00 7F FF 00 01 01 00 11 00 00 10 20 04 1E 40 02 65 00 80 00 01 03 35 35 00 00 FE 11 00 00 00 80 8C 60 00 FF FF 01 00 00 00 00 00 00 1A 00 C0 00 00 09 6F 55 FE'
[14:38:56.987] 'AA 2F 01 00 04 00 01 00 C4 B3 55 FE'
[14:38:57.089] 'AA 2F 04 00 01 00 1A 00 42 01 01 02 00 01 0A 0A 97 00 02 00 00 04 30 56 11 04 04 0F 00 01 00 33 18 00 BD 55 FE'
[14:38:58.203] 'AA 20 01 00 04 00 07 00 FF 7F 02 00 FF 7F 81 16 55 FE'
[14:38:58.372] 'AA 20 04 00 01 00 37 00 00 00 00 00 ED 00 ED 00 FF 7F FF 7F FF 7F 2F 01 00 80 80 7E 7E 7E 41 41 7E 7E 7A FF EE 00 40 10 00 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 00 00 00 FF 7F AB F9 55 FE'
[14:38:59.989] 'AA 23 01 00 04 00 01 65 C8 98 55 FE'
[14:39:00.081] 'AA 23 04 00 01 00 15 65 02 80 7E 7E 7E 04 41 41 00 EE EE 0E 00 00 00 00 00 00 00 00 A2 85 55 FE'

Edit - added CRC

Ok another progress on this.

The CRC is CRC-16/MODBUS - little endian.

So The trick is not to take the starting 0xAA into account!

So for above example AA 2A 01 00 04 00 01 01 50 73 55 FE, we know AA is the starting byte and 55 FE are the ending bytes - both constant. Let’s ignore them.

If we put 2A 01 00 04 00 01 01 into CRC calculations, we get 0x7350 which is what we have in the message: 50 73.

Here’s a python code to test the crc:

def calc_modbus_crc(data: bytes) -> bytes:
    """
    Calculates the CRC-16/MODBUS for the given data.
    Returns the 2-byte CRC in little-endian format (LSB, MSB).
    """
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc >>= 1
    
    return crc.to_bytes(2, 'little')  # return as two bytes: [low byte, high byte]

# full_message = bytes.fromhex('AA 20 04 00 01 00 37 00 00 00 00 00 DA 00 DA 00 FF 7F FF 7F FF 7F 8F 00 00 80 80 82 82 82 41 41 7B 7A 77 FF EE 00 48 10 04 00 00 00 FF 02 E3 CC 00 00 00 00 00 00 12 00 00 B2 00 00 FF 7F C7 DA 55 FE')
full_message = bytes.fromhex('AA 2A 01 00 04 00 01 02 10 72 55 FE')
message_with_crc = full_message[1:-2] # get rid of the starting and ending bytes:
message_without_crc = message_with_crc[:-2] # get rid of the known crc
known_crc = message_with_crc[-2:] # save the known crc

crc_bytes = calc_modbus_crc(message_without_crc)

print(f"Input Message: {full_message.hex().upper()}")
print(f"Known      CRC (Hex): {known_crc.hex().upper()}") 
print(f"Calculated CRC (Hex): {crc_bytes.hex().upper()}") 
print(f"Match" if known_crc == crc_bytes else "Mismatch")