Phype / purei9_unofficial

This project includes a client/library to connect to Electrolux and AEG cleaner robots.
https://pypi.org/project/purei9-unofficial
MIT License
27 stars 5 forks source link

Help reverse engineering the API #21

Open allan-null opened 1 year ago

allan-null commented 1 year ago

First I'd like to thank @Phype for his awesome work of reverse engineering the API, because it seems like a lot of hard work to accomplish this task.

I've been trying to use this project for a few months now, but I've been unsuccessful. Since I am getting a 404 error trying to get my purei9.2 status, I thought my i9.2 might be registered under another server than the one used on this project (I am from Brazil, and sounds reasonable different regions use different API locations), so I decided to do some digging myself. The only thing I have been able to discover is that the API domain used by my account is the api.ocp.electrolux.one. I then tried to just replace the domain used on this project by it, but no luck.

I am able to successfully decrypt HTTPS data with from Google Chrome on a rooted Android emulator with PCAPDroid, but the Electrolux app doesn't work even with PCAPDroid CA cert installed at the system level, so I'd like help with that if you may.

I don't want to make a big fuss about this issue, because it seems like there are some oddities exclusive to my region (or maybe to just my account). For example, I was talking with a developer from the Electrolux app and he said my vaccum wasn't supposed to show as white o the app, because the white image is just a development placeholder.

Thank you for your attention.

Phype commented 1 year ago

I assume you are using the newest app, right? Over the time, there has been three apps:

  1. com.electrolux.purei9 - not on google play anymore
  2. https://play.google.com/store/apps/details?id=com.electrolux.wellbeing
  3. https://play.google.com/store/apps/details?id=com.electrolux.oneapp.android.electrolux

I have only reversed the APIs of 1. and 2., 3. could be using yet another API which isn't supported. What you could do:

louisjennings commented 1 year ago

I have been able to control my i9 (original version) using the v2 API but have been unable to reverse the wellbeing API with dynamic analysis as the wellbeing app has been discontinued so decided to reverse engineer the new API (#23).

@allan-null if/once the pull request has been merged, let me know if it works. This version of the API does use api.ocp.electrolux.one so hopefully it works for you.

For my reverse engineering, I have been using mitmproxy on a rooted physical device. I have a certificate installed into the system CA and am able to intercept https traffic from the new Electrolux app with no issues. mitmproxy provide a guide on installing a certificate into the system CA on a rooted emulator so perhaps you could try that (https://docs.mitmproxy.org/stable/howto-install-system-trusted-ca-android/).

allan-null commented 1 year ago

@allan-null if/once the pull request has been merged, let me know if it works. This version of the API does use api.ocp.electrolux.one so hopefully it works for you.

It did work for me, somewhat. After fiddling a lot with the code, I managed to understand that the index deviceType doesn't exist for my device, and that is very odd. Just out of curiosity, do your device also has a micro USB connector inside the dust bin?

louisjennings commented 1 year ago

It did work for me, somewhat. After fiddling a lot with the code, I managed to understand that the index deviceType doesn't exist for my device, and that is very odd. Just out of curiosity, do your device also has a micro USB connector inside the dust bin?

It's a bit strange that the deviceType field isn't present in the response from the server. It might be interesting to check the JSON response from the server to see which fields are present.

Yes, I do have a micro USB connector inside the robot once the dust bin has been removed (I have a pure i9 as opposed to 9.2). I expect the incompatibility is related to region or a variable in the account rather than the model of robot.

allan-null commented 1 year ago

It's a bit strange that the deviceType field isn't present in the response from the server. It might be interesting to check the JSON response from the server to see which fields are present. Sure! But removing the one line that looks for the deviceType makes it work. I mean, only through "the cloud". I haven't been able to make it work locally yet.


[
{
"applianceId":"900921353101005641100106",
"applianceData":{
"applianceName":"Geoffrey",
"created":"2022-10-01T13:02:13.8254392Z",
"modelName":"PUREi9"
},
"properties":{
"desired":{
"firmwareVersion":"43.23",
"ecoMode":false,
"powerMode":3,
"tasks":{
        }
     },
     "reported":{
        "availableLanguages":[
           "deu",
           "eng",
           "fra",
           "pol",
           "spa",
           "kor",
           "zht",
           "zhs",
           "jpn",
           "ces",
           "ita",
           "rus"
        ],
        "capabilities":{
           "CustomPlay":{

           },
           "FreezeMapOnDemand":{

           },
           "InteractiveMap":{

           },
           "MultipleScheduledCleaningsPerDay":{

           },
           "PowerLevels":{

           },
           "PowerZones":{

           }
        },
        "batteryStatus":6,
        "robotStatus":10,
        "messageList":{
           "messages":[

           ]
        },
        "dustbinStatus":"connected",
        "platform":"1.01",
        "applianceName":"Geoffrey",
        "firmwareVersion":"43.23",
        "language":"eng",
        "mute":true,
        "powerMode":3,
        "tasks":{

        }
     },
     "metadata":"None"
  },
  "status":"enabled",
  "connectionState":"Connected"

} ]



>Yes, I do have a micro USB connector inside the robot once the dust bin has been removed (I have a pure i9 as opposed to 9.2). I expect the incompatibility is related to region or a variable in the account rather than the model of robot.
I see, same as mine. I thought they had sold me a development unit, hehe...
louisjennings commented 1 year ago

That looks similar to the response I get from https://api.ocp.electrolux.one/appliance/api/v2/appliances

For me, deviceType is part of the response from https://api.ocp.electrolux.one /appliance/api/v2/appliances/applianceId/info (that would be https://api.ocp.electrolux.one/appliance/api/v2/appliances/900921353101005641100106/info for you).

What's the response from the request on this line? https://github.com/louisjennings/purei9_unofficial/blob/8c542fcd5c67a69004f796ddae9929168dabdded/src/purei9_unofficial/cloudv2_electroluxone.py#L257 The code I modified had a device field to parse that response, so deviceType might be a peculiarity of my configuration.

allan-null commented 1 year ago

Alright, I messed this up. The JSON I posted is what I get from https://api.ocp.electrolux.one/appliance/api/v2/appliances. The request from https://github.com/louisjennings/purei9_unofficial/blob/8c542fcd5c67a69004f796ddae9929168dabdded/src/purei9_unofficial/cloudv2_electroluxone.py#L257 gets me an error 404. But if I make a request to https://api.ocp.electrolux.one/appliance/api/v2/appliances/900921353101005641100106 I get a similar response from what I already posted. Sorry, I already changed a lot of this code and I am not sure what is the original anymore.

louisjennings commented 1 year ago

If you're getting 404s, you might have to intercepting the HTTPS traffic again and see if you can find which URLs the official app is accessing. It would be useful to work out how and why the API differs between users.