SecKatie / ha-wyzeapi

Home Assistant Integration for Wyze devices.
733 stars 112 forks source link

[Bug] API Access Token Error After Time #509

Closed crsiebler closed 9 months ago

crsiebler commented 1 year ago

Describe the bug Wyze integration fails after time. If I restart Home Assistant the API calls succeed and everything functions as expected. I just deleted and reloaded the integration with a new API key.

To Reproduce Steps to reproduce the behavior:

  1. Go to Wyze entity
  2. Click on Switch
  3. See error

Expected behavior Clicking the Wyze switch in Home Assistant turns on and off the device.

System configuration System: Docker HA Version: 2023.8.0 WyzeApi Version: 0.1.22

home-assistant.log

Log Details (ERROR)
This error originated from a custom integration.
Logger: homeassistant.core
Source: custom_components/wyzeapi/token_manager.py:50
Integration: Wyze Home Assistant Integration ([documentation](https://github.com/SecKatie/ha-wyzeapi#readme), [issues](https://github.com/SecKatie/ha-wyzeapi/issues))
First occurred: 10:32:37 AM (3 occurrences)
Last logged: 10:34:13 AM

Error executing service: <ServiceCall switch.turn_on (c:01H7NCX8FZP9WY0E81JRV45XW2): entity_id=['switch.coffee_machine']>
Error executing service: <ServiceCall switch.turn_off (c:01H7ND04VEYZS96EPPE2M63BWQ): entity_id=['switch.coffee_machine']>
Error executing service: <ServiceCall switch.turn_on (c:01H7ND05Z86H3CB9XV38P1JN1X): entity_id=['switch.coffee_machine']>
Traceback (most recent call last):
  File "/config/custom_components/wyzeapi/token_manager.py", line 45, in inner_function
    await func(*args, **kwargs)
  File "/config/custom_components/wyzeapi/switch.py", line 197, in async_turn_on
    await self._service.turn_on(self._device)
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/switch_service.py", line 43, in turn_on
    await self._set_property(switch, PropertyIDs.ON.value, "1")
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/base_service.py", line 359, in _set_property
    check_for_errors_standard(response_json)
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/utils.py", line 80, in check_for_errors_standard
    raise AccessTokenError
wyzeapy.exceptions.AccessTokenError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/core.py", line 1990, in _run_service_call_catch_exceptions
    await coro_or_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 2011, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 235, in handle_service
    return await service.entity_service_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 870, in entity_service_call
    response_data = await _handle_entity_call(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 942, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/config/custom_components/wyzeapi/token_manager.py", line 50, in inner_function
    raise ConfigEntryAuthFailed("Unable to login, please re-login.") from err
homeassistant.exceptions.ConfigEntryAuthFailed: Unable to login, please re-login.
Log Details (ERROR)
Logger: wyzeapy.services.update_manager
Source: /usr/local/lib/python3.11/site-packages/wyzeapy/services/update_manager.py:46
First occurred: August 11, 2023 at 1:41:43 PM (31001 occurrences)
Last logged: 10:47:02 AM

Unknown error happened during updating device info
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/update_manager.py", line 42, in update
    self.device = await self.service.update(self.device)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/switch_service.py", line 24, in update
    device_info = await self._get_property_list(switch)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/base_service.py", line 167, in _get_property_list
    check_for_errors_standard(response_json)
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/utils.py", line 80, in check_for_errors_standard
    raise AccessTokenError
wyzeapy.exceptions.AccessTokenError
manofpants commented 1 year ago

Same error here after recently installing 2023.8.2.

This error originated from a custom integration.

Logger: homeassistant.config_entries
Source: custom_components/wyzeapi/__init__.py:128
Integration: Wyze Home Assistant Integration (documentation, issues)
First occurred: 6:40:10 AM (1 occurrences)
Last logged: 6:40:10 AM

Error setting up entry for wyzeapi
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 388, in async_setup
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/wyzeapi/__init__.py", line 128, in async_setup_entry
    mac_addresses = await client.unique_device_ids
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/__init__.py", line 148, in unique_device_ids
    devices = await self._service.get_object_list()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/services/base_service.py", line 122, in get_object_list
    check_for_errors_standard(response_json)
  File "/usr/local/lib/python3.11/site-packages/wyzeapy/utils.py", line 80, in check_for_errors_standard
    raise AccessTokenError
wyzeapy.exceptions.AccessTokenError
brg468 commented 1 year ago

@SecKatie, this is just a wild guess, but do you think it could be an issue of not updating the access token soon enough? From the Wyze dev instructions:

Notes:
The access token generated is valid for 2 days only.
The refresh token generated is valid for 30 days.
Please do not repeatedly use the login endpoint (the first endpoint) to generate new access tokens as this endpoint has a rate limit protection. If you need a new access token after using the login endpoint, you can use the refresh token endpoint (the second endpoint) to get this. You'll want to use a valid refresh token generated from the login endpoint for this.

We currently have the refresh timer set to 48 hours, so in theory that would work, but this is Wyze we're talking about. Is it possible they are using 2 calendar days or something goofy and the token is expiring before we refresh it?

I personally haven't run into this issue but it seems like its been a problem for several since the switch to the access token method.

lygris commented 1 year ago

@SecKatie, this is just a wild guess, but do you think it could be an issue of not updating the access token soon enough? From the Wyze dev instructions:

Notes:
The access token generated is valid for 2 days only.
The refresh token generated is valid for 30 days.
Please do not repeatedly use the login endpoint (the first endpoint) to generate new access tokens as this endpoint has a rate limit protection. If you need a new access token after using the login endpoint, you can use the refresh token endpoint (the second endpoint) to get this. You'll want to use a valid refresh token generated from the login endpoint for this.

We currently have the refresh timer set to 48 hours, so in theory that would work, but this is Wyze we're talking about. Is it possible they are using 2 calendar days or something goofy and the token is expiring before we refresh it?

I personally haven't run into this issue but it seems like its been a problem for several since the switch to the access token method.

I think @brg468 is correct here, or at least on the right path. I've been having this issue every 3 days or so and it always seems to pop up after i install an hacs addon update and have to reboot HA. Once HA is back up I notice the integration is in a failed state and i have to go generate a new api key, input into the integration, and then reload it.

Does the refresh timer reset after an HA reboot and/or does the refresh process replace the access token stored in the integration? I could see either of these causing the issue in my case.

SecKatie commented 1 year ago

if the token is a jwt we could probably look at the expiration parameter and refresh prior to that. otherwise we could just do a refresh whenever it dies.

fennemaj commented 1 year ago

If it's valuable to know, I believe I'm seeing the same issue. I noticed that all my automations with Wyze plugs and bulbs stopped working and found that the integration was failing to load. The log was showing issues about being unable to login, please login again.

2023-08-16 15:10:36.485 ERROR (MainThread) [custom_components.wyzeapi.token_manager] TokenManager detected a login issue please re-login. 2023-08-16 15:10:36.489 ERROR (MainThread) [custom_components.wyzeapi.token_manager] TokenManager detected a login issue please re-login.

However, for me, this happened before I upgraded to the most recent version from one version back. When I updated the credentials today, from the ones I had just generated last week, then the integration loaded and started working again, which was after the update, but the issue started prior to the update.

brg468 commented 1 year ago

if the token is a jwt we could probably look at the expiration parameter and refresh prior to that. otherwise we could just do a refresh whenever it dies.

It doesn’t look like it’s a jwt, based on what little I know about these things.

It might be worth trying bumping the refresh time to say 24 hours initially and see if that fixes it. The refresh endpoint looks to have a rate limit of 300 so I don’t think we’re in any danger of hitting that.

Edit: it turns out it is a jwt, at least after it’s been refreshed once. What’s weird is the exp value is set at 24 hours. 🤦 So I don’t understand why I’m not seeing these errors.

brg468 commented 1 year ago

However, for me, this happened before I upgraded to the most recent version from one version back. When I updated the credentials today, from the ones I had just generated last week, then the integration loaded and started working again, which was after the update, but the issue started prior to the update.

Are you talking about the Wyze integration update or updating HA core?

lygris commented 1 year ago

if the token is a jwt we could probably look at the expiration parameter and refresh prior to that. otherwise we could just do a refresh whenever it dies.

Wait so is it not coded to refresh the token at all right now?

brg468 commented 1 year ago

if the token is a jwt we could probably look at the expiration parameter and refresh prior to that. otherwise we could just do a refresh whenever it dies.

Wait so is it not coded to refresh the token at all right now?

It is, every 48 hours.

fennemaj commented 1 year ago

after the update, but the issue started prior to the update.

Are you talking about the Wyze integration update or updating HA core?

It was happening to me prior to updating both the HA core and the Wyze integration. It was part of why I updated both, thinking that might resolve it.

lygris commented 1 year ago

I made some changes locally to the code yesterday and changed the refresh_time to be 24 hours to see if it would resolve the issue. i'll report back if it breaks again or if the change fixed it.

lygris commented 1 year ago

Changing the refresh_time in the code to 24 hours seems to have worked for me. rebooted to install an update today and the integration came up just fine.

Tirnion commented 1 year ago

Do you have any information on how to change refresh_time? I'm having the same issue. In const.py, REFRESH_TIME = "refresh_time", and in .storage/core.config_entries, "refresh_time": "1692597667.8xxxxx" which seems to be the timestamp of the last refresh request. Those are the only places I'm seeing to edit refresh_time, but it's very likely I'm overlooking something.

lygris commented 1 year ago

Change it in const.py and then in init.py change line 75 to "REFRESH_TIME: str[REFRESH_TIME]," and line 99 to "float(str(REFRESH_TIME)),"

EDIT: Not entirely sure i made the correct or perfect edits because in my core.config_entries is shows "86400": "1692597667.8" instead of "refresh_time" but even with that is seems to be fixed or at least working better than before.

lygris commented 1 year ago

I ended up forking the upstream wyzeapy repo and setting the refresh time there to 86400. This also did not work. It seems like the integration is never refreshing the token, or rebooting somehow messes with the refresh process that was implemented.

Trying some more fixes and will report back

brg468 commented 1 year ago

I can say for sure that the token does get refreshed, I’ve been able to watch the tokens change every 48 hours. I’m thinking it’s something with the reboots.

When you have these issues, are you doing updates or things that may alter the config entries?

lygris commented 1 year ago

I can say for sure that the token does get refreshed, I’ve been able to watch the tokens change every 48 hours. I’m thinking it’s something with the reboots.

When you have these issues, are you doing updates or things that may alter the config entries?

Just updates and config changes here and there, nothing in the config entries though. Currently i set it to refresh the token on every reboot in init.py. i'll see if that fixes my issue.

brg468 commented 1 year ago

Currently i set it to refresh the token on every reboot in init.py. i'll see if that fixes my issue.

That was going to be my next suggestion.

brg468 commented 12 months ago

If anybody that's having these issues wants to try this and see if it fixes the issue:

Go to your manifest.json file and change the "requirements" value to this:

"requirements": [
    "git+https://github.com/brg468/wyzeapy.git@handle-token-refresh#wyzeapy==0.5.23"
  ],

This will pull an updated version of the backend that refreshes the token on every HA restart and has a way to handle token expiration while HA is still running. Looking for feedback if this fixes your issues, I still haven't been able to duplicate.

Edit: disregard these steps, it doesn’t seem to have the intended result. See my comment below that should work 🤞

crsiebler commented 12 months ago

@brg468 I modified my manifest.json as explained and restarted HA. The integration reloaded and was functional. Thank you for your effort in tracking down this issue.

lygris commented 12 months ago

If anybody that's having these issues wants to try this and see if it fixes the issue:

Go to your manifest.json file and change the "requirements" value to this:

"requirements": [
    "git+https://github.com/brg468/wyzeapy.git@handle-token-refresh#wyzeapy==0.5.23"
  ],

This will pull an updated version of the backend that refreshes the token on every HA restart and has a way to handle token expiration while HA is still running. Looking for feedback if this fixes your issues, I still haven't been able to duplicate.

Changed over my manifest to yours this morning and it doesn't seem to be refreshing on reboot? tried 2 reboots after changing it and the refresh_time in config_entries didn't change

brg468 commented 12 months ago

@lygris that is weird. I just tried on my main setup and had the same result. It works on my dev setup. It seems to be something with pulling from GitHub on every start. I just tried placing the wyzeapy folder in my config folder and it worked, I could see the token and time refresh, so if you want to try that, download my branch from here and place the wyzeapy folder in your config and restart, no need to change the manifest.json, HA will use the folder in config over what the manifest says.

fennemaj commented 11 months ago

@brg468 I pulled your branch and moved the wyzeapy folder into ~/config/ and restarted. I'm prompted to "reconfigure" Wyze and when I enter my login creds and the new key/API pair I generated, it's saying "Unknown Error occurred". Let me know any suggestions you have.

Edit: I think I figured it out, I think I needed to put it in the "custom_components" subdirectory under config. I did that, regenerated a new API key, updated the values in the Wyze integration, and everything auth'd fine. Then I tested with a restart to see if it would fail after the restart and it didn't, it looks fine after a restart to me. I'll check in a day or two and try a restart again and see. For me the issue tended to happen after an upgrade and/or restart, so hopefully this is the fix.

brg468 commented 11 months ago

@fennemaj that's interesting, I've never tried putting in in custom_components so I cant be sure that it'll work.

The way you can tell is to go to your.storage folder and then core-CONFIG_ENTRIES file, find the entry for the wyzeapi domain and see that the access token, refresh token and refresh time change with a restart.

Edit: based on a quick test of putting it in custom_components, it is not using the latest wyzeapy folder so none of the changes are implemented.

lygris commented 11 months ago

@brg468 I was trying it on my own "fix" until this morning when i noticed it wasn't updating status. turns out not rebooting for 2+ days broke it this time. I cloned your branch to my repo and referenced that release in the manifest.json. I'll test out for a few days to see if it is working correctly now

brg468 commented 11 months ago

@lygris The method of updating the manifest didn’t work as intended. Downloading and placing the wyzeapy folder in confit did work, so I’d try that.

lygris commented 11 months ago

@brg468 I don't think it worked because you dont have a release matching that tag? I could be wrong but that's why i cloned yours to my repo and made a release.

Any way i can check if it did? I can seem to find a way to locate the files in HA

brg468 commented 11 months ago

https://github.com/SecKatie/ha-wyzeapi/issues/509#issuecomment-1692135621 check out this comment above.

The tag number shouldn’t match, it’s saying pull my branch unless wyzeapy x.x.xx exists. But for some reason it wasn’t updating the token on startup that way. If you can get the wyzeapy folder from my branch and place it directly in your config folder it will use that. Then check in .storage, config entries and see if the token and time updates.

fennemaj commented 11 months ago

Edit: based on a quick test of putting it in custom_components, it is not using the latest wyzeapy folder so none of the changes are implemented.

Not sure what I screwed up the first time, but I just repulled your branch and dropped it into the config/ directory like suggested and afterwards, when I did the reconfig, I hit no issues entering the credentials and getting everything working. Did a restart and no issue there as well, so looks good to me for now. Will post back if anything changes. Thanks @brg468 !

brg468 commented 11 months ago

Anybody that’s tried this patch, the message below is what you should now see if a token expires and isn’t refreshed by the 48 hour timer. Still not entirely sure why it sometimes seems to expire at an odd time, but this means the fix seems to be working, at least for me.

Logger: wyzeapy.services.update_manager
Source: wyzeapy/utils.py:81 
First occurred: September 1, 2023 at 3:04:59 PM (2 occurrences) 
Last logged: 3:05:01 PM

Unknown error happened during updating device info
Traceback (most recent call last):
  File "/config/wyzeapy/services/update_manager.py", line 42, in update
    self.device = await self.service.update(self.device)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/wyzeapy/services/camera_service.py", line 44, in update
    response = await self._get_event_list(10)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/wyzeapy/services/base_service.py", line 294, in _get_event_list
    check_for_errors_standard(self, response_json)
  File "/config/wyzeapy/utils.py", line 81, in check_for_errors_standard
    raise AccessTokenError("Access Token expired, attempting to refresh")
wyzeapy.exceptions.AccessTokenError: Access Token expired, attempting to refresh
lygris commented 11 months ago

Are we going to get a legit fix for this or is the maintainer MIA?

brg468 commented 11 months ago

Are we going to get a legit fix for this or is the maintainer MIA?

I’m starting to wonder the same..

denverwombat commented 11 months ago

Is it still happening for you all? I definitely had the problem, couldn't go more than about 2-3 days without the API key expiring. I changed my manifest.json with @brg468 's git line when he posted it, and that didn't quite fix it either. I was preparing to pull down his branch locally, but I did an API token refresh about 10 days ago (had houseguests, was prepared for 3 days of functionality before it went out again) and my Wyze lights are still working just fine, 100%

brg468 commented 11 months ago

Is it still happening for you all?

I’m curious about this as well. Those that were constantly having problems, are you still?

James62370 commented 11 months ago

I haven't had a token access error in a while, maybe it was on wyze's end...

Valdorama commented 11 months ago

Same here, don't seem to have had the issue since about 3 weeks ago.

fennemaj commented 11 months ago

Should we remove the wyzeapy directory that was added in bgr468's fix, to see if the last build works as expected? I haven't looked to see if the latest update removed it automatically, but if not, then that's still there for me most likely. I've not had any issues since putting in that fix. Let me know what the approach should be and I'm happy to make the adjustment and report back. So far though, no issues, and I've had at least one update and reboot since 3 weeks ago when I applied the fix noted above.

brg468 commented 11 months ago

There is no latest build, there have been no updates to this repository in almost 2 months.

Maybe the problem was addressed on Wyze's end, you can try removing my branch if you want and see if any issues return. I never had any issues to start with but I did have at least one instance where the updated code caught an expired token and refreshed, but that was several weeks ago now.

JoeSchubert commented 10 months ago

Just stopping by as I was updating things in HA and figured I'd read the latest issues to see what to expect and figured I'd offer some wild speculation @brg468 .

I'm guessing things got resolved since the comments are all pretty old now. But I'm willing to bet that this was all kicked off around the same time as Wyze modified the login method to include the API key. With how they handle logins and token renewals... you probably hit a point where people's renewal tokens somehow invalidated and they weren't getting new ones when the login succeeded for whatever reason... I'm making that assumption based on us having (at least back when I was active) been renewing the token every 48 hours. The tokens lasted something like 60 hours and the refresh tokens never expired. So... It's possible that they still allowed indefinite renewals with a valid refresh token, but weren't handing them out with API logins. If the refresh token failed and the python module wasn't able to successfully log back in, it was setup to make the HA integration here let people know that they needed to re-login. This would have accounted for some people having issues, while others did not.

ManImCool commented 9 months ago

Just stopping by as I was updating things in HA and figured I'd read the latest issues to see what to expect and figured I'd offer some wild speculation @brg468 .

I'm guessing things got resolved since the comments are all pretty old now. But I'm willing to bet that this was all kicked off around the same time as Wyze modified the login method to include the API key. With how they handle logins and token renewals... you probably hit a point where people's renewal tokens somehow invalidated and they weren't getting new ones when the login succeeded for whatever reason... I'm making that assumption based on us having (at least back when I was active) been renewing the token every 48 hours. The tokens lasted something like 60 hours and the refresh tokens never expired. So... It's possible that they still allowed indefinite renewals with a valid refresh token, but weren't handing them out with API logins. If the refresh token failed and the python module wasn't able to successfully log back in, it was setup to make the HA integration here let people know that they needed to re-login. This would have accounted for some people having issues, while others did not.

I'm still having issues and getting the "unknown error occurred" error when trying to submit credentials and keyid/apikey in the wyze integration. Between everyone's prior speculations and guesses and failed attempts to fix it, I currently have no idea what did or didn't work to actually fix this. Any ideas?

brg468 commented 9 months ago

@ManImCool are you saying you're not able to log in at all?

The issues that most people were having was an issue with the access token expiring, but that seems to have gone away, most likely due to a token issue on Wzye's end. Not being able to log in at all is either a credentials issue or the integration being corrupted for some reason. Try uninstalling and re-installing through HACS and see if that fixes anything.