bekmansurov / gree-hvac-protocol

Description of data exchange protocol for GREE air conditioners via UART based on reverse engineering
19 stars 2 forks source link

Swing mode encoding, and further packet structure updates! #6

Open evilwombat opened 1 week ago

evilwombat commented 1 week ago

Hello. I am reverse-engineering the binary protocol that the Gree app uses to talk to the Wifi unit, and I am seeing a similar packet structure. The status packet used for my unit has a length field of 0x25, but some of the fields definitely match what you have found.

Some notes: Byte 12 - swing mode (4 bits for vertical, 4 bits for horizontal) Values:

Byte 8, bit 7 = Device on/off state Byte 8, bits 6-4: Device mode (0=Auto, 1=Cool, 2=Dehimidify, 3=Fan, 4=Heat)

The temperature is encoded in an absolutely idiotic way. For Celsius, it's stored as Degrees C - 16, in the upper 4 bits of byte 9. Then, bit 3 of byte 13 indicates if an extra 0.5 degrees should be added. For Fahrenheit, it's something far more stupid and I am still trying to determine what's going on...

evilwombat commented 1 day ago

I'm working on a Python script to replicate the status decode / control encode features of the crummy (and now, outdated) wifi app. The wifi app for my unit uses a binary protocol, unlike the JSON protocol that is commonly understood.

I have been trying to sniff the UART traffic between the wifi board and the main unit, while trying to control the unit using both the RF remote, and the wifi app (or in my case, my python script that can set the device state, similar to the app).

The good news is, it appears that the binary packet sent by the app very closely matches up with the control packet sent by the wifi board to the main unit. This means that most of this packet can be understood based on the understanding of the control packet sent by the app (I will clean up the code and post it later).

It seems that the 2A packet basically has an app control packet embedded inside it. Example:

                                    /---- Humidity from onboard sensor
                                   /   /-- Temperature from onboard sensor
                                  /   /    /--- Beginning of app control packet main body
                                 /   /    / 
App sends: config = 7e 7e 25 01          af c2 80 02 82 30 20 00 80 67 91 3c 00 00 00 04 00 bb cc cc 00 00 00 59 00 00 54 1a 21 c0 02 02 00 00 00       a2
Wifi board sends  : 7e 7e 2a 01 1f 1e 30 af c2 80 02 82 30 20 00 80 67 91 3c 00 00 00 04 00 bb cc cc 00 00 00 59 00 00 54 1a 21 c0 02 02 00 00 00 00 02 16

Spaces are added for clarity. The app packet begins with 7E 7E 25 01 but the wifi board packet begins with 7E 7E 2A 01. So far, so good. Next, the wifi board packet contains three new bytes: 1F, 1E, and 30. I believe 1F and 1E represent the current humidity and temperature, as measured by the sensor on the wifi board. Blowing air on this sensor causes these values to rapidly change. I am not sure what the 30 byte is. The next value after this is AF, which is the beginning of the config structure sent by the app. I will explain the encoding later, when the code is cleaned up. After this, there are two more mystery bytes (00 02) and I don't know what this does, but the wifi board seems to send 00 02 during updates and 00 00 otherwise. Following that, is the standard checksum.

The AF value is interesting. The app always sends AF but the remote sends either 85 or 87, depending on which features are being changed. I wonder if this is a bitmask indicating which settings are actually being updated.

My unit uses CS532U, by the way.

EDIT: 0xAF indeed looks like a bitmask of settings that are requested to be updated. The mobile app sends 0xAF but the remote can send 0x85 or 0x87. The remote will send 0xC5 when I FEEL / FOLLOW ME are active, which tells the unit to use the remote's temp sensor (value specified in a separate byte). When my script sends 0xAF and sets the bit that enables using the remote temp sensor, the system quickly falls back to the previous value of the remote temp. However, sending 0xCF instead of 0xAF indeed causes the new remote temp value to be latched by the main unit. So, if you want to tell the unit to ignore the temp reading from the wifi board, and to specify an alternate indoor temp reading (such as from a sensor near where the user is sitting), this is also possible. Sending 0x40 instead of 0xAF will seemingly update only the remote temp value and nothing else? This seems useful because the unit will not make a beeping sound in response to this update, which would get annoying if you were updating the remote temp reading every minute.

Of course, if you are replacing the entire CS532U with your own hardware, you can just override the temp/humidity reading being reported in the first few bytes sent by the CS532U.