tomikaa87 / gree-remote

Simple remote control utility for Gree Smart air conditioners
GNU General Public License v3.0
280 stars 64 forks source link

Mind sharing some details about how does Gree device work? #1

Closed oroce closed 6 years ago

oroce commented 7 years ago

Hey, I have a Gree Smart AC as well and if I can guess you are mimicking the Gree Smart app. Can you share some details how does it work? I was trying to reverse engineer it, but I had no luck.

I tried:

I emailed them for docs, no reply.

Do you have a documentation or did I miss something?

Thanks

tomikaa87 commented 7 years ago

Hi Robert,

Thank you for your interest in my project. You are correct, I intend to create a library (and some front-ends for it [Windows, Mac, Android]) that mimic the functionality of the "official" Gree Smart app. Currently, as you can see, the project is in a very early state, but I'm working on it as my time allows.

I did not try to contact the manufacturer, but I did some research on the Internet to find details of the protocol without any luck, so I decided to find out how the Android app works. After analyzing the network traffic with Wireshark, I decided to disassemble the application (there are several, even online tools to do that) and reverse-engineered the protocol from that. It's a pretty basic, JSON-based protocol with some encryption. It uses AES-128 ECB to encode the data parts of the packet. The application has a master key which is used to initiate communication with a specific AC unit. In this process there is a binding phase where the application pairs with the unit and gets a device key from it. After binding, this unit key is used to encrypt and decrypt the packages.

The network part of the protocol uses UDP on port 7000, but my partial implementation currently works only if you set up the AC unit and it's connected to the local network. There is no option to initiate direct WiFi connection to the unit at the moment. The communication begins with a scanning phase where a scan packet is broadcasted on the local network. All the online units reply to that with a description packet which is encypted with the master key. In the response there is a device ID, which is used to address a specific unit. After scanning, you must bind the unit to get the device's unique AES key and from that point, you can send status request and update packets encrypted with that key.

Tamas

oroce commented 7 years ago

Hey Tamas,

wow thanks for detailed explanation. (I love these chinese manufacturers, i really doubt that this is the simplest solution to provide secure connection between an app and an AC unit.)

I was trying to understand your implementation, can it happen that you forgot to add src/deviceviewmodel.cpp and src/deviceitem.cpp to your repository?

Cheers

tomikaa87 commented 7 years ago

Hi,

Probably I forgot to add them, but the basic implementation can be found in GreeLib/src/devicefinder.cpp and GreeLib/src/device.cpp. DeviceFinder does the initial scanning and the binding, Device manages the AC unit. You can find some packet creator functions in protocolutils.cpp.

tomikaa87 commented 7 years ago

I have just updated the library which now can give you the device parameters in a more digestible format with some nice methods. I have also mapped some numeric values to certain states of the fan, mode, swing etc, but there are a handful of values that my device doesn't seem to use. Maybe you should check the library with your device if it uses them.

It'd be more than welcome if you'd create a pull request with some new mappings. 😀

oroce commented 7 years ago

Wow thanks.

In the meantime I started playing with my AC and started reimplementing this library as a nodejs module but my goal is adding to home assistant, but node is the language which I'm most experienced with.

I'm happy to create a pull request once I'm familiar enough with the communication between the app and the AC.

oroce commented 7 years ago

Now I was able to get the status of the AC: https://github.com/oroce/node-gree-smart/pull/1

Basically this is what I received from the unit:

{
  "id": "f4911e053a74",
  "name": "1e053a74",
  "address": "192.168.1.113",
  "port": 7000,
  "bound": true,
  "props": {
    "Pow": 0,
    "Mod": 1,
    "SetTem": 20,
    "WdSpd": 3,
    "Air": 0,
    "Blo": 0,
    "Health": 0,
    "SwhSlp": 0,
    "Lig": 1,
    "SwingLfRig": 0,
    "SwUpDn": 1,
    "Quiet": 0,
    "Tur": 0,
    "StHt": 0,
    "TemUn": 0,
    "HeatCoolType": 0,
    "TemRec": 0,
    "SvSt": 0
  },
  "key": "<--key-->"
}

