flz / iaqualink-py

Asynchronous library for Jandy iAqualink
BSD 3-Clause "New" or "Revised" License
30 stars 20 forks source link

Support vacuums #23

Open johntdyer opened 2 years ago

johntdyer commented 2 years ago

Would he awesome to support Jandy integrated pool vacuums, at the very least I would love to stop / start and see time to completion... Is the Jandy api documented anywhere?

johntdyer commented 2 years ago

this project looks interesting https://github.com/tekkamanendless/iaqualink

flz commented 2 years ago

I don't have one of those so unless this changes, I won't be working on adding support.

Happy to review patches though!

galletn commented 1 year ago

Hi Guys,

Glad I found this! I have the code, could you please help to put it in correctly?

image

galletn commented 1 year ago

import json
import datetime
from homeassistant.helpers.entity import Entity
from datetime import timedelta
from homeassistant.util import Throttle

URL_LOGIN="https://prod.zodiac-io.com/users/v1/login"
URL_GET_DEVICES="https://r-api.iaqualink.net/devices.json"
URL_GET_DEVICE_STATUS="https://prod.zodiac-io.com/devices/v1/"

SCAN_INTERVAL = timedelta(seconds=30)

def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the sensor platform."""
    add_devices([iaqualinkRobotSensor(config)])

class iaqualinkRobotSensor(Entity):
    def __init__(self, config):
        self._name = config.get('name')
        self._username = config.get('username')
        self._password = config.get('password')
        self._api_key = config.get('api_key')

        self._headers = {"Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "*/*" }

        self._attributes = {}

        # Apply throttling to methods using configured interval
        self.update = Throttle(SCAN_INTERVAL)(self._update)

        self._update()

    @property
    def name(self):
        return self._name 

    @property
    def username(self):
        return self._username

    @property
    def frist_name(self):
        return self._first_name

    @property
    def last_name(self):
        return self._last_name

    @property
    def serial_number(self):
        return self._serial_number

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def device_state_attributes(self):
        """Return device specific state attributes."""
        return self._attributes

    @property
    def extra_state_attributes(self):
        """Return entity specific state attributes."""
        return self._attributes

    def _update(self):
        self._attributes['username'] = self._username
        url = URL_LOGIN
        data = {"apikey": self._api_key, "email": self._username, "password": self._password}
        data = json.dumps(data)
        response = requests.post(url, headers = self._headers, data = data)
        self._state = response.status_code
        if response.status_code == 200:
            data = response.json()
            self._first_name = data["first_name"]
            self._last_name = data["last_name"]
            self._attributes['first_name'] = self._first_name
            self._attributes['last_name'] = self._last_name
            self._authentication_token = data["authentication_token"]
            self._id =  data["id"]
            self._id_token = data["userPoolOAuth"]["IdToken"]

            url = URL_GET_DEVICES
            data = None
            response = requests.get(url, headers = self._headers, params = {"authentication_token":self._authentication_token,"user_id":self._id,"api_key":self._api_key})

            if response.status_code == 200:
                data = response.json()
                self._serial_number = data[0]["serial_number"] #assumption only 1 robot for now
                self._attributes['serial_number'] = self._serial_number

                url = URL_GET_DEVICE_STATUS + self._serial_number + "/shadow"
                data = None
                self._headers = {"Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "*/*", "Authorization" : self._id_token}
                response = requests.get(url, headers = self._headers)
                if response.status_code == 200:
                    data = response.json()
                    self._state = data["state"]["reported"]["aws"]["status"]
                    self._last_online = datetime_obj = datetime.datetime.fromtimestamp((data["state"]["reported"]["aws"]["timestamp"]/1000)) #Convert Epoch To Unix
                    self._attributes['last_online'] = self._last_online
                    self._temperature = data["state"]["reported"]["equipment"]["robot"]["sensors"]["sns_1"]["val"]
                    self._attributes['temperature'] = self._temperature
                    self._pressure = data["state"]["reported"]["equipment"]["robot"]["sensors"]["sns_2"]["state"]
                    self._attributes['pressure'] = self._pressure
                    self._total_hours = data["state"]["reported"]["equipment"]["robot"]["totalHours"]
                    self._attributes['total_hours'] = self._total_hours
                    self._error_state = data["state"]["reported"]["equipment"]["robot"]["errorState"]
                    self._attributes['error_state'] = self._error_state
                    self._lift_control = data["state"]["reported"]["equipment"]["robot"]["liftControl"]
                    self._attributes['lift_control'] = self._lift_control
                    self._equipment_id = data["state"]["reported"]["equipment"]["robot"]["equipmentId"]
                    self._attributes['equipment_id'] = self._equipment_id
                    self._cycle_start_time = datetime_obj = datetime.datetime.fromtimestamp(data["state"]["reported"]["equipment"]["robot"]["cycleStartTime"])
                    self._attributes['cycle_start_time'] = self._cycle_start_time
                else:
                    self._state = response.text[:250]
            else:
                self._state = response.text[:250]

Config File:

    - platform: iaqualink
      username: 
      password: 
      api_key: EOOEMOW4YR6QNB07
      name: Bobby
flz commented 1 year ago

There's some commonalities with the exo code (namely the /shadow part). I don't have the equipment which makes testing of an unpublished API impossible.

The exo code is in a separate "exo" branch and hasn't been merged since testing by the community has been limited and the API broke at some point (I think it's working again?).

johntdyer commented 1 year ago

@galletn how about we create a new integration just for the robots ? I would be happy to help

bertocea85 commented 1 year ago

hello! yes, that would be fine, I have a polaris and could help in whatever is needed.

galletn commented 1 year ago

I have a quite busy period at work, but let me see what I can do. I already have the separate one, but I did not publish it yet.

galletn commented 1 year ago

If you already want to test the basics, this should read out your robot.

add the extracted folder to your custom components folder. entry in the config File: sensor:

iaqualink.zip

bertocea85 commented 1 year ago

thanks @galletn! this part sensor:

directly in configuration.yaml?

gives the following error

Registrar: homeassistant.setup Source: setup.py:251 First Occurred 14:24:48 (1 occurrences) Last logged 14:24:48 Error in iaqualink custom integration setup: No setup or config entry setup function defined.

bertocea85 commented 1 year ago

I have already managed to make it appear as an entity within home assistant. the robot's data appears. but there is this error message. {'message': "Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header.

image

galletn commented 1 year ago

I'll try to send you my postman collection to see which of the URL's it is that gives you this error, for me it still works, so I think depending on the type of robot another URL might be needed to get some of the details. of your robot. You know how to work with postman?

bertocea85 commented 1 year ago

thank you @galletn yes, I can manage with postman. I see that the app makes POST calls passing a signature, timestamp and user_id field. The url is https://r-api.iaqualink.net/v2/devices/{serialnumber}/control.json and adds the mentioned fields.

galletn commented 1 year ago

Sorry it took some time, but please find the postman collection included. I put $ where you should change some values. Iaqualink.zip

ppastur commented 1 year ago

Hey guys I've been following along and am keen to help where I can - perhaps to test as I'm an amateur at development. I have a EX4000 iQ Robotic cleaner and although I cant seem to get the sensor working in HA, I have so far been able to (using postman) log in and get my device. For get device status, features, site etc , I can't seem to figure out what I'm supposed to use as the Authorization: $AuthKey. I assume its in the login response?? Your thoughts and guidance is appreciated.

bertocea85 commented 1 year ago

Exactly! it asks for some kind of Authkey. Using Mitm I see that it sends a GET request (https://r-api.iaqualink.net/v2/devices.json?user_id=xxxxxx&signature=xxxxxxxxxxxxxxxxxxxxxxxxxx&timestamp=1683565854) and passes three values. User_id, signature and Timestamp. These last two I think are calculated somehow?

ppastur commented 1 year ago

I just got past this stage and can successfully run get device status. So now I can run, login, get devices, get device status, get device features and get device site. I still cant get the sensor to show up in HA though :(

ppastur commented 1 year ago

@bertocea85 I used "RefreshToken" as the $AuthKey I received on login. I also changed the URL in GetDeviceFeatures to be; https://prod.zodiac-io.com/devices/v2/XXXMYSERIALNUMBERXXX/features

Where XXXMYSERIALNUMBERXXX=my robot serial number reported from the login stage. I mention this because the original postman collection indicated $deviceID$ which is an entirely different number. How did you get the sensor to show up in HA?

I added the extracted folder (iaqualink.zip) to my custom components folder. I added the following to my config.yaml: - platform: iaqualink username: !secret iaqualink_username password: !secret iaqualink_password api_key: EOOEMOW4YR6QNB07 name: Fred

What have I missed?

bertocea85 commented 1 year ago

I understand that the iaqualink folder is inside custom_components (custom_components/iaqualink/xx.py). I have added in sensors.yaml

And in configuration.yaml at the end of the file: sensor: !include sensors.yaml Once restarted, in the part of Settings, Devices and services, in Entities, you should see the name that you have put as a sensor.

ppastur commented 1 year ago

I understand that the iaqualink folder is inside custom_components (custom_components/iaqualink/xx.py). I have added in sensors.yaml

  • platform: iaqualink username: !secret iaqualink_username password: !secret iaqualink_password api_key: EOOEMOW4YR6QNB07 name: XXX

And in configuration.yaml at the end of the file: sensor: !include sensors.yaml Once restarted, in the part of Settings, Devices and services, in Entities, you should see the name that you have put as a sensor.

I see it but other than the number 500 (state) its empty. Today for some reason I get an empty response when I run GetDevices in postman

ppastur commented 1 year ago

Ok - I figured it out. I had to modify sensor.py. line 110 is trying to map

self._temperature = data["state"]["reported"]["equipment"]["robot"]["sensors"]["sns_1"]["val"] but it should be (in my case) self._temperature = data["state"]["reported"]["equipment"]["robot"]["sensors"]["sns_1"]["state"]

so now I get this image

ppastur commented 1 year ago

and here is where I got to image

I added a few more attributed such as running state and canister empty/ok

LOki61 commented 1 year ago

and here is where I got to image

I added a few more attributed such as running state and canister empty/ok

How did you get the canister and running state? thanks again all of you.

ppastur commented 1 year ago

I modified sensor.py in the section where the response from the API call is being mapped into attributes (I think) here self._headers = {"Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "*/*", ``"Authorization" : self._id_token} response = requests.get(url, headers = self._headers) if response.status_code == 200:

and added the following lines; self._canister = data["state"]["reported"]["equipment"]["robot"]["canister"] self._attributes['canister'] = self._canister self._running = data["state"]["reported"]["equipment"]["robot"]["state"] self._attributes['running'] = self._running

Then I created template sensors in the config.yaml to map 0/1 to empty/full or running/Idle

Then in the card, I created badges and animations to show when running/idle or when the canister needs emptying.

Couldnt have done it without the code from @galletn. Its a shame I don't know how to help make this an official component of the integration to help make it easier for others who might like to add this and save the many hours/days to figure it out.

The next part id like to start working on is executing commands from the card like lift or start cycle or change cycle but I think I need either a little help with figuring out how do that or need many more hours to study how to reverse engineer the ios app - I only dabble :)

https://github.com/flz/iaqualink-py/assets/91765182/950c3478-9fc8-4a1b-b9dd-6977317f75d9

LOki61 commented 1 year ago

I modified sensor.py in the section where the response from the API call is being mapped into attributes (I think) here self._headers = {"Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "*/*","Authorization" : self._id_token} `response = requests.get(url, headers = self._headers)`if response.status_code == 200:

and added the following lines; self._canister = data["state"]["reported"]["equipment"]["robot"]["canister"] self._attributes['canister'] = self._canister self._running = data["state"]["reported"]["equipment"]["robot"]["state"] self._attributes['running'] = self._running

Then I created template sensors in the config.yaml to map 0/1 to empty/full or running/Idle

Then in the card, I created badges and animations to show when running/idle or when the canister needs emptying.

Couldnt have done it without the code from @galletn. Its a shame I don't know how to help make this an official component of the integration to help make it easier for others who might like to add this and save the many hours/days to figure it out.

The next part id like to start working on is executing commands from the card like lift or start cycle or change cycle but I think I need either a little help with figuring out how do that or need many more hours to study how to reverse engineer the ios app - I only dabble :)

poolrobot.1.HB_proc.mp4

Perhaps I can investigate, I am a complete noob. Can you tell me what I should download to review the API or code? How can I look at it. Maybe can tinker and learn.

ppastur commented 1 year ago

I would start with this : https://github.com/tekkamanendless/iaqualink . The part that I think will help is this : https://github.com/tekkamanendless/iaqualink#development. Once we understand how to structure the post and manually send commands via postman then we can progress.

galletn commented 1 year ago

I'll have a look to make a separate integration out of this somewhere this week, then we can commit and do whatever we need to make it work for all of us. @ppastur indeed, that is what should be done, but need to find the time to install the proxy stuff, I already have a proxy running so I think that just wiresharking on that one might work too. Keep you posted!

ppastur commented 1 year ago

@galletn , I setup mitmproxy and managed to capture turning the robot on and off. It looks like its all websocket traffic which means Im a little out of my depth. I am however happy to work with you to provide you with the capture and also to test if that is helpful?

Here is the redacted websocket messages. Ive replaced userID, robot serial number and other serial/part numbers

SEND-->

{
    "action": "subscribe",
    "namespace": "authorization",
    "payload": {
        "userId": $USERID$
    },
    "service": "Authorization",
    "target": "$ROBOTSERIALNUMBER$",
    "version": 1
}

RECIEVE <--

{
    "namespace": "authorization",
    "payload": {
        "data": [
            {
                "accelero": [
                    -85,
                    -31,
                    1049
                ],
                "angleRotation": 183,
                "cleanerPos": 1,
                "cumulAngleRotation": 502,
                "cycleId": 1684646687,
                "floorBlockageCnt": 0,
                "gyro": [
                    1,
                    -2,
                    1
                ],
                "iPump": 2442,
                "iTract1": 99,
                "iTract2": 109,
                "lastMoveLength": 13,
                "loopCnt": 200,
                "magneto": [
                    0,
                    0,
                    0
                ],
                "movementId": 1,
                "patternId": 0,
                "pwmPump": 100,
                "pwmTract1": 80,
                "pwmTract2": 80,
                "stairsCnt": 1764,
                "tiltCnt": 32692,
                "timestamp": 1684650932,
                "totalHours": 348,
                "vEbox": 28,
                "vRobot": 28,
                "vSensor": 11,
                "wallCnt": 1660
            }
        ],
        "ota": {
            "status": "UP_TO_DATE"
        },
        "robot": {
            "metadata": {
                "desired": {
                    "equipment": {
                        "robot": {}
                    }
                },
                "reported": {
                    "aws": {
                        "session_id": {
                            "timestamp": 1684751732
                        },
                        "status": {
                            "timestamp": 1684751732
                        },
                        "timestamp": {
                            "timestamp": 1684751732
                        }
                    },
                    "dt": {
                        "timestamp": 1681926072
                    },
                    "eboxData": {
                        "completeCleanerPn": {
                            "timestamp": 1681926072
                        },
                        "completeCleanerSn": {
                            "timestamp": 1681926072
                        },
                        "controlBoxPn": {
                            "timestamp": 1681926072
                        },
                        "controlBoxSn": {
                            "timestamp": 1681926072
                        },
                        "motorBlockSn": {
                            "timestamp": 1681926072
                        },
                        "powerSupplySn": {
                            "timestamp": 1681926072
                        },
                        "sensorBlockSn": {
                            "timestamp": 1681926072
                        }
                    },
                    "equipment": {
                        "robot": {
                            "canister": {
                                "timestamp": 1684571511
                            },
                            "customCyc": {
                                "timestamp": 1681926072
                            },
                            "customIntensity": {
                                "timestamp": 1681926072
                            },
                            "cycleStartTime": {
                                "timestamp": 1684752278
                            },
                            "durations": {
                                "customTim": {
                                    "timestamp": 1681926072
                                },
                                "deepTim": {
                                    "timestamp": 1681926072
                                },
                                "firstSmartTim": {
                                    "timestamp": 1681926072
                                },
                                "quickTim": {
                                    "timestamp": 1681926072
                                },
                                "smartTim": {
                                    "timestamp": 1681926072
                                },
                                "waterTim": {
                                    "timestamp": 1681926072
                                }
                            },
                            "equipmentId": {
                                "timestamp": 1681926073
                            },
                            "errorCode": {
                                "timestamp": 1681926072
                            },
                            "errorState": {
                                "timestamp": 1681926072
                            },
                            "firstSmrtFlag": {
                                "timestamp": 1681926072
                            },
                            "liftControl": {
                                "timestamp": 1681926072
                            },
                            "logger": {
                                "timestamp": 1681926072
                            },
                            "prCyc": {
                                "timestamp": 1684752605
                            },
                            "repeat": {
                                "timestamp": 1681926072
                            },
                            "rmt_ctrl": {
                                "timestamp": 1681926072
                            },
                            "scanTimeDuration": {
                                "timestamp": 1681926072
                            },
                            "schConf0Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf0Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf0Min": {
                                "timestamp": 1681926072
                            },
                            "schConf0Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf0WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf1Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf1Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf1Min": {
                                "timestamp": 1681926072
                            },
                            "schConf1Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf1WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf2Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf2Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf2Min": {
                                "timestamp": 1681926072
                            },
                            "schConf2Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf2WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf3Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf3Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf3Min": {
                                "timestamp": 1681926072
                            },
                            "schConf3Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf3WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf4Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf4Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf4Min": {
                                "timestamp": 1681926072
                            },
                            "schConf4Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf4WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf5Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf5Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf5Min": {
                                "timestamp": 1681926072
                            },
                            "schConf5Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf5WDay": {
                                "timestamp": 1681926072
                            },
                            "schConf6Enable": {
                                "timestamp": 1681926072
                            },
                            "schConf6Hour": {
                                "timestamp": 1681926072
                            },
                            "schConf6Min": {
                                "timestamp": 1681926072
                            },
                            "schConf6Prt": {
                                "timestamp": 1681926072
                            },
                            "schConf6WDay": {
                                "timestamp": 1681926072
                            },
                            "sensors": {
                                "sns_1": {
                                    "state": {
                                        "timestamp": 1684752306
                                    },
                                    "type": {
                                        "timestamp": 1681926072
                                    }
                                },
                                "sns_2": {
                                    "state": {
                                        "timestamp": 1684752306
                                    },
                                    "type": {
                                        "timestamp": 1681926072
                                    }
                                },
                                "sns_3": {
                                    "state": {
                                        "timestamp": 1681926072
                                    },
                                    "type": {
                                        "timestamp": 1681926072
                                    }
                                }
                            },
                            "state": {
                                "timestamp": 1684752605
                            },
                            "stepper": {
                                "timestamp": 1681926072
                            },
                            "stepperAdjTime": {
                                "timestamp": 1681926072
                            },
                            "totalHours": {
                                "timestamp": 1684752280
                            },
                            "vr": {
                                "timestamp": 1681926073
                            }
                        }
                    },
                    "jobId": {
                        "timestamp": 1651189088
                    },
                    "sn": {
                        "timestamp": 1681926072
                    },
                    "vr": {
                        "timestamp": 1681926072
                    }
                }
            },
            "state": {
                "desired": {
                    "equipment": {
                        "robot": {}
                    }
                },
                "reported": {
                    "aws": {
                        "session_id": "7d0137d2-06bd-45f4-8be9-e3f503886d65",
                        "status": "connected",
                        "timestamp": 1684751732835
                    },
                    "dt": "vr",
                    "eboxData": {
                        "completeCleanerPn": "${some-part-number}",
                        "completeCleanerSn": "${some-serial-number}",
                        "controlBoxPn": "${some-part-number}",
                        "controlBoxSn": "${some-serial-number}",
                        "motorBlockSn": "${some-serial-number}",
                        "powerSupplySn": "${some-serial-number}",
                        "sensorBlockSn": ""
                    },
                    "equipment": {
                        "robot": {
                            "canister": 0,
                            "customCyc": 1,
                            "customIntensity": 0,
                            "cycleStartTime": 1684752276,
                            "durations": {
                                "customTim": 150,
                                "deepTim": 165,
                                "firstSmartTim": 150,
                                "quickTim": 75,
                                "smartTim": 111,
                                "waterTim": 45
                            },
                            "equipmentId": "JY21002990",
                            "errorCode": 0,
                            "errorState": 0,
                            "firstSmrtFlag": 0,
                            "liftControl": 0,
                            "logger": 0,
                            "prCyc": 1,
                            "repeat": 0,
                            "rmt_ctrl": 0,
                            "scanTimeDuration": 30,
                            "schConf0Enable": 0,
                            "schConf0Hour": 0,
                            "schConf0Min": 0,
                            "schConf0Prt": 1,
                            "schConf0WDay": 0,
                            "schConf1Enable": 0,
                            "schConf1Hour": 0,
                            "schConf1Min": 0,
                            "schConf1Prt": 1,
                            "schConf1WDay": 1,
                            "schConf2Enable": 0,
                            "schConf2Hour": 0,
                            "schConf2Min": 0,
                            "schConf2Prt": 1,
                            "schConf2WDay": 2,
                            "schConf3Enable": 0,
                            "schConf3Hour": 0,
                            "schConf3Min": 0,
                            "schConf3Prt": 1,
                            "schConf3WDay": 3,
                            "schConf4Enable": 0,
                            "schConf4Hour": 0,
                            "schConf4Min": 0,
                            "schConf4Prt": 1,
                            "schConf4WDay": 4,
                            "schConf5Enable": 0,
                            "schConf5Hour": 0,
                            "schConf5Min": 0,
                            "schConf5Prt": 1,
                            "schConf5WDay": 5,
                            "schConf6Enable": 0,
                            "schConf6Hour": 0,
                            "schConf6Min": 0,
                            "schConf6Prt": 1,
                            "schConf6WDay": 6,
                            "sensors": {
                                "sns_1": {
                                    "state": 0,
                                    "type": "temperature"
                                },
                                "sns_2": {
                                    "state": 0,
                                    "type": "pressure"
                                },
                                "sns_3": {
                                    "state": 0,
                                    "type": "compass"
                                }
                            },
                            "state": 0,
                            "stepper": 0,
                            "stepperAdjTime": 15,
                            "totalHours": 349,
                            "vr": "V32E47"
                        }
                    },
                    "jobId": "Job_VR_V32E47_V32C47",
                    "sn": "$ROBOTSERIALNUMBER$",
                    "vr": "V32C47"
                }
            },
            "timestamp": 1684752680,
            "version": 138294
        }
    },
    "service": "Authorization",
    "target": "$ROBOTSERIALNUMBER$"
}

SEND --> (start clean cycle on the app)

{
    "action": "setCleanerState",
    "namespace": "vr",
    "payload": {
        "clientToken": "$USERID$|Z6dmjtJcsJ79ANUfe1rYoh|cQ4zyywG4B2NSlv8PMpnZo",
        "state": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": 1
                    }
                }
            }
        }
    },
    "service": "StateController",
    "target": "$ROBOTSERIALNUMBER$",
    "version": 1
}

notice state:1

RECIEVE <-- (a bunch of these)

{
    "event": "StateReported",
    "payload": {
        "clientToken": "$USERID$|Z6dmjtJcsJ79ANUfe1rYoh|cQ4zyywG4B2NSlv8PMpnZo",
        "metadata": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": {
                            "timestamp": 1684752688
                        }
                    }
                }
            }
        },
        "state": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": 1
                    }
                }
            }
        },
        "timestamp": 1684752688,
        "version": 138295
    },
    "service": "StateStreamer",
    "target": "$ROBOTSERIALNUMBER$",
    "version": 1
}

SEND --> (stop clean cycle on the app)

{
    "action": "setCleanerState",
    "namespace": "vr",
    "payload": {
        "clientToken": "$USERID$|Z6dmjtJcsJ79ANUfe1rYoh|8RhttxQIeSlg1q1nPj0xoe",
        "state": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": 0
                    }
                }
            }
        }
    },
    "service": "StateController",
    "target": "$ROBOTSERIALNUMBER$",
    "version": 1
}

notice state: 0

RECIEVE <-- (a bunch of these)

{
    "event": "StateReported",
    "payload": {
        "clientToken": "$USERID$|Z6dmjtJcsJ79ANUfe1rYoh|8RhttxQIeSlg1q1nPj0xoe",
        "metadata": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": {
                            "timestamp": 1684752705
                        }
                    }
                }
            }
        },
        "state": {
            "desired": {
                "equipment": {
                    "robot": {
                        "state": 0
                    }
                }
            }
        },
        "timestamp": 1684752705,
        "version": 138300
    },
    "service": "StateStreamer",
    "target": "$ROBOTSERIALNUMBER$",
    "version": 1
}
galletn commented 1 year ago

I guess we can move to https://github.com/galletn/iaqualink prepping it to get into HACS now

LOki61 commented 1 year ago

I guess we can move to https://github.com/galletn/iaqualink prepping it to get into HACS now

How can I help guys?

galletn commented 1 year ago

@ppastur @LOki61 please join the converstation here:

https://github.com/galletn/iaqualink/issues/1

@ppastur can you repost your proxy logs there? also did you capture the URL's that were triggered? can you also post the changes you made to the code to make it work for you? I'll have a look to make it generic for all robots.

@LOki61 you could help by sending your changes too, I'll also try to fit these in. Then we have a nice clean start for all. If you could also try the HACS install? For me it worked but ... better double check 👍