galletn / iaqualink

Home Assistant Iaqualink Vacuums Robots
8 stars 1 forks source link

Experimenting with an unsupported model, Polaris 9650iq #20

Open VynDesign opened 1 month ago

VynDesign commented 1 month ago

I figured I'd give it a try, what the heck. The attributes shown are accurately returning my account information, so the authentication is working, but I'm getting the "Device does not belong to user" status reported:

Screenshot 2024-06-27 170212

I'm willing to do any legwork you would like for me to assist with getting this model supported. If you have a basic postman collection I can use to start investigating my specific model, please share it.

galletn commented 1 month ago

Hi there!

the good news is, it's not the first time we get this error back, mostly it was because multiple devices exist on the account, and for example some of the equipment returns null for owner id, when you then request further data it returns this error.

Now let's hope it's something like that, and not that you need yet another API, then we will need to use a proxy to trace what api's are called.

attached the postman collection, login, then get devices, and please post that reply here so that I can have a first look at what happens.

New Collection Test.postman_collection.json

VynDesign commented 1 month ago

I figured out which values from the 'login' response were required for subsequent calls. It was a little confusing which token was needed by the device /shadow, /features, and /site endpoints as the names varied and didn't exactly match what was in the login response - turns out it was the userPoolOAuth.IdToken value. I modified the postman collection to use collectionVariables to store the values necessary, and then the subsequent calls reference the collectionVariables:

iAquaLink Robot API template.postman_collection.json

You just need to input the username and password for your specific account, and the rest get populated when you hit 'login' and then 'devices':

Screenshot 2024-06-28 101433

I can get the list of devices (I only have the one):

Screenshot 2024-06-28 103326

Unfortunately, when I attempt to get the /shadow, /features, or /site, I get the "Device does not belong to user" response (in various formats):

Screenshot 2024-06-28 103656

Screenshot 2024-06-28 103214

Screenshot 2024-06-28 103956

galletn commented 1 month ago

I'm afraid this will not be a quick fix. I'm investigating on changing the code towards socket instead of the http calls. I'll keep you posted once I'm getting there. Maybe they don't require the same inputs in order to get your device info. For sure these http calls have very different behaviour depending on the device.

You could install MITM proxy and check what calls are done.

Don't know what your experience is in that area...

And thanks for the adjustments to the postman collection!

galletn commented 1 month ago

Good news is I found some time to check out the websocket thing, seems to be fairly easy.

Can you try and run following Python code: (replace with your credentials and device ID


import asyncio
import json
import datetime
import requests
import websocket
from websockets.sync.client import connect

def run():
        attributes = {}
        headers = {"Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "*/*" }
        url = "https://prod.zodiac-io.com/users/v1/login"
        data = {"apikey": "EOOEMOW4YR6QNB07", "email": "$mail$", "password": "$Pass$"}
        data = json.dumps(data)
        response = requests.post(url, headers = headers, data = data)
        print(response)

        if response.status_code == 200:
            data = response.json()
            first_name = data["first_name"]
            last_name = data["last_name"]
            authentication_token = data["authentication_token"]
            id =  data["id"]
            id_token = data["userPoolOAuth"]["IdToken"]

        print(id_token)

        message = { "action": "subscribe", "namespace": "authorization", "payload": { "userId": id }, "service": "Authorization", "target": "$Device Serial Number$", "version": 1 }
        y = json.dumps(message)

        with connect("wss://prod-socket.zodiac-io.com/devices", additional_headers={"Authorization": id_token}) as websocket:
            websocket.send(y)
            message = websocket.recv()

        print(message)

run()
VynDesign commented 1 month ago

It gets the JWT just fine, but then hangs until it closes the connection:

  File "c:\Users\vynsa\Dev\python\iAquaLink\main.py", line 41, in <module>
    run()
  File "c:\Users\vynsa\Dev\python\iAquaLink\main.py", line 37, in run
    message = websocket.recv()
              ^^^^^^^^^^^^^^^^
  File "C:\Users\vynsa\AppData\Local\Programs\Python\Python311\Lib\site-packages\websockets\sync\connection.py", line 201, in recv
    raise self.protocol.close_exc from self.recv_events_exc
websockets.exceptions.ConnectionClosedOK: received 1001 (going away) Going away; then sent 1001 (going away) Going away

I also tried this in postman, no response is received:

Screenshot 2024-06-28 152115
VynDesign commented 1 month ago

As for mitmproxy I have it installed, but don't really get how to use it just yet. I can see traffic from my laptop, but not other devices on the network from what I can tell. I was also using wireshark, but haven't seen any traffic to/from my vacuum's IP address. If you have any pointers, I'm all ears.

falinka commented 1 month ago

It gets the JWT just fine, but then hangs until it closes the connection:

  File "c:\Users\vynsa\Dev\python\iAquaLink\main.py", line 41, in <module>
    run()
  File "c:\Users\vynsa\Dev\python\iAquaLink\main.py", line 37, in run
    message = websocket.recv()
              ^^^^^^^^^^^^^^^^
  File "C:\Users\vynsa\AppData\Local\Programs\Python\Python311\Lib\site-packages\websockets\sync\connection.py", line 201, in recv
    raise self.protocol.close_exc from self.recv_events_exc
websockets.exceptions.ConnectionClosedOK: received 1001 (going away) Going away; then sent 1001 (going away) Going away

I also tried this in postman, no response is received:

Screenshot 2024-06-28 152115

Hi VynDesign, I think i had the similar issue, timing out on the same place forever. Can you try to manually put the serial number of your device in the script, instead of having it as variable ("target": "$Device Serial Number$" replace with "target": "Q9Zxxxxx")?

VynDesign commented 1 month ago

Yeah, I had already done that. And, unfortunately, now I won't be able to test for a while, as my robot is out of commission. One of the wheel motors went bad, so I'm waiting on a new motor block :(

galletn commented 1 month ago

too bad, ping me once you have it back, or we can check with what was still of last values... its not that important that it is online. if you are willing send me over your credentials (after you changed your pass first) then I can have a look. You can send them to nicolas.gallet@skynet.be

falinka commented 1 month ago

Is the robot out of game, or just you cannot start the cleaning mode? I believe plenty of valuable data can be gathered via MITM, in order to get modes, set modes :) Anyway, good luck with replacement, hope you don't for a long time.

VynDesign commented 1 month ago

The motor is replaced, but I'm getting Err10 on the control unit now 😒. I have a few other pieces that need replacing, which is probably causing slipping gears at the wheels. We're gearing up for our 4th of July party, so won't be able to do much until the weekend at this point.

RogueDruid commented 1 month ago

The motor is replaced, but I'm getting Err10 on the control unit now 😒. I have a few other pieces that need replacing, which is probably causing slipping gears at the wheels. We're gearing up for our 4th of July party, so won't be able to do much until the weekend at this point.

err 10 is communication error. Most likely due to a cable getting pulled out of place where it connects to the control board. If you open up the connector there are screws to tighten the terminals.

galletn commented 2 weeks ago

hi @VynDesign the good news is that I found what is wrong for you, its the same is #4 you have an i2d_robot, and that model uses other endpoints/api's. The owner of the other thread has shared me his credentials and will put the robot in the pool next week, so I should be able to debug what needs to be done to get i2d_robot model supported too! Hope it will all be done by the time you have yours back!

galletn commented 1 week ago

@VynDesign https://github.com/galletn/iaqualink/tree/galletn-patch-4 contains the required code for your robot, can you test it?