and in the meantime, I disassembled the app and started figuring out how can we send commands to the unit.

tomikaa87 commented 7 years ago

Can you play with the values using the remote control or the android application and see which variable is changed?

I already captured the device control packet and implementing it in the library right now. There is also a UI for device testing in the GreeRemoteQt application.

oroce commented 7 years ago

I did, if I turn on the unit using the app, the Pow changes to 1.

update: just tried to change the temperature (SetTem got updated), then the up and down (the SwUpDn got updated). so reading the device's status definitely works.

tomikaa87 commented 7 years ago

If you see device.h, you can find some values that I mapped already.

oroce commented 7 years ago

awesome, tomorrow I'm gonna continue playing with mine and report back here the results.

tomikaa87 commented 7 years ago

Setting the temperature is done via the following pack:

pack: {
    "opt": ["TemUn", "SetTem"],
    "p": [0, 27],
    "t": "cmd"
}

TemUn seems to be the temperature unit, 0 for Celsius, 1 for Fahrenheit and obviously SetTem is the temperature value.

If the command is executed successfully, the response pack should look like this:

pack: {
    "t": "res",
    "mac": "<--- MAC --->",
    "r": 200,
    "opt": ["TemUn", "SetTem"],
    "p": [0, 27],
    "val": [0, 27]
}

Accordingly, you can use these packets for the other parameters you see in the status packet.

oroce commented 7 years ago

It works. I tried it this morning, and the temperature was set to 27

oroce commented 7 years ago

I made a dummy server to simulate the AC unit: https://github.com/oroce/node-gree-smart/pull/3/files

I'm playing with the mobile app to figure out how to change things, so far I have

Power

Turning on the unit:

{
    opt: ['Pow'],
    p: [1],
    t: 'cmd'
}

Turning off:

{
    opt: ['Pow'],
    p: [0],
    t: 'cmd'
}

Windspeed

Changing windspeed to low:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 1, 0, 0, 0 ],
  t: 'cmd'
}

Changing windspeed to medium low:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 2, 0, 0, 0 ],
  t: 'cmd'
}

Changing windspeed to medium:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 3, 0, 0, 0 ],
  t: 'cmd'
}

Changing windspeed to medium high:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 4, 0, 0, 0 ],
  t: 'cmd'
}

Changing windspeed to high:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 5, 0, 0, 0 ],
  t: 'cmd'
}

Auto windspeed:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 3, 0, 0, 0 ],
  t: 'cmd'
}

Changing windspeed to turbo:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 5, 0, 1, 0 ],
  t: 'cmd'
}

Changing windspeed to quiet:

{
  opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ],
  p: [ 1, 2, 0, 0 ],
  t: 'cmd'
}

Up and down

Changing up and down

{ 
  opt: [ 'SwUpDn' ],
  p: [ 0 ],
  t: 'cmd' 
}

Possible values:

0 // blowing air to the ceiling, upside
10
11 
1 // full range

Features

Air

{
  opt: [ 'Air' ],
  p: [ 1 ],
  t: 'cmd'
}

To turn it off set p to 0

Dry

{
  opt: [ 'Blo' ],
  p: [ 1 ],
  t: 'cmd'
}

To turn it off set p to 0

Health

{
  opt: [ 'Health' ],
  p: [ 1 ],
  t: 'cmd'
}

To turn it off set p to 0

Light

{
  opt: [ 'Lig' ],
  p: [ 1 ],
  t: 'cmd'
}

To turn it off set p to 0

Sleep (turning on)

{
  opt: [ 'SwhSlp', 'SlpMod' ],
  p: [ 1, 1 ],
  t: 'cmd'
}

Saving (turning on)

{
  opt: [ 'SvSt', 'WdSpd', 'Quiet', 'Tur', 'SwhSlp', 'SlpMod' ],
  p: [ 1, 0, 0, 0, 0, 0 ],
  t: 'cmd'
}

Preset

Turning off at 20:40 on Tuesday and Friday

