Repository navigation
Protocol Overview
You don't need this page to use the library. It's for anyone who wants to understand what goes over the wire, debug a unit with --debug, or extend the protocol package.
Everything here is ported from midea-local. The tests check the Java code byte for byte against frames produced by midea-local 12.1.0.
From the outside in:
TCP port 6444
└─ 0x8370 envelope V3 only: session encryption and signature
└─ 0x5A5A packet device id, timestamp, MD5 checksum
└─ 0xAA frame the actual message, AES-128-ECB encrypted
└─ body body type byte + payload (+ message id + CRC-8)
83 70 | size (2, big endian) | 20 | padding<<4 | type | counter (2) | data | SHA-256 (32)
- Type 0 is the handshake request, 1 the answer, 6 an encrypted request, 3 an encrypted response.
- Encrypted data is AES-256-CBC with a zero IV and the session key, padded with random bytes to a 16 byte boundary.
- The SHA-256 covers the header and the plaintext.
Handshake: the client sends the 64 byte token. The unit answers with 32 bytes of encrypted random data plus its SHA-256. The client decrypts it with the 32 byte key, checks the hash, and XORs the random data with the key. The result is the session key.
0-1 5A 5A
2-3 type: 01 11 data, 01 10 heartbeat
4-5 total length, little endian
6-7 20 00 (7B 00 for a heartbeat)
12-19 timestamp
20-27 device id, little endian
40- AES-128-ECB(0xAA frame), PKCS#7 padded
last 16 MD5(packet + salt)
The AES key and the salt are the same for every unit.
AA | length | device type | 00 00 00 00 00 | protocol version | message type | body | checksum
- Device type is
0xACfor air conditioners. - Message type:
02set,03query,04/05notifications from the unit,A0appliance info. - The checksum is the two's complement of the byte sum, from the length byte on.
- The protocol version must match what the unit reported in its appliance info answer.
Most bodies end with a rolling message id and a CRC-8/MAXIM over body type, payload and id.
| Request body | Type | Purpose | Answer |
|---|---|---|---|
0x41 81 00 FF ... |
query | basic status | 0xC0 |
0x40 ... |
set | basic settings (full state) | 0xC0 |
0xB1 n tag tag ... |
query | new protocol values | 0xB1 |
0xB0 n tlv ... |
set | new protocol features |
0xB0 / 0xB1
|
0xB5 01 00 / 0xB5 01 01 01
|
query | capabilities, first and second frame | 0xB5 |
0x41 21 01 4x 00 01 |
query | group data (energy, runtime, service) | 0xC1 |
0x41 42 00 FF 02 00 02 ... |
query | toggle display | 0xC0 |
| 19 zero bytes | A0 |
appliance info, gives the protocol version | A0 |
The unit can also send 0xA0 and 0xA1 notifications without being asked. The client applies them like any other answer.
| Group | Byte 3 of the answer | Content |
|---|---|---|
| 0 | 0x40 |
runtime counters |
| 1 | 0x41 |
compressor, T1 to T4, discharge temperature |
| 2 | 0x42 |
indoor fan, condensate pump |
| 3 |
0x43 (some units answer 0x03) |
outdoor fan |
| 4 | 0x44 |
energy and power |
| 5 | 0x45 |
humidity |
| 7 | 0x47 |
compressor power |
Requests and 0xB5 answers encode each parameter as tag_lo tag_hi len value. 0xB0/0xB1 answers add a zero byte before the length: tag_lo tag_hi 00 len value.
| Tag | Meaning |
|---|---|
0x0009 |
up/down louver angle |
0x000A |
left/right louver angle |
0x0015 |
indoor humidity |
0x0017 |
display |
0x0018 |
breezeless |
0x001A |
prompt tone |
0x0039 |
self cleaning |
0x0042 |
indirect wind |
0x0048 |
power limit |
0x004B, 0x0233
|
fresh air |
0x00CD |
quiet outdoor unit |
0x022C |
buzzer |
- Set point in
0x40/0xC0: low nibble isdegrees - 16, bit0x10adds half a degree. That's why only 16 to 31.5 can be expressed. - Sensor values:
(raw - 50) / 2, plus a tenth digit from a separate nibble.0xFFmeans no sensor.
The client sends a fixed 72 byte probe to UDP ports 6445 and 20086. Units answer with a 0x5A5A packet (V2) or the same packet behind an 8 byte 0x8370 header (V3). The encrypted part holds the TCP port, serial number, model and Wi-Fi SSID; the device type is the second part of the SSID (net_ac_...).
The cloud files tokens under a "UDP id": SHA-256 of the 6 byte device id, with the two halves XORed. Units differ in byte order, so the client asks for both big and little endian, then tests each answer with a real handshake.
midea-ac · MIT License · Protocol based on midea-local · Not affiliated with Midea