galletn / iaqualink

Home Assistant Iaqualink Vacuums Robots
9 stars 2 forks source link

Add cycle selection #29

Closed ppastur closed 2 weeks ago

ppastur commented 1 month ago

Enhancement request Hi @galletn, you know I love your work and am very appreciative. If its not too much work. do you think it will be possible to add the ability to select the cycle type? I am happy to help with any traces, testing, videos etc Thanks in advance

galletn commented 1 month ago

hi @ppastur, I'll try to find some time to do that. I just need to look on how to do it the best for the vacuum type.

falinka commented 1 month ago

I think you can 'borrow' for example, from Roborock integration:

image

Simple drop-down menu, but then again, simple for me, as i don't know how hard is to implement things like this :)

galletn commented 1 month ago

@falinka thanks seems indeed that that is the best option.

@ppastur could you get some traces of what is send over when you switch between the modes? Then I can write the code for it.

Thanks!

ppastur commented 1 month ago

No Problems - Ill use mitmproxy and then post the sanitised logs of the following test case;

  1. ill open the app
  2. start logging
  3. change cycle
  4. start cleaning
  5. stop cleaning
  6. change cycle back
  7. stop logging

ok with that? need anything more/less/else?

falinka commented 1 month ago

@falinka thanks seems indeed that that is the best option.

@ppastur could you get some traces of what is send over when you switch between the modes? Then I can write the code for it.

Thanks!

So, for cyclonext type (CNX 30 iQ), there are only 2 options - floor only and floor and walls.

Floor only is "cycle:2" and floor and walls is "cycle:3":

message = { "action": "setCleaningMode", "namespace": "cyclonext", "payload": { "clientToken": clientToken, "state": { "desired": { "equipment": { "robot.1": { "cycle":3 } } } } }, "service": "StateController", "target": "xxxxxxxx", "version": 1 }

Let me know if you need more, you have my contact.

galletn commented 1 month ago

Thanks @falinka !

@ppastur indeed that should be enough or like @falinka his post is fine, that is the actual payload that is send over to the server. We will need it for all modes and all device types.

galletn commented 1 month ago

can someone with a cyclonext type test it? https://github.com/galletn/iaqualink/tree/galletn-patch-2

@falinka ?

image
falinka commented 1 month ago

I will let you know a bit later, I’m out at the moment.On 28. 7. 2024, at 14:21, galletn @.***> wrote: can someone with a cyclonext type test it? https://github.com/galletn/iaqualink/tree/galletn-patch-2 @falinka ?

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>

ppastur commented 1 month ago

@galletn For my EX 4000 iQ

Foor only cycle is: {"action":"setCleaningMode","version":1,"namespace":"vr","payload":{"state":{"desired":{"equipment":{"robot":{"prCyc":1}}}},"clientToken":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"},"service":"StateController","target":"YYYYYYYYYYY"}

Floor and Wall cycle is {"action":"setCleaningMode","version":1,"namespace":"vr","payload":{"state":{"desired":{"equipment":{"robot":{"prCyc":2}}}},"clientToken":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"},"service":"StateController","target":"YYYYYYYYYYY"}

Does that give you what you need?

falinka commented 1 month ago

can someone with a cyclonext type test it? https://github.com/galletn/iaqualink/tree/galletn-patch-2

@falinka ?

image

So, i'm back. No luck, nothing changes when i change the "speed". Maybe it's related to some errors i'm seing in HA since latest update, mostly time-out errors:

File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 241, in handle_call_service response = await hass.services.async_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2731, in async_call response_data = await coro ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2774, in _execute_service return await target(service_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 999, in entity_service_call single_response = await _handle_entity_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1071, in _handle_entity_call result = await task ^^^^^^^^^^ File "/config/custom_components/iaqualinkRobots/vacuum.py", line 218, in async_stop data = await asyncio.wait_for(self.setCleanerState(request), timeout=30) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/asyncio/tasks.py", line 519, in wait_for async with timeouts.timeout(timeout): File "/usr/local/lib/python3.12/asyncio/timeouts.py", line 115, in aexit raise TimeoutError from exc_val TimeoutError

galletn commented 1 month ago

@ppastur can you confirm again the modes? For my robot 1 is floor only, 2 is smart / scan, and 3 is floor and walls.

This makes it a bit hard as there seems not to be a consistant value for alle robots ... I could also just make it mode 1 2 3 ... depending on what it supports but even then ... I would need to find what modes are supported to list up the correct ones!

@falinka can you test again? Think its fixed, works for my robot. @ppastur you can test too, I put it at your values for now.

ppastur commented 1 month ago

@galletn I installed the latest version of vacuum.py (patch2) and it seems to work very well so far. Ill keep testing

falinka commented 1 month ago

@ppastur can you confirm again the modes? For my robot 1 is floor only, 2 is smart / scan, and 3 is floor and walls.

This makes it a bit hard as there seems not to be a consistant value for alle robots ... I could also just make it mode 1 2 3 ... depending on what it supports but even then ... I would need to find what modes are supported to list up the correct ones!

@falinka can you test again? Think its fixed, works for my robot. @ppastur you can test too, I put it at your values for now.

Hi, I just downloaded latest patch, but it throws strange errors when i try to change the mode:

2024-07-29 06:19:48.181 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [547593446896] Unexpected exception Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 241, in handle_call_service response = await hass.services.async_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2731, in async_call response_data = await coro ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/core.py", line 2774, in _execute_service return await target(service_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 999, in entity_service_call single_response = await _handle_entity_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1071, in _handle_entity_call result = await task ^^^^^^^^^^ File "/config/custom_components/iaqualinkRobots/vacuum.py", line 485, in async_set_fan_speed data = await asyncio.wait_for(self.setCleanerState(request), timeout=30) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/asyncio/tasks.py", line 520, in wait_for return await fut ^^^^^^^^^ File "/config/custom_components/iaqualinkRobots/vacuum.py", line 430, in setCleanerState await self.async_update() File "/config/custom_components/iaqualinkRobots/vacuum.py", line 267, in async_update self._status = data['payload']['robot']['state']['reported']['aws']['status']


KeyError: 'robot'
ppastur commented 1 month ago

@galletn I only have 2 modes. 1=Floor only. 2=walls and floor (see screenshot of app) IMG_2802FC301D53-1

ppastur commented 1 month ago

@galletn I've tested and it seems very solid - thank you. I've also put together another video if you care to display it on the title. Let me know if I missed anything that should be redacted or if you want something changed - very happy to contribute.

https://github.com/user-attachments/assets/17713681-c963-40b9-b679-921f701c571c

galletn commented 1 month ago

@falinka

are you sure it does not change the mode? I can see it changing when I open the app, it only works when the robot is online.

Next to that the error you get is because a timeout occured when fetching the status of the robot. I'm afraid that we might sometimes spam the API a lot and it says too many calls.

I added the update right after the change of mode to show faster then 30 seconds that it switched of mode.

I could try to remove that but it might make the update slower in HA in that case.

@ppastur

I'll have a look but I have 3 modes, but yours is SMART cycle and not just floors and walls, I have both smart & floors & walls separate. I will see of the SMART function of yours and mine correspond, in that case I'll rename it that way that it matches for all Robots!

falinka commented 1 month ago

@falinka

are you sure it does not change the mode? I can see it changing when I open the app, it only works when the robot is online.

Next to that the error you get is because a timeout occured when fetching the status of the robot. I'm afraid that we might sometimes spam the API a lot and it says too many calls.

I added the update right after the change of mode to show faster then 30 seconds that it switched of mode.

I could try to remove that but it might make the update slower in HA in that case.

@ppastur

I'll have a look but I have 3 modes, but yours is SMART cycle and not just floors and walls, I have both smart & floors & walls separate. I will see of the SMART function of yours and mine correspond, in that case I'll rename it that way that it matches for all Robots!

I did the same test, click something, then check the app, but nothing changed. Did few times, but no luck. At the moment, robot is in floor-only mode, running in the pool. I still have the old creds, so feel free to start/stop change mode :) Just let me know when it's done, so I can pick it up and clean it :) P.S. It seems that when you're converting epoch to datetime, it kinda puts everything into UTC, ignoring HA settings for timezone. My bad, had some wrong timezone on docker.

galletn commented 1 month ago

@falinka can you leave the Robot in the pool tonight my time being around 20.00 GMT+1 ?

falinka commented 1 month ago

@falinka can you leave the Robot in the pool tonight my time being around 20.00 GMT+1 ?

Yeap, i can. I will be out from 20 until 22.30 (CET) latest, in case you need me to check on something.

galletn commented 1 month ago

@falinka I'll update the code soon, the good news is, it was just value 1 instead of 2 😮‍💨 , so 1 and 3 in your case. You don't have the SMART mode 2, so the good thing is, it's consistent over all robots the names of the modes 👍

galletn commented 1 month ago

merged the patch towards the main branch!

only thing I still need to look at is that when you start it up first time it shows the correct fan speed directly, and most importantly ... I'm not sure yet on how to devide all the different modes ...

So we have:

  1. Floor Only
  2. SMART (Floor and Walls)
  3. Floor and Walls

So Falinka his Cyclonext has 1 & 3, ppastur with a VR 1 & 2, and I have a VR with 1,2,3 😲

I just wonder what would happen ppastur is you would also set mode to 3 🤕

ppastur commented 1 month ago

merged the patch towards the main branch!

only thing I still need to look at is that when you start it up first time it shows the correct fan speed directly, and most importantly ... I'm not sure yet on how to devide all the different modes ...

So we have:

  1. Floor Only
  2. SMART (Floor and Walls)
  3. Floor and Walls

So Falinka his Cyclonext has 1 & 3, ppastur with a VR 1 & 2, and I have a VR with 1,2,3 😲

I just wonder what would happen ppastur is you would also set mode to 3 🤕

I suspect the same thing will likely happen for me if #3 is selected as will happen for falinka if #2 is selected. Im happy to try the experiment

ppastur commented 1 month ago

Thinking about this a little more and please excuse my basic knowledge of Python but in your code you have device mapping using device type. Perhaps if you changed that to model number, you could then assign properties to each model e.g. fan speed selection so that in your code you can send commands based on model e.g.


async def async_set_fan_speed(self, fan_speed):
        """ code to send fan speed to vacuum cleaner """
        if fan_speed not in self._fan_speed_list:
            raise ValueError('Invalid fan speed')
        self._fan_speed = fan_speed

        clientToken = str ( self._id ) + "|" + self._authentication_token + "|" + self._app_client_id

        if self._device_type == "EX 4000 iQ":
            if fan_speed == "Floor only":
                _cycle_speed = "1"

            if fan_speed == "Floor and walls":
                _cycle_speed = "2"

            request = {"action":"setCleaningMode","version":1,"namespace":"vr","payload":{"state":{"desired":{"equipment":{"robot":{"prCyc":_cycle_speed}}}},"clientToken": clientToken},"service":"StateController","target": self._serial_number}

        if self._device_type == "Polaris - VRX iQ+":
            if fan_speed == "Floor only":
                _cycle_speed = "1"

            if fan_speed == "Floor and walls":
                _cycle_speed = "2"

            request = {"action":"setCleaningMode","version":1,"namespace":"vr","payload":{"state":{"desired":{"equipment":{"robot":{"prCyc":_cycle_speed}}}},"clientToken": clientToken},"service":"StateController","target": self._serial_number}

        if self._device_type == "CNX 30 iQ":
            if fan_speed == "Floor only":
                _cycle_speed = "2"

            if fan_speed == "Floor and walls":
                _cycle_speed = "3"

            request = { "action": "setCleaningMode", "namespace": "cyclonext", "payload": { "clientToken": clientToken, "state": { "desired": { "equipment": { "robot.1": { "cycle": _cycle_speed } } } } }, "service": "StateController", "target": self._serial_number, "version": 1 }

        data = await asyncio.wait_for(self.setCleanerState(request), timeout=30)
falinka commented 1 month ago

merged the patch towards the main branch!

only thing I still need to look at is that when you start it up first time it shows the correct fan speed directly, and most importantly ... I'm not sure yet on how to devide all the different modes ...

So we have:

  1. Floor Only
  2. SMART (Floor and Walls)
  3. Floor and Walls

So Falinka his Cyclonext has 1 & 3, ppastur with a VR 1 & 2, and I have a VR with 1,2,3 😲

I just wonder what would happen ppastur is you would also set mode to 3 🤕

Regarding the startup, as we cannot determine the current selection, why don't we configure it to actually set on mode 1 during startup, that way.. it will be correct :) Mode 1 is the common on all models, so far.