{
  "cmd": [
    {
      "mac": [
        "foo-mac"
      ],
      "opt": [
        "Pow"
      ],
      "p": [
        0
      ]
    }
  ],
  "enable": 0,
  "hr": 20,
  "id": 0,
  "min": 40,
  "name": "5363686564756c65",
  "sec": 0,
  "t": "setT",
  "tz": 1,
  "week": [
    0,
    0,
    1,
    0,
    0,
    1,
    0
  ]
}

Todo:

jllcunha commented 7 years ago

Hi Robert and Tamas,

I'd been looking for some info on interfacing with the Gree airconditioner and stumbled upon this conversation. I'm amazed at the work that has been done :)

I hope you dont mind, but I took the liberty of creating a Java version of your library. So far I have Scanning, Binding, Power on & off and Set Temperature working.

My goal is to create a binding to use in OpenHab.

Please let me know if I can be of any help :)

Thanks, John

tomikaa87 commented 7 years ago

Hi,

Thank you for your interest. I'm looking forward to check your implementation and maybe I could get some inspiration for the Android app's network library. 😃

jllcunha commented 7 years ago

Hi, Quick question that was puzzling me... We connect and bind to the airconditioner... and we can query it's status... If the status on the airconditioner changes (e.g. using the IR remote control) does the airconditioner publish the status change to the bound client (our code)? Or do we need to periodically query the status of the airconditioner? Thanks, John

tomikaa87 commented 7 years ago

Hi,

In the original Gree Smart application and in my implementations the AC units are periodically polled because there is no signaling from the units.

jllcunha commented 7 years ago

Thanks for the info

jllcunha commented 6 years ago

Hi Robert, Many thanks for your description of the Wind settings above. But.. on my device remote control I only have 4 settings: Low, Medium, Hight and Auto. My values are the same as yours but 'Auto' has { opt: [ 'WdSpd', 'Quiet', 'Tur', 'NoiseSet' ], p: [ 0, 0, 0, 0 ], t: 'cmd' }

Hope this helps :)

oroce commented 6 years ago

@jllcunha thanks

fun fact: on the remote control i have the mentioned 4 options but in the app i have all of them.

jllcunha commented 6 years ago

Interesting :) For the Up Down Swing, I just ran some tests... Mine supports values ; 0 Seems to do nothing 10 Full Range 11 Full Range 1 Full range 2 Point up 3 Mid Up 4 Mid 5 Mid Down 6 Down

I'm guessing this depends on Model BTW: Mine is a Lomo (GWH12QC-K3DNB2G/I)

jllcunha commented 6 years ago

The Java application is pretty much done for now. I'll clean up the code and add more funtionality over time but for now I'm focussing on implementing an OpenHab binding based on this code. https://github.com/jllcunha/GreeTest

jllcunha commented 6 years ago

Just released the addon for OpenHab2 based on the work started here :) https://github.com/jllcunha/openhab-greeair-binding

jllcunha commented 6 years ago

Some info on the Presets:

List presets: We send: {"count":1,"index":0,"t":"queryT"} Unit Responds (there are no presets): {"t":"listT","total":0,"index":0,"list":[]}

Set a preset (preset1) to turn on the airconditioner Repeat Mon, Tue 19.00 We send: {"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[1]}],"enable":0,"hr":19,"id":0,"min":0,"name":"53636865643120","sec":0,"t":"setT","tz":1,"week":[0,1,1,0,0,0,0]} Unit Responds: {"t":"resT","r":200}

Now when we list presets: We send : {"count":1,"index":0,"t":"queryT"} Unit Responds: {"t":"listT","total":1,"index":0,"list":[{"id":0,"name":"53636865643120","enable":0,"hr":19,"min":0,"sec":0,"week":[0,1,1,0,0,0,0],"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[1]}]}]}

Now we set another preset (preset2) to turn on the airconditioner Repeat Wed, Thur 20.00 We send: {"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[0]}],"enable":0,"hr":20,"id":1,"min":0,"name":"53636865643220","sec":0,"t":"setT","tz":1,"week":[0,0,0,1,1,0,0]} Unit Responds: {"t":"resT","r":200}

Now we can query for the presets: Query for Preset1: We send : {"count":1,"index":0,"t":"queryT"} Unit Reponds: {"t":"listT","total":2,"index":0,"list":[{"id":0,"name":"53636865643120","enable":0,"hr":19,"min":0,"sec":0,"week":[0,1,1,0,0,0,0],"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[1]}]}]} Query for Preset2: We send : {"count":1,"index":1,"t":"queryT"} Unit Reponds: {"t":"listT","total":2,"index":1,"list":[{"id":1,"name":"53636865643220","enable":0,"hr":20,"min":0,"sec":0,"week":[0,0,0,1,1,0,0],"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[0]}]}]}

We can disable Preset1: We send : {"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[1]}],"enable":1,"hr":19,"id":0,"min":0,"name":"53636865643120","sec":0,"t":"updateT","tz":1,"week":[0,1,1,0,0,0,0]} Unit responds: {"t":"resT","r":200}

And we can enable Preset1 again We send ; {"cmd":[{"mac":["f4911e04c3b3"],"opt":["Pow"],"p":[1]}],"enable":0,"hr":19,"id":0,"min":0,"name":"53636865643120","sec":0,"t":"updateT","tz":1,"week":[0,1,1,0,0,0,0]} Unit Responds: {"t":"resT","r":200}

Finally we can delete Preset2 We send : {"id":1,"t":"deleteT"} Unit Responds : {"t":"resT","r":200}

Note that whenever we query for a preset, the response always contains "total":2 which tells us how many presets are stored in the unit. Important to note that "enable":0 enables the preset and "enable":1 disables the preset.

jllcunha commented 6 years ago

Great job on the Android app :) The code is much cleaner and organized than mine :)

tomikaa87 commented 6 years ago

Thank you but there is still room for improvements. The scheduling API is not implemented, you cannot rename the device and I want to add persistence to avoid binding on every start.

arthurkrupa commented 6 years ago

Hi, just wanted to say thank you for all the groundwork!

If anyone's interested, I've implemented an MQTT bridge in NodeJS based on your spec (it can also be used as a Hass.io addon).

sm4rk0 commented 6 years ago

Hi guys! Another Gree AC owner here (Viola model). I've found you by chance when discovering what openHAB could do with stuff in my home. You've done great job in opening this proprietary protocol and liberating us from Gree Smart Home Android app with its crazy permissions and privacy intrusions. I've intercepted the app's data with Fiddler and found out that you can also use web app for almost the same functions you are talking about here. According to your GitHub profiles, you are all from Europe, so this link should work for you, too. I don't know if we should keep a low profile just in case someone from Gree discovers us and changes the protocol?

tomikaa87 commented 6 years ago

Hi!

Thanks for the info about the web app, I'll check it out.

About the low profile thing I don't think they will re-write the firmware for all the devices they make and even if they do, I think firmware updates are done manually on these devices. In the latest version of the android app I saw they somewhat tried to hide the encryption layer in a native library, but after some fiddling with a disassembler one could find the encryption key and the algorithm, which makes this "security-by-obscurity" thing pretty useless.

In addition my question is why do they want to hide the protocol from the potential developers? Philips Hue has an open and documented API and as a result there are many hue-compatible apps in the app stores.

oroce commented 6 years ago

@sm4rk0 thanks for the information, first when I wanted to reverse engineer my AC I looked at their web app but you have to register an account to be able to access that, I did not do that on purpose. With the registration, you can access your device over the internet, you don't need to be on the same network. That last thing - to be honest - I want that my device is opening a tunnel to a server (which is probably located in China).

sm4rk0 commented 6 years ago

Maybe they are trying to hide the protocol so users are limited to using their privacy-intruding app. Just try running the Gree Smart Home with XPrivacy to see what I'm talking about.

tomikaa87 commented 6 years ago

@sm4rk0 IMHO privacy is not the only problem. The "official" app is bloated, buggy, inconvinient and drains the battery in the backgrund if I don't kill it. I'd also like a widget on my home screen which controls the AC units instead of always opening the app and waiting for it to connect to my units.

@oroce fun fact, the AC always communicates with a remote server even if you don't register them on the website. It sends heartbeat packets and waits for the server to reply to them. If you try to block them on the firewall, after a while the WiFi module freezes and you have to restart the unit.

duculete commented 6 years ago

Hello,

Thanks for your hard work in reverse engineering the gree controller protocol. Any chance to create a Homebridge plugin to integrate this AC with Apple HomeKit?

oroce commented 6 years ago

@duculete asked this question in my repo as well, here's my answer: https://github.com/oroce/node-gree-smart/issues/4

tomikaa87 commented 6 years ago

@duculete I'll look into it as my time allows.

Edit: I began to see how it works and it shouldn't be a hard thing to implement. Maybe on this weekend I can come up with a working version. If you have any other questions about the plugin, please open a new ticket as I'm gonna close this.

tomikaa87 commented 6 years ago

@duculete just FYI, the Homebridge plugin is in progress, I plan to release an initial version of it in a few days.

duculete commented 6 years ago

Thanks. I started also to create a homebridge version, I have something functional but not finished.

gurglespuge commented 6 years ago

Great Work! @tomikaa87 Thanks! I just tried this on a new unit.

Have some updated info on setting temp using Fahrenheit for the ahem ... certain countries.

Set using Fahrenheit Two things I found were despite TemUn being set , the set temp is still in Celsius. Use the TemRec bit to distinguish between the two Fahrenheit temps

pack: {
"opt": ["TemUn", "SetTem","TemRec"],
"p": [1, 27,0],
"t": "cmd"
}

TempRec TemSet Mapping for setting Fahrenheit

Units 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Fahrenheit 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86.
Celsius 20.0 20.5 21.1 21.6 22.2 22.7 23.3 23.8 24.4 25.0 25.5 26.1 26.6 27.2 27.7 28.3 28.8 29.4 30.0
TemSet 20 21 21 22 22 23 23 24 24 25 26 26 27 27 28 28 29 29 30 30
TemRec 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1

Equations TemSet = round((desired_temp_f-32.)5.0/9.0) TemRec = (int) ((((desired_temp_f-32.)5.0/9.0) - TemSet) > 0)

tomikaa87 commented 6 years ago

@gurglespuge thanks for the info, i've added it to the protocol documentation. 👍

MooonWalker commented 6 years ago

Tomi, thankyou for your great work!! In Hungary i purchased a AC named NORD which is produced by Gree and it is fully compatible with Gree app. So i hope i can write my own app for that too which would not possible without your great effort!

Thank you!

antonmies commented 6 years ago

Hello! I have just installed Gree GWH09QB-K6DNB8 and am using the Openhab2 binding that was made by jllcunha. The unit I have has 8C heating function that is activated by remote (Temp+Clock simultaneously) or with Gree+ App. John's binding doesn't support that and seems that the function isn't listed here either.

Does anyone here have the 8C heating function so that it could be added to different bindings eliminating the need to use the Gree app?

tomikaa87 commented 6 years ago

Hello! I have just installed Gree GWH09QB-K6DNB8 and am using the Openhab2 binding that was made by jllcunha. The unit I have has 8C heating function that is activated by remote (Temp+Clock simultaneously) or with Gree+ App. John's binding doesn't support that and seems that the function isn't listed here either.

Does anyone here have the 8C heating function so that it could be added to different bindings eliminating the need to use the Gree app?

Hi,

I'll look into in today and add the necessary protocol instructions to the documentation.

Edit: probably it's the StHt flag in the command and status pack.

sm4rk0 commented 6 years ago

Just checked with an android packet capturing application and can confirm that "opt":"StHt","p":"1.0" is used to turn on and "opt":"StHt","p":"0.0" is used to turn off the 8°C heating mode.

antonmies commented 6 years ago

Great! Thank you guys!