Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First implementation of vacuum platform #111

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open

Conversation

rospogrigio
Copy link
Owner

Introduced vacuum platform.

@RobyDomo
Copy link

RobyDomo commented Oct 22, 2020

@rospogrigio thank you very much for your helps and your implementation. I'm really new about HA so maybe i done some errors. I'm going to explain you what i done:
I create 4 new files copying your code ( init.py , const.py , vacuum.py and en.json) so i overwritten old files inside the folder localtuya and translations, then in configuration.yaml i written this code:

localtuya:
  - host: MY_Device_IP
    device_id: MY_DEVICE_ID
    friendly_name: Robottino501
    protocol_version: "3.3"
      - platform: vacuum
        friendly_name: robot
        id: 1

And also inside the new init.py i put my info (Host IP, Device ID and Local Key)


"""The LocalTuya integration integration.
Sample YAML config with all supported entity types (default values
are pre-filled for optional fields):
localtuya:
  - host: 192.168.1.x
    device_id: xxxxx
    local_key: xxxxx
    friendly_name: Tuya Device

But rebooting HA it restarted in safe mode cause some error...
what i wrong?

@postlund
Copy link
Collaborator

You should not edit any of the python files, just your configuration.yaml. Looks like you are missing entities: just below protocol_version:.

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 22, 2020

And moreover @RobyDomo , the code of this PR is not yet operational because I still need your DPs dump.
In order to retrieve it, please refer to the Wiki page: https://github.com/rospogrigio/localtuya/wiki/HOWTO-get-a-DPs-dump .
Thank you

@RobyDomo
Copy link

@postlund Thank you!!! I got it..
@rospogrigio i tried to get my DPS dump but there are somethings wrong....

I launched following command

/home/homeassistant/.homeassistant/custom_components/tuyadebug $ python test.py ID IP LK

this is the result,

Traceback (most recent call last):
  File "test.py", line 12, in <module>
    import localtuya
  File "/home/homeassistant/.homeassistant/custom_components/tuyadebug/localtuya/__init__.py", line 41, in <module>
    from . import pytuya
  File "/home/homeassistant/.homeassistant/custom_components/tuyadebug/localtuya/pytuya/__init__.py", line 312
    raise Exception(f"Unexpected payload={payload}")
                                                  ^
SyntaxError: invalid syntax

Sorry!!!! :-(

@rospogrigio
Copy link
Owner Author

Sorry, I was not clear enough. You have uncompressed it in the localtuya directory... no, just uncompress it in another directory, out of the homeassistant environment (your home, for example). Decompress everything and launch the script and it should work.

@RobyDomo
Copy link

@rospogrigio i didn't uncompress in localtuya folder.
I uncompressed it inside /home/homeassistant/.homeassistant/custom_components/tuyadebug and run the command python test.py ID IP LK from terminal inside this folder.
Anyway i just uncompressed in home folder, but had back the same error:

/home/tuyadebug $ python test.py XXX XXX XXX

Traceback (most recent call last):
  File "test.py", line 12, in <module>
    import localtuya
  File "/home/tuyadebug/localtuya/__init__.py", line 41, in <module>
    from . import pytuya
  File "/home/tuyadebug/localtuya/pytuya/__init__.py", line 312
    raise Exception(f"Unexpected payload={payload}")
                                                  ^
SyntaxError: invalid syntax

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 22, 2020

@RobyDomo The script is executable, please launch it directly. As an alternative, launch it with python3 ("python" actually uses python2 and it fails).

@RobyDomo
Copy link

RobyDomo commented Oct 22, 2020

@rospogrigio i already tried to run directly as esecutable but it didn't work, and it didn't work also launching

/home/tuyadebug $ python3 test.py XX XX XX
This is the result:
In the last row seems is missing a module called Crypto...

Traceback (most recent call last):
File "/home/tuyadebug/test.py", line 12, in
import localtuya
File "/home/tuyadebug/localtuya/init.py", line 40, in
from Crypto.Cipher import AES
ModuleNotFoundError: No module named 'Crypto'

@RobyDomo
Copy link

I also tried to install pycryptodome, but same results:

pip install pycryptodome
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pycryptodome
Downloading https://files.pythonhosted.org/packages/4c/2b/eddbfc56076fae8deccca274a5c70a9eb1e0b334da0a33f894a420d0fe93/pycryptodome-3.9.8.tar.gz (15.6MB)
100% |████████████████████████████████| 15.6MB 20kB/s
Building wheels for collected packages: pycryptodome
Running setup.py bdist_wheel for pycryptodome ... done
Stored in directory: /home/pi/.cache/pip/wheels/d8/a7/26/540fd905ea8099b16e107c515600c4178a056822ef42737b53
Successfully built pycryptodome
Installing collected packages: pycryptodome
Successfully installed pycryptodome-3.9.8
pi@RP:/home/tuyadebug $ python3 test.py XXX XXX XXX
Traceback (most recent call last):
File "/home/tuyadebug/test.py", line 12, in
import localtuya
File "/home/tuyadebug/localtuya/init.py", line 40, in
from Crypto.Cipher import AES
ModuleNotFoundError: No module named 'Crypto'

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 22, 2020

You are using an old version of tuyadebug.tgz, the one currently on master uses cryptography instead of Crypto. Don't know how you are downloading such an old version... please use this URL and retry: https://github.com/rospogrigio/localtuya/raw/master/tuyadebug.tgz
Its MD5 should be a7cde283771d7079d93944dda2209bb9 , to be clear (get it with md5sum).

@RobyDomo
Copy link

I can't believe, and i'm so sorry to bore you so much, but it don't work....

~/Downloads $ md5sum tuyadebug.tgz 
a7cde283771d7079d93944dda2209bb9  tuyadebug.tgz
pi@RB:~/Downloads $ cd tuyadebug/
pi@RB:~/Downloads/tuyadebug $ python3 test.py 1234 192.X.X.X 5678
Traceback (most recent call last):
  File "/home/pi/Downloads/tuyadebug/test.py", line 12, in <module>
    import localtuya
  File "/home/pi/Downloads/tuyadebug/localtuya/__init__.py", line 40, in <module>
    from Crypto.Cipher import AES
ModuleNotFoundError: No module named 'Crypto'

:-(

@rospogrigio
Copy link
Owner Author

Ooops, now I see... can you try pip3 install Crypto ?

@RobyDomo
Copy link

No way!!! :-(

Installed Crypto, same result...

~/Downloads/tuyadebug $ python3 test.py XXX XXX XXX
Traceback (most recent call last):
File "/home/pi/Downloads/tuyadebug/test.py", line 12, in
import localtuya
File "/home/pi/Downloads/tuyadebug/localtuya/init.py", line 40, in
from Crypto.Cipher import AES
ModuleNotFoundError: No module named 'Crypto'

@rospogrigio
Copy link
Owner Author

OK, I uploaded a new tuyadebug.tgz without Crypto. Give it a try.
The other possibility would be to use PR #79 even if it is still being debugged...
Ah, by the way: should we succeed in getting a DPs dump, you should then try all the possible commands using the Tuya app or any manual command, and post how the DPs dump changes.
Thank you

@RobyDomo
Copy link

:-( now is changed the module... Itt can't find module 'cryptography'

:~/Downloads/tuyadebug $ python3 test.py bla bla bla
Traceback (most recent call last):
File "/home/pi/Downloads/tuyadebug/test.py", line 12, in
import localtuya
File "/home/pi/Downloads/tuyadebug/localtuya/init.py", line 41, in
from cryptography.hazmat.backends import default_backend
ModuleNotFoundError: No module named 'cryptography'

@rospogrigio
Copy link
Owner Author

Well, then you should pip3 install --upgrade cryptography ...
Have you tried using PR #79, as an alternative?

@RobyDomo
Copy link

by the way i installed cryptograpy (pip install cryptography) and somethings is changed...

~/Downloads/tuyadebug $ python3 test.py bla bla bla
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21)
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device bla bla, protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"bla","devId":"bla"}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:Detecting list of available DPS of device bla [bla], protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"bla","devId":"bla"}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:Detecting list of available DPS of device bla [bla], protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"bla","devId":"bla"}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:TIMEOUT: No response from device bla [bla] after 2 attempts.

Now i can't start robot cause my wife will kill me... :-) I canmake some try tomorrow morning if this result is what you aspected..
Let me know. And thank you very much for your helps!!! :-)

i didn't try PR #79

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 22, 2020

OK now the script is working.
It is refusing connections though, so you should kill all the Tuya apps and/or put your phone in airplane mode and retry, because probably it only accepts one connection at a time, and we still don't have the desired DPs dump.
Let me know...
Edit: you also should remove it from HA configuration right now, or stop HA...

@RobyDomo
Copy link

My phones are switched off, HA stopped:

~/Downloads/tuyadebug $ sudo systemctl stop home-assistant@homeassistant

~/Downloads/tuyadebug $ python3 test.py n
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21)
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device , protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":" ","devId":" "}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:Detecting list of available DPS of device [ ], protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":" ","devId":" "}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:Detecting list of available DPS of device [ ], protocol 3.3.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":" ","devId":" "}'
WARNING:localtuya.pytuya:Failed to get status: [Errno 111] Connection refused
INFO:localtuya:TIMEOUT: No response from device [ ] after 2 attempts.

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 22, 2020

Mmm it is still refusing connections... maybe a different protocol? Try to add 3.1 at the end and see if it goes.
You could also try to reboot the vacuum in case....

@RobyDomo
Copy link

i don't know if i understood...
i added 3.1 at the command
python3 test.py bla bla bla 3.1, with same results.

Now i can't do nothing. tomorrow i will try tho reboot the vacuum and i let you know.
Thank you very much.
Good night.

@RobyDomo
Copy link

RobyDomo commented Oct 23, 2020

HABEMUS PAPAM!!!!! :-)

So, these are the DPS Dump in different state:

Vacuum IN THE DOCK (IN CHARGE)

~/Downloads/tuyadebug $ python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX 3.1
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21) 
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device BLABLA [1.2.3.4], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"BLABLA","devId":"BLABLA"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xbe\x95\xff\xb9I\xae%\xd3\x17\x92\x8e\x17\xba\xc7\\\x0bjX\xc8\xab=\x8a\x19\x00/\x93\xe1m\xb0\x07iK\xc6\x1e\xf26>ftA\xdc]X\x1b\x83\xe1\x1dV\xabQB\xe5\x89,\xbe\n\x0b\xcd\xb6\xfa\x99\xb3\xfeZC\xbc\x05\xcage\xed\xac\x88t\x94\xc7\n\x1dy\xf7\x01\xc1\x85$\xca^\xf2\xc4[3>_\xba\xa3l\x9d\xfd\xbcA\x9fOf\r^k+Vf^\x9a\x92B\xdc\xdc\xb2v\xd7\x97\xa0\x9b+\x1c\xb2\xccKk\xf8;[\xa4u\xcf\x18Q\xfb\xac\x82P4\x0e\xbb\xf5\xa3q'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":true,"2":false,"3":"standby","4":"foward","5":"5","6":100,"13":false,"16":1,"17":0,"18":0,"101":"nar","102":25,"103":237,"104":0}}'
AVAILABLE DPS ARE [{'1': True, '2': False, '3': 'standby', '4': 'foward', '5': '5', '6': 100, '13': False, '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 25, '103': 237, '104': 0}]
INFO:localtuya:COMPLETE response from device BLABLA [1.2.3.4].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device BLABLA at 1.2.3.4 key XXXXXXXXXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [True] 
    DPS [2] VALUE [False] 
    DPS [3] VALUE [standby] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [5] 
    DPS [6] VALUE [100] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [25] 
    DPS [103] VALUE [237] 
    DPS [104] VALUE [0] 

Vacuum In STOPPED MODE ( OUT THE DOCK) Stand-By


~/Downloads/tuyadebug $ python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX 3.1
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21) 
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device BLABLA [1.2.3.4], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"BLABLA","devId":"BLABLA"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xbe\x95\xff\xb9I\xae%\xd3\x17\x92\x8e\x17\xba\xc7\\\x0b\x94\xab\xb6&\x92\x99\x8b\xf6\xc9\xa0\xe0\xf6\xd1H\xc8\xafJ\x15\x83.f0\x16\x93>1~\xe5\x88\x07\x8em\xa4\xbf\x95\x84\xcet1\xf1\xe4\xae.s\xc8w\xbb\x1f\xa7\x08a\xc8[5\xa7;\x1d\xc3\xc6>N\xcb\xefQ\x99JbJU\x93\xa9BV\xcb\xa1\xbc\r\xb6\xfe\x7f\x17\xa2\x7f\xd8\xa1]|8\xf8yl\x8bk\x03\xa2\xc8\xd5\xe4\x9d\x1b>%\x966\x1d\xed\x0f\xd7\r|\xe0\x9e.\x08\xb0\xdc\xf5\xedv\xccE\x0e\x85O\rN\x18\x8f'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":true,"2":true,"3":"smart","4":"foward","5":"1","6":99,"13":false,"16":1,"17":0,"18":0,"101":"nar","102":21,"103":179,"104":0}}'
AVAILABLE DPS ARE [{'1': True, '2': True, '3': 'smart', '4': 'foward', '5': '1', '6': 99, '13': False, '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 21, '103': 179, '104': 0}]
INFO:localtuya:COMPLETE response from device BLABLA [1.2.3.4].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device BLABLA at 1.2.3.4 key XXXXXXXXXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [smart] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [1] 
    DPS [6] VALUE [99] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [21] 
    DPS [103] VALUE [179] 
    DPS [104] VALUE [0] 

Vacuum STARTED


:~/Downloads/tuyadebug $ python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX 3.1
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21) 
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device BLABLA [1.2.3.4], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"BLABLA","devId":"BLABLA"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xbe\x95\xff\xb9I\xae%\xd3\x17\x92\x8e\x17\xba\xc7\\\x0b\x94\xab\xb6&\x92\x99\x8b\xf6\xc9\xa0\xe0\xf6\xd1H\xc8\xafJ\x15\x83.f0\x16\x93>1~\xe5\x88\x07\x8em\xa4\xbf\x95\x84\xcet1\xf1\xe4\xae.s\xc8w\xbb\x1f\xa7\x08a\xc8[5\xa7;\x1d\xc3\xc6>N\xcb\xefQ\x99JbJU\x93\xa9BV\xcb\xa1\xbc\r\xb6\xfe\x7f\x17\xa2\x7f\xd8\xa1]|8\xf8yl\x8bk\x03\xa2\xc8\xd5\xe4\x9d\x1b>%\x966\x1d\xed\x0f\xd7\r|\xe0\x9e.\x08\xb0\xdc\xf5\xedv\xccE\x0e\x85O\rN\x18\x8f'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":true,"2":true,"3":"smart","4":"foward","5":"1","6":99,"13":false,"16":1,"17":0,"18":0,"101":"nar","102":21,"103":179,"104":0}}'
AVAILABLE DPS ARE [{'1': True, '2': True, '3': 'smart', '4': 'foward', '5': '1', '6': 99, '13': False, '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 21, '103': 179, '104': 0}]
INFO:localtuya:COMPLETE response from device BLABLA [1.2.3.4].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device BLABLA at 1.2.3.4 key XXXXXXXXXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [smart] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [1] 
    DPS [6] VALUE [99] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [21] 
    DPS [103] VALUE [179] 
    DPS [104] VALUE [0] 

Vacuum started with program turn back at home

~/Downloads/tuyadebug $ python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX 3.1
INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21) 
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device BLABLA[ 1.2.3.4], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"BLABLA","devId":"BLABLA"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xbe\x95\xff\xb9I\xae%\xd3\x17\x92\x8e\x17\xba\xc7\\\x0b\xc7\x14\x01\xed\x189\x1d\xc4Ab\x96g\x8f\x92\xf2U]\xcdQ6\x84\xa8\xa9@\xf99\x91\xe7;<\x87\x05\xaaa\xd4O\xa6\\\x9a|\x19\xb3\xc5\xf8\xf0-t|\x0c\x1b\x1c\x14Um\x1b\xbf\xa2L\xa2\x1fGQ\xd3}\xf7\xe2B\x920\xf2\x85\x9bu\xc0\x04\xdc\xd5\xd5\x11\xc7\xc4C<\x10\xfch\n\xbc\xb4\xd26\xff\xeb\xad\t\xbc\x11\xff+L\xb2\xee?L\x82\x0e\xb8\xf6IRD\xc9\x95@\xef_\x00\x16\xa3\x17\xc8\x00M\xa3\xdd\xbf\xbfo'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":true,"2":true,"3":"chargego","4":"foward","5":"4","6":98,"13":false,"16":1,"17":0,"18":0,"101":"nar","102":23,"103":68,"104":0}}'
AVAILABLE DPS ARE [{'1': True, '2': True, '3': 'chargego', '4': 'foward', '5': '4', '6': 98, '13': False, '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 23, '103': 68, '104': 0}]
INFO:localtuya:COMPLETE response from device BLABLA[ 1.2.3.4].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device BLABLAat  1.2.3.4 key XXXXXXXXXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [chargego] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [4] 
    DPS [6] VALUE [98] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [23] 
    DPS [103] VALUE [68] 
    DPS [104] VALUE [0] 

Thank you!!!

@RobyDomo
Copy link

@rospogrigio sorry, i think i made my try with protocol 3.1, because my last try yesterday was

python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX 3.1

Now i just re-runned the command withot 3.1 at the end, ( python3 test.py BLABLA 1.2.3.4 XXXXXXXXXX ) and protocol changed in protocol 3.3.

:Detecting list of available DPS of device XX [XX], protocol 3.3.

I don't know if this info is important, and if you need that i try again all states with different command (without 3.1 at the end).
Let me know, and thank you.

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 23, 2020

Good, you can ignore the 3.1/3.3 thing, we have the DPs. Now it's time to try to understand what each of the DPs refers to, also with the help of what you see in the Tuya app.
Now, I think that DPs 2 refers to the status of the vacuum (cleaning or not), and 3 to the operation (standby/smart/chargego), and also 5 might play a role (5/1/4). DP 6 definitely seems to be the battery status. What I don't like (and also looks very strange) is that I see absolutely no difference in the DPs between the Stopped and the Started modes... are you really sure of those dumps?
Edit: you also probably should be able to select different cleaning modes (light/hard/turbo... something like this), and we also would need to see how this reflects in the DPs.
Once we have these things sorted out, give me some days to implement the code.
Bye

@RobyDomo
Copy link

RobyDomo commented Oct 23, 2020

Vacuum IN THE DOCK (IN CHARGE)


    DPS [1] VALUE [True] 
    DPS [2] VALUE [False] 
    DPS [3] VALUE [standby] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [5] 
    DPS [6] VALUE [100] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [27] 
    DPS [103] VALUE [293] 
    DPS [104] VALUE [0] 

STOPPED OUT THE DOCK (Stand-BY)

    DPS [1] VALUE [True] 
    DPS [2] VALUE [False] 
    DPS [3] VALUE [standby] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [0] 
    DPS [6] VALUE [100] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [27] 
    DPS [103] VALUE [176] 
    DPS [104] VALUE [0] 

STARTED with SMART program and with LOW air flow

    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [smart] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [1] 
    DPS [6] VALUE [99] 
    DPS [13] VALUE [False] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [low] 
    DPS [102] VALUE [28] 
    DPS [103] VALUE [180] 
    DPS [104] VALUE [0] 

STARTED with "WALL FOLLOWING" program and with MEDIUM air flow


    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [wall_follow] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [2] 
    DPS [6] VALUE [94] 
    DPS [13] VALUE [False] 
    DPS [15] VALUE [20201023104700200200021] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [26] 
    DPS [103] VALUE [177] 
    DPS [104] VALUE [0] 

** STARTED with "SPIRAL" program and with HIGH air flow **


    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [spiral] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [3] 
    DPS [6] VALUE [91] 
    DPS [13] VALUE [False] 
    DPS [15] VALUE [20201023104700200200021] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [high] 
    DPS [102] VALUE [27] 
    DPS [103] VALUE [206] 
    DPS [104] VALUE [0] 

** STARTED with "RANDOM" program and with LOW air flow **


    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [random] 
    DPS [4] VALUE [foward] 
    DPS [5] VALUE [6] 
    DPS [6] VALUE [90] 
    DPS [13] VALUE [False] 
    DPS [15] VALUE [20201023104700200200021] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [low] 
    DPS [102] VALUE [28] 
    DPS [103] VALUE [202] 
    DPS [104] VALUE [0] 

** STARTED with "MANUAL" program - In this program i can direct Vacuum from smartphone or remote control **


    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [smart] 
    DPS [4] VALUE [stop] 
    DPS [5] VALUE [1] 
    DPS [6] VALUE [89] 
    DPS [13] VALUE [False] 
    DPS [15] VALUE [20201023104700200200021] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [nar] 
    DPS [102] VALUE [29] 
    DPS [103] VALUE [180] 
    DPS [104] VALUE [0] 

** Started with program "BACK HOME" - Come back to dock - **


    DPS [1] VALUE [True] 
    DPS [2] VALUE [True] 
    DPS [3] VALUE [chargego] 
    DPS [4] VALUE [stop] 
    DPS [5] VALUE [4] 
    DPS [6] VALUE [89] 
    DPS [13] VALUE [False] 
    DPS [15] VALUE [20201023104700200200021] 
    DPS [16] VALUE [1] 
    DPS [17] VALUE [0] 
    DPS [18] VALUE [0] 
    DPS [101] VALUE [high] 
    DPS [102] VALUE [30] 
    DPS [103] VALUE [149] 
    DPS [104] VALUE [0] 

@rospogrigio
Copy link
Owner Author

rospogrigio commented Oct 23, 2020

OK OK OK @RobyDomo please don't flood the conversation like this.
First of all, we don't need all the communication, just the last part of the output is important (the list).
Then, it's not needed to test all the combinations, but we just need to associate the commands to the DPs. So, as far as I can imagine, I'd say:

DPS [1] VALUE [True]    # Unknown, it's always true
DPS [2] VALUE [True]    # True only if out of the dock
DPS [3] VALUE [chargego]   # operation mode: [chargego/standby/smart/random/spiral/wall_follow]
DPS [4] VALUE [stop]    # direction of movement, in manual mode [stop/foward]
DPS [5] VALUE [4]         # I think this is associated to the operation mode [0=standby; 1=smart; 2=wall_follow; 3=spiral; 4=chargego; 5=standby (docked); 6=random]
DPS [6] VALUE [89]       # still battery, I believe
DPS [13] VALUE [False] # Unknown
DPS [15] VALUE [20201023104700200200021]  # I think it's a datetime field
DPS [16] VALUE [1] 
DPS [17] VALUE [0] 
DPS [18] VALUE [0] 
DPS [101] VALUE [high]   # vacuum intensity [low/nar/high]
DPS [102] VALUE [30] 
DPS [103] VALUE [149]    
DPS [104] VALUE [0] 

This is a start. Please edit your post and reduce it to a little less cases because it's really huge.
Thank you

@RobyDomo
Copy link

@rospogrigio SORRY!!!! Edited post with essential info... Thank you very much!!!

@rospogrigio
Copy link
Owner Author

rospogrigio commented Nov 5, 2020

I don't know which is the really difference between pause and stop. I supppose that stop cancel the setted program and pause is just a stand-by (pause) of the program. For me anyway is ok. i never used Stop Button. :-)

As we saw from DPS 5, your device has only 7 states available:
0=standby; 1=smart; 2=wall_follow; 3=spiral; 4=chargego; 5=standby (docked); 6=random
Now, 1-2-3-6 are actually cleaning modes. Then we have 4 (going to the dock), 0 (standby, but out of the dock) and 5 (docked standby). Now, there is no way to distinguish a "stopped" state from a "paused" state, so we can implement it as we like. I made the "stop" command make it go to the dock but we can make it have the same behavior as "pause"... how does Tuya app work? Does it have both these commands? And how do the DPs change when you use them?

If you have time and want to make the implementation perfect, you could show the status (red arrow), show the active program (blue circle) and show the selected speed (yellow circle)
Also in the Vaccum card, you could show the real status:

It should already work correctly. If it is not showing the current status/program/fan speed, then we have to debug what is going on. Please confirm that none of these is working, and I'll add some debug instructions to understand why.

A the end, you could implement the cleaning map, where the vacuum has already cleaned, something like that
and all history about cleaning

This is impossible, unless we understand where are this info located within the DPs... but I believe this info are shared with the app in some other way.

@RobyDomo
Copy link

RobyDomo commented Nov 6, 2020

As we saw from DPS 5, your device has only 7 states available:
0=standby; 1=smart; 2=wall_follow; 3=spiral; 4=chargego; 5=standby (docked); 6=random
Now, 1-2-3-6 are actually cleaning modes. Then we have 4 (going to the dock), 0 (standby, but out of the dock) and 5 (docked standby). Now, there is no way to distinguish a "stopped" state from a "paused" state, so we can implement it as we like. I made the "stop" command make it go to the dock but we can make it have the same behavior as "pause"... how does Tuya app work? Does it have both these commands? And how do the DPs change when you use them?

Tuya App works that when i press stop the vacuum stop to clean and cancel the program, but i don't care. For me is OK in this way. These are a debug:

STOP


INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21)
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device XXXXX [XXXXX], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"XXXX","devId":"XXXX"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xfd\xa2\xe7o5\xf1\xb4\x95\xaf\xa22\xaa\x1d{\xc1\xed\xd4\x19\x93\x94\x7f\x01\x93\xc7{\x1a\x0fq\xceK\x15\x19\xcf\xc0\xb1\xa4\xf2\x0c\xa8\xdd\xb9m\x89\x9d\xba\x8d*\xe80\xa7\xb7\xb4\x06]\x8b\x7fq\xb9K\xebl2\xf2j\x9e&\xd0\x8f\x9a\xf4\x89\xaayl\xc5\xbb\xb4\xc5aY\xa24\xbcD\x05\xfa>;\x97,\x99:\xe2\xcf\xcbP\xd6\xe8w\xbf\x01u\x070\xfd\xe0\xde\xb2\x83]\xd3\x0b\x1f4+\xb1 r\x948\xf4HjS~B\xde\xee\x11U\\\xca\xb3\xb9\x04S\x07+\x9b\x1d\xdeP\xd3\x11%"WMS\x1f\xd8\xd8\xefq8\xc5\x8er\xea\xae\xe9\xcb6]\xa1\\\xa2\xac7&\x00\xb5\x7f\xec\x05\xde'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":false,"2":false,"3":"standby","4":"stop","5":"0","6":96,"13":false,"15":"20201102083605804000024","16":1,"17":0,"18":0,"101":"nar","102":35,"103":312,"104":0}}'
AVAILABLE DPS ARE [{'1': False, '2': False, '3': 'standby', '4': 'stop', '5': '0', '6': 96, '13': False, '15': '20201102083605804000024', '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 35, '103': 312, '104': 0}]
INFO:localtuya:COMPLETE response from device XXXX [XXXX].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device XXXXX at XXX key XXXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [False]
    DPS [2] VALUE [False]
    DPS [3] VALUE [standby]
    DPS [4] VALUE [stop]
    DPS [5] VALUE [0]
    DPS [6] VALUE [96]
    DPS [13] VALUE [False]
    DPS [15] VALUE [20201102083605804000024]
    DPS [16] VALUE [1]
    DPS [17] VALUE [0]
    DPS [18] VALUE [0]
    DPS [101] VALUE [nar]
    DPS [102] VALUE [35]
    DPS [103] VALUE [312]
    DPS [104] VALUE [0]

And this is in Pause State:

INFO:localtuya:localtuya version 1.0.0
INFO:localtuya:Python 3.9.0 (default, Oct 16 2020, 19:28:21)
[GCC 8.3.0] on linux
INFO:localtuya:Using pytuya version '8.1.0'
INFO:localtuya:Detecting list of available DPS of device XXX [XXX], protocol 3.1.
DEBUG:localtuya.pytuya:Sending command status (device type: type_0a)
DEBUG:localtuya.pytuya:paylod=b'{"gwId":"XX","devId":"XXX"}'
DEBUG:localtuya.pytuya:DATA RECEIVED!
DEBUG:localtuya.pytuya:decode payload=b'\xbe\x95\xff\xb9I\xae%\xd3\x17\x92\x8e\x17\xba\xc7\\\x0bjX\xc8\xab=\x8a\x19\x00/\x93\xe1m\xb0\x07iK\x13\x93:\xc4\xc1\x8d\xf3\x03\xde\x85kJ\xe1\xdcN\xce\x1d\x91\xf2\x12\xc2\t\x12\xc8\x17\xe8Ln\xdfx\xce \xdb\x16\xe6\x15\x9e\xea\x18\x98\x8c\x0c\xd21\x12\xc9\xa8A\xfe\xb0\x15p\x06\x85C\x17eS\xd0\x92\x08\xa9\xccOTR3\xed\xd1n\xcf)\xb5\x00W\x14\xf6G9S\x99JbJU\x93\xa9BV\xcb\xa1\xbc\r\xb6\xfe\x7f\x17\xa2\x7f\xd8\xa1]|8\xf8yl\x8bk\x03\xa2\xc8\xc5\x0f\xc1\x82\x9d\x86\xf7\x9b\xe7\xf4G\x03\x97\x95\x17\x02\xb2\x8c\x021\xe0\x18g\x88/f\xe1\x89>|\x87x'
DEBUG:localtuya.pytuya:decrypted result='{"dps":{"1":true,"2":false,"3":"standby","4":"stop","5":"0","6":95,"13":false,"15":"20201102083605804000024","16":1,"17":0,"18":0,"101":"nar","102":34,"103":86,"104":0}}'
AVAILABLE DPS ARE [{'1': True, '2': False, '3': 'standby', '4': 'stop', '5': '0', '6': 95, '13': False, '15': '20201102083605804000024', '16': 1, '17': 0, '18': 0, '101': 'nar', '102': 34, '103': 86, '104': 0}]
INFO:localtuya:COMPLETE response from device XXX [XXX].

**** deviceInfo returned OK ****

TuyaDebug (Tuya DPs dump) [1.0.0]

Device XXX at XXX key XXX protocol 3.1 dev_type type_0a:
    DPS [1] VALUE [True]
    DPS [2] VALUE [False]
    DPS [3] VALUE [standby]
    DPS [4] VALUE [stop]
    DPS [5] VALUE [0]
    DPS [6] VALUE [95]
    DPS [13] VALUE [False]
    DPS [15] VALUE [20201102083605804000024]
    DPS [16] VALUE [1]
    DPS [17] VALUE [0]
    DPS [18] VALUE [0]
    DPS [101] VALUE [nar]
    DPS [102] VALUE [34]
    DPS [103] VALUE [86]
    DPS [104] VALUE [0]

I can't see differnece.
The behavior in STOP STATE is that the vacuum is Switched off and if i want to start it i have to press again Stop Button (START)
Just to explain better in the app there is Button to Switch On and Switch Off (STOP)

Screenshot_20201106-151742

But for me, what you have done is OK.

It should already work correctly. If it is not showing the current status/program/fan speed, then we have to debug what is going on. Please confirm that none of these is working, and I'll add some debug instructions to understand why.

For me doesn't work:

vacuum

Thank you again for all your time!!! :-)

@postlund
Copy link
Collaborator

Are we in a state so I should review this, @rospogrigio?

@rospogrigio
Copy link
Owner Author

Well actually I am still pondering whether supporting fully RobyDomo's device, making Stop and Pause command behave differently (Stop switches off the vacuum). You can give it a look so I can correct the issues you might find, but expect more commits to come.
Rather than this, can you give a look at #162 ?
Thank you

@rospogrigio
Copy link
Owner Author

@postlund , a question about hacs/default#662 : the only check that fails is about the fact that this repo is a fork: is there any way to fix this, detaching from mileperhour's repo? I'm wondering whether our PR is not being reviewed because they see a "fail" mark beside it...

@postlund
Copy link
Collaborator

@rospogrigio I don't think I have any opinion when it comes how that works. From an overview perspective I guess I would expect pause to just "pause" what is currently happening, play resume a "pause" (or start a new round of docked) and stop would abort everything and make the robot go back to base.

Do we really need to support everything? It would probably be better to do MVP and extend functionality in additional PRs, just so we don't get stuck. It would also help us get feedback from more users as the functionality would actually ship in the next release. Agree?

I've been thinking about the failed check too, but since the docs say that it's ok that it fails I assumed it was ok. Let me try to take a bullet...

@higuita
Copy link

higuita commented Dec 13, 2020

Hi

I was searching around how to replace tuya cloud in my Ikohs netbot LS23 and this plus what was already build in valetudo (tuya fake services injected inside xioami vacuums, that also use tuya) could be used to improve this support by checking that they did for any missing feature
Specially for the map, Valetudo already have a external service that picks the map data from MQTT and generates the map, injecting the map back to the MQTT

@FeikoJoosten
Copy link

FeikoJoosten commented Dec 23, 2020

@postlund @rospogrigio is there a status update on this? I've just received a new robot vacuum and I'd love to make use of this!

Edit: For now I'll be used this, but based on the fact that both are using the Tuya platform I'm pretty sure I should be able to switch over in the future.

@remb0
Copy link

remb0 commented Jan 2, 2021

hello @rospogrigio what Can I do to add my vacuum by flow? Do I have to replace some files to test it?
the flow detects my devices and I have the correct keys but cannot choose for vacuum. Can you please tell me the things I have to do?

and thanks for all your hard work!!

@ConorIA
Copy link

ConorIA commented Mar 10, 2021

Hi, just dropping in with a quick note. I had to add _LOGGER before the **kwargs on line 64 of _vacuum.py`, otherwise the entity failed to init.

@unfilet
Copy link

unfilet commented Mar 24, 2021

@rospogrigio @postlund Do you plan to continue working on this area?

@postlund
Copy link
Collaborator

@unfilet I would love to see this merged, I don't have time nor any tuya compatible vacuum to test with though. Best would be if someone took over the PR, perhaps started fresh to clean up the history a bit and also got hold on some users to test it. I can do general code review. Having code owners/primary maintainers per platform would be ideal IMHO.

@ConorIA
Copy link

ConorIA commented Mar 24, 2021

I can't commit to taking over the PR (no time!), but I have a Lefant M501B and have it working on this branch of the custom component. Happy to help test if this is going to go forward!

@unfilet
Copy link

unfilet commented Mar 25, 2021

I tried to merge the master's branch but my knowledge of python is not enough to do it correct. I have a “liectroux c30b” for test.
I made test for my vacuum:

DPS [1] VALUE [True]
DPS [11] VALUE [0]
DPS [14] VALUE [100] - battery power %
DPS [25] VALUE [True] - voice_switch {true,false}
DPS [26] VALUE [foward] - direction_control {"range":["forward","backward","turn_left","turn_right","stop"]}
DPS [27] VALUE [smart] - mode {"range":["standby","smart","wall_follow","spiral","single","chargego"]}
DPS [28] VALUE [cleanning] - current state ["charging", "docking", "cleanning", "pause", ...]
DPS [30] VALUE [normal] - suction {"range":["high","normal","low"]}
DPS [31] VALUE [True] - maybe seek {true,false}
DPS [32] VALUE [0]
DPS [33] VALUE [0]
DPS [34] VALUE [00000000153]

@unfilet
Copy link

unfilet commented Mar 29, 2021

And my config:

  • host: 192.168.88.170
    device_id: XXXXX
    local_key: XXXXX
    friendly_name: Robotic Vacuum Cleaner
    protocol_version: "3.3"
    entities:
    • platform: vacuum
      friendly_name: MyVacuum
      commands_set: "smart,standby,chargego"
      commands_dp: 27
      id: 28
      idle_status_value: "charging,chargecompleted"
      returning_status_value: "docking"
      docked_status_value: "charging"
      battery_dp: 14
      cleaning_mode_dp: 27
      cleaning_modes: "standby,smart,wall_follow,spiral,single,chargego"
      fan_speed_dp: 30
      fan_speeds: "high,normal,low"

@postlund postlund mentioned this pull request Apr 1, 2021
@rikman122
Copy link

Hi guys!

I'm currently working on this integration but I'm not sure what is the actual progress of this branch so I'm going to share what I was doing and please let me know if it can be helpful for this branch.

What I have already done:

  1. Updated the integration to work with the current released version of the master branch
  2. Updated the setup process UI with common default values for DPs and state values for tuya vacuums. Also added flexibility in some state values and new DPs for cleaning area/time
  3. Changed the way to handle vacuum speeds and modes. Speed is managed as it is in the HA vacuum integration and modes are set using the send_command service provided by the integration. An example os this:

image

  1. Updated the way the state of the vacuum is determined
  2. Added cleaning time and cleaning area to the attributes list

What I'm currently working on:

  1. Custom card for Tuya vacuums to be able to change/display cleaning mode without having to mix vacuum speeds and modes on the same combo box

So let me know if you want this to be integrated in a new branch or PR as I'm not sure what is the actual status of this component...

@rikman122
Copy link

Hi!

I already have a functional custom card based on this: Xiaomi Vacuum Card . Currently looks like this:

image

I'm not a frontend developer so I'm having trouble with the dropdown to select mode/fan speed. It's currently working but doesn't look good:

image

Could be better to show the dropdown just under mode/fan speed and add some kind of arrow icon like the native HA dropdowns.

If someone can help with this pleas let me know to share you the code!

@timota
Copy link

timota commented Jun 10, 2021

@rikman122 Do you have working code/branch of integration, so we can test it at least

@rikman122
Copy link

@timota No, I'm currently working locally waiting for @rospogrigio and @postlund to let me know the progress on this PR. I'm not sure if this is out of date nor I should create a new branch

@ConorIA
Copy link

ConorIA commented Jun 10, 2021

@timota No, I'm currently working locally waiting for @rospogrigio and @postlund to let me know the progress on this PR. I'm not sure if this is out of date nor I should create a new branch

Maybe @postlund 's reply to a different contributor is helpful: #425 (comment)

@rikman122
Copy link

Hi!

I opened a PR against master branch with the progress so next updates will be commented there

For now custom card is almost done!!!!

image

@SamJongenelen
Copy link

Thanks for your work so far. I'm currently using cloud based access in HA but will try this with my S5Max once it gets to master (I'm currently using climate LocalTuya PR work)

@timota
Copy link

timota commented Jun 14, 2021

Thanks for your work so far. I'm currently using cloud based access in HA but will try this with my S5Max once it gets to master (I'm currently using climate LocalTuya PR work)

does cloud based integration supports Vacuum ?

@SamJongenelen
Copy link

I'm not completely following, but I'm using a custom component for roborock

@VictoriousCupid
Copy link

Is this still ongoing or am I missing something?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet