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

[Feature Request] Wyze Vacuum #107

Closed
Lukejb14 opened this issue Jan 14, 2021 · 32 comments
Closed

[Feature Request] Wyze Vacuum #107

Lukejb14 opened this issue Jan 14, 2021 · 32 comments
Assignees
Labels
Feature Request New feature or request

Comments

@Lukejb14
Copy link

Is your feature request related to a problem? Please describe.

No

Describe the solution you'd like

Wyze Vacuum support for Vacuum integration in Home Assistant

Describe alternatives you've considered

Xiaomi Mi robot vacuum 2

Additional context

Wyze Vacuum is virtually the same as Xiaomi Mi robot vacuum 2

@LucasPMagno
Copy link

LucasPMagno commented Jan 16, 2021

I received my Wyze Vacuum recently and intercepted the API calls from the app. It seems like it uses two APIs, api.wyzecam.com and wyze-venus-service.wyzecam.com. As far as I can tell, you need to send two API calls whenever starting, pausing, or stopping cleaning. The one sent to api.wyzecam.com updates the app, the one to wyze-venus-service.wyzecam.com sends the command to the robot. If you send it only to the robot the app gets glitched.

I am thinking of implementing this myself, but after looking at the source code this might be a bit too advanced for me. Plus I have never coded anything for Home Assistant. I will fork the repository and see if I can figure something out later though.

I attached a file with what I have collected from the API.
event.txt

@tggman
Copy link

tggman commented Jan 16, 2021

What tool/how did you intercept the API calls from the app?

@LucasPMagno
Copy link

I used mitmproxy to intercept the requests. I had to also install the certificate as a system certificate because apps on android don't use user certificates, so I rooted BlueStacks. For redirecting requests to the proxy, the simplest way I found was to use ProxyCap.

@shauntarves
Copy link

@LucasPMagno excellent sleuthing, but getting this to work will not be a simple task. I happened to be in the middle of doing the same kind of reverse engineering after getting my robot vacuum.

The Signature2 field that is used in the request headers is dynamically generated via the native app, but after tracing the whole call chain down in their android app, I found that it's not simple Java-compiled code that generates that string (which I'd be able to at least re-write in python), but rather a call to a native C shared object library built for the native (mobile device) architecture [technical details: com/wyze/olive/util/WpkSecurity.java loads the libwyze_olive-lib.so library and executes the getSignature call.]

I've tried reconstituting the source code from that library with the retdec tool that is available online, and that produces readable C code. Unfortunately, I don't know C, but maybe one of the guys on here does. I'll attach the de-compiled C file here.

Without being able to replicate the algorithm used to generate that Signature2 field, we're out of luck.

libwyze_olive-lib.so.c.gz

@SecKatie
Copy link
Owner

SecKatie commented Jan 26, 2021

Crap, well, it looks like it uses a completely different control mechanism as much of the other devices. The annoying thing about Wyze is that they don't implement their own services and APIs to control the devices. They add the SDK for the device into their app and install its service on the other end.

This means that there is a brand new API and endpoint for each new device, which complicates integrating it with this. It is probably impossible for me to do without having the vacuum in front of me.

@shauntarves I can help with the python and home assistant development angle, but as for the reverse engineering, it is basically impossible to do it from my end because I am flying blind. A lot of my process for developing this was trial and error with Burp Suite and the app.

Sorry guys, until there is a python package to talk to the vacuums API or a pull request, I can do nothing.

@SecKatie SecKatie added Feature Request New feature or request help wanted Extra attention is needed labels Feb 7, 2021
@shauntarves
Copy link

@JoshuaMulliken followed up with email about helping on this.

@trevorbenyack
Copy link

trevorbenyack commented Feb 18, 2021

Just a heads up to the commenters here who seem to have a better grip on the software mechanics of all this, you can root the Wyze vac pretty easily. I was hoping to install Valetudo on it to get away from the Wyze app and use it in home sssistant, but it doesn't look like it used miio (at least that I could tell), so as of right now i don't think it's possible. -- I was actually in the process of trying to sniff the traffic with mitmproxy but ran out of time getting it working a couple days back and haven't gotten to it since. Based on what you've seen, is it possible to just not use the app and use direct calls to the vacuum? What about map data? Can that be intercepted?

-- didn't see you attached the log! Looks like the map data is there

@LucasPMagno
Copy link

I saw your Reddit post just now. Hopefully, the event.txt file I sent earlier gives you the information you need to get the robot running locally. On the map data, I have no idea how it is encoded. I tried decoding it in a couple of ways but all I got back was garbled data. Not sure if the roborock uses the same encoding and Valetudo has already figured out how to decode it.

@trevorbenyack
Copy link

I just posted a link to your log in Valetudo's telegram chat so we'll see if anyone bites.

@shauntarves
Copy link

shauntarves commented Feb 18, 2021 via email

@SecKatie
Copy link
Owner

@shauntarves thanks again for picking up the mantle to work on this!

@bubbaiOS
Copy link

Thank you @shauntarves! Can't wait to not have to be my my phone to arm this thing.

@trevorbenyack
Copy link

Will this be working in conjunction with the app or side stepping it?

@shauntarves
Copy link

shauntarves commented Feb 23, 2021

@trevorbenyack @bubbaiOS @LucasPMagno if you're interested in playing with the vacuum and/or smart plug features, please email me shaun <at> tarves <dot> net and I will get you access to the private repo

@brianhanifin
Copy link
Contributor

brianhanifin commented Mar 22, 2021

According to the Home Assistant logs, the alpha version may not be getting the user id? v0.5.14 adds my outdoor plugs.
wyze user : None

P.S. @shauntarves I took a look at the smartbridge repo you shared with me last month and realized I had no idea what to do with it! 😅 Last week I tinkered with the Rest API documented in the Wiki using Insominia. I managed to setup Insomnia Environment variables to store and process my unique values. So I'm starting to get my head around some of the API. Maybe there is more troubleshooting I can help with.

Insomnia Export (secrets scrubbed): https://gist.github.com/brianhanifin/e24cd0f4e2965b04b2f1c628e13c29d3

2021-03-22 08:53:18 INFO (MainThread) [custom_components.wyzeapi.smartbridge.factory] Creating 'wyze' provider
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Returning a class for the wyze provider
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Importing provider: wyze
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Importing providers from wyze
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Registering the provider: <class 'custom_components.wyzeapi.smartbridge.providers.wyze.provider.WyzeProvider'>
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] List of available providers: defaultdict(<class 'dict'>, {'wyze': {'class': <class 'custom_components.wyzeapi.smartbridge.providers.wyze.provider.WyzeProvider'>}})
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Returning provider class for wyze
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.factory] Created 'wyze' provider
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key access_token, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key refresh_token, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key user_id, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_app_id, with supplied default value: 9319141212m2ik
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_app_name, with supplied default value: wyze
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_app_version, with supplied default value: 2.16.55
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_phone_id, with supplied default value: b5b53c59-9817-41dd-ae6a-947dcf232dff
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_phone_system_type, with supplied default value: 2
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_username, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_password, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_access_token, with supplied default value: None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_is_secure, with supplied default value: True
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.base.provider] Getting config key wyze_validate_certs, with supplied default value: True
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.providers.wyze.client] wyze user : None
2021-03-22 08:53:18 DEBUG (MainThread) [custom_components.wyzeapi.smartbridge.providers.wyze.client] wyze service : 9319141212m2ik
2021-03-22 08:53:18 ERROR (MainThread) [homeassistant.setup] Error during setup of component wyzeapi
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 213, in _async_setup_component
    result = await task
  File "/config/custom_components/wyzeapi/__init__.py", line 67, in async_setup
    login_response = ProviderFactory().create_provider(ProviderList.WYZE, client_cfg).wyze_client.login(
  File "/config/custom_components/wyzeapi/smartbridge/providers/wyze/client.py", line 71, in login
    return self.auth_client.login(username, password)
  File "/config/custom_components/wyzeapi/smartbridge/providers/wyze/client.py", line 635, in login
    return self.do_post(
  File "/config/custom_components/wyzeapi/smartbridge/providers/wyze/client.py", line 329, in do_post
    log.trace('unmodified prepared request')
AttributeError: 'HassLogger' object has no attribute 'trace'

@esmoyer
Copy link

esmoyer commented Apr 14, 2021

Curious if anything was changing with this? I just realized since the most recent HA update, it appears something broke. I'll see what I can find.

@SecKatie SecKatie removed the help wanted Extra attention is needed label May 5, 2021
@pabo
Copy link

pabo commented May 6, 2021

@shauntarves Did you ever solve the signature2 field? I've been trying to reverse engineer it for the thermostat and so far have not been successful.

@shauntarves
Copy link

shauntarves commented May 6, 2021 via email

@pabo
Copy link

pabo commented May 6, 2021

Awesome, I'm checking it out now and you have really good support for all the devices. Do you have plans to integrate into home assistant already or is that work left for someone else to do?

@shauntarves
Copy link

shauntarves commented May 6, 2021 via email

@christensonautohome
Copy link

curious if this is a future request that will be added. Seems like it's being worked on but haven't seen an update for some time and I sent an email per the request above to @shauntarves for access to the vacuum repo for help testing, but haven't heard back

@bubbaiOS
Copy link

curious if this is a future request that will be added. Seems like it's being worked on but haven't seen an update for some time and I sent an email per the request above to @shauntarves for access to the vacuum repo for help testing, but haven't heard back

Shaun said he'd leave the integration up to others. His code is here https://github.com/shauntarves/wyze-sdk

@christensonautohome
Copy link

Shaun said he'd leave the integration up to others. His code is here https://github.com/shauntarves/wyze-sdk

Thanks, thought I read somewhere on here that we could shoot a message to him to gain access to the wyzeapi-vacuum alpha version ( v0.5.15-vacuum-alpha.9) for testing. #117 is a closed issue which references the alternate version.
@JoshuaMulliken are you working on the integration? seems like the only open issue on the vacuum but no update on the testing (if it is indeed happening).

@SecKatie
Copy link
Owner

I am not working on vacuums right now. I started but the back and forth was not working for me because I do not own the vacuum, so I abandoned it.

I would start again if I am provided with a vacuum and paid for my time, but I own Roombas, so I don't have any need or interest in working on this currently

@alanjames1987
Copy link

Using the great Wyze-SDK that @shauntarves put together I threw together a really quick custom integration just for controlling the Wyze robot vacuum.

https://github.com/alanjames1987/Wyze-HA

It can be installed with HACS or manually.

Please be aware that this is the absolute basics and, at the time of posting this, it doesn't support all the features, like selective room cleaning.

I'm planning on working on this more over the next few weeks in my spare time but, in its current state, it's just 1 day of work.

If you have any suggestions please open an issue and we can talk about it more. I'm also very willing to accept any PRs to make this better.

@alanjames1987
Copy link

After creating my custom integration I found this other custom integration that also adds support for the Wyze robot vacuum using Wyze-SDK.

https://github.com/romedtino/simple-wyze-vac

@SecKatie
Copy link
Owner

SecKatie commented Sep 4, 2021

That's great! I don't have a Wyze Vac so I won't support it here but it is great that it is available to HA users elsewhere!

@IIAIronWolf
Copy link

After creating my custom integration I found this other custom integration that also adds support for the Wyze robot vacuum using Wyze-SDK.

https://github.com/romedtino/simple-wyze-vac

These are great, I just wish I didn't have to remove my account security to make them work. Wyze is the worst when it comes to listening to customers. We've been asking for developer/API access since their inception.

@shauntarves
Copy link

shauntarves commented Sep 7, 2021 via email

@alanjames1987
Copy link

I didn't see this in the docs so I didn't look for it but I reviewed the Client code and see the option for a totp key to be passed in from an authenticator app.

@shauntarves I don't think I can currently add 2FA with how your client constructor is written.

  1. Home Assistant integration will reauthenticate each time Home Assistant is restarted and the stored TOTP will be outdated so it won't be able to auth.
  2. Your client caches the access token for calls after the login happens but it's not persisted so I would have to create a new client when Home Assistant restarts.
  3. Unfortunately the __init__ method of Client calls self.login() which would be using the outdated TOTP mentioned in step 1.

If I can stop the login when creating the new client AND I can set the _token property myself before calling login() I can make the 2FA work because then the TOTP would be used only once.

Basically I need to change this:

client = Client(email=WYZE_EMAIL, password=WYZE_PASSWORD, totp=WYZE_TOTP)

to this:

client = Client(email=WYZE_EMAIL, password=WYZE_PASSWORD, totp=WYZE_TOTP, login=False)
client.set_access_token(HOME_ASSISTANT_CACHED_TOKEN)
client.login()

or even better:

client = Client()
client.email  = WYZE_EMAIL
client.password = WYZE_PASSWORD
client.totp = WYZE_TOTP
client.access_token = HOME_ASSISTANT_CACHED_TOKEN
client.login()

I'm sure you get the idea. @shauntarves do you mind if I make that change and open a PR? I will keep it backwards compatible.

@IIAIronWolf I'll create an issue in my repo to add the 2FA feature using an TOTP authenticator app but I won't be able to add SMS 2FA. The issue will be located here.

@SecKatie
Copy link
Owner

Hey everyone,

It sucks that I don’t have a Wyze Vaccum (and don’t need one cause we are a Roomba house) so I probably won’t be adding this. However, if someone puts together a group that can develop and test the feature I would be willing to work on a PR to get it merged!

@Sunoo
Copy link

Sunoo commented Oct 30, 2021

I’m happy to help test if you do. I had planned to put together a PR myself, I just haven’t had the free time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature Request New feature or request
Projects
None yet
Development

No branches or pull requests