core: Token refresh fails for Neato

The problem

When the token expires, an exception in the code prevent the refresh making robot unavailable.

What is version of Home Assistant Core has the issue?

2021.6.6

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Container

Integration causing the issue

neato

Link to integration documentation on our website

https://www.home-assistant.io/integrations/neato/

Example YAML snippet

No response

Anything in the logs that might be useful for us?

Logger: homeassistant.config_entries
Source: helpers/config_entry_oauth2_flow.py:464
First occurred: 10:57:09 (1 occurrences)
Last logged: 10:57:09

Error setting up entry Configuration.yaml for neato
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/pybotvac/session.py", line 184, in _get
    return self._oauth.get(path, headers=headers, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 555, in get
    return self.request('GET', url, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py", line 477, in request
    url, headers, data = self._client.add_token(
  File "/usr/local/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 198, in add_token
    raise TokenExpiredError()
oauthlib.oauth2.rfc6749.errors.TokenExpiredError: (token_expired) 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 293, in async_setup
    result = await component.async_setup_entry(hass, self)  # type: ignore
  File "/usr/src/homeassistant/homeassistant/components/neato/__init__.py", line 87, in async_setup_entry
    await hass.async_add_executor_job(hub.update_robots)
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 280, in wrapper
    result = method(*args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/components/neato/__init__.py", line 120, in update_robots
    self._hass.data[NEATO_ROBOTS] = self.my_neato.robots
  File "/usr/local/lib/python3.8/site-packages/pybotvac/account.py", line 123, in robots
    self.refresh_robots()
  File "/usr/local/lib/python3.8/site-packages/pybotvac/account.py", line 163, in refresh_robots
    resp = self._session.get("users/me/robots")
  File "/usr/local/lib/python3.8/site-packages/pybotvac/session.py", line 167, in get
    response = self._get(url, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/pybotvac/session.py", line 186, in _get
    self._oauth.token = self.refresh_tokens()
  File "/usr/src/homeassistant/homeassistant/components/neato/api.py", line 28, in refresh_tokens
    run_coroutine_threadsafe(
  File "/usr/local/lib/python3.8/concurrent/futures/_base.py", line 444, in result
    return self.__get_result()
  File "/usr/local/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result
    raise self._exception
  File "/usr/src/homeassistant/homeassistant/helpers/config_entry_oauth2_flow.py", line 464, in async_ensure_token_valid
    new_token = await self.implementation.async_refresh_token(self.token)
AttributeError: 'OAuth2Session' object has no attribute 'async_refresh_token'

Additional information

No response

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 4
  • Comments: 20 (12 by maintainers)

Most upvoted comments

Excellent! Thank you for working on this. And please let me know if you need any further testing done. I don’t mind leaving the integration broken for a while if it would be helpful.

@chemelli74 I am having the same issue. I added the Oauth2 debug line you requested above, but the output is the same as the original issue. I grepped for neato and oauth in the log output.

If it would still be helpful, I can leave my integration broken for testing.

`2021-07-12 12:29:05 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry Configuration.yaml for neato Traceback (most recent call last): File “/srv/homeassistant/lib/python3.8/site-packages/pybotvac/session.py”, line 184, in _get return self._oauth.get(path, headers=headers, **kwargs) File “/srv/homeassistant/lib/python3.8/site-packages/requests/sessions.py”, line 555, in get return self.request(‘GET’, url, **kwargs) File “/srv/homeassistant/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py”, line 394, in request url, headers, data = self._client.add_token(url, File “/srv/homeassistant/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/clients/base.py”, line 198, in add_token raise TokenExpiredError() oauthlib.oauth2.rfc6749.errors.TokenExpiredError: (token_expired)

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/config_entries.py”, line 293, in async_setup result = await component.async_setup_entry(hass, self) # type: ignore File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/components/neato/init.py”, line 87, in async_setup_entry await hass.async_add_executor_job(hub.update_robots) File “/usr/local/lib/python3.8/concurrent/futures/thread.py”, line 57, in run result = self.fn(*self.args, **self.kwargs) File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/util/init.py”, line 280, in wrapper result = method(*args, **kwargs) File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/components/neato/init.py”, line 120, in update_robots self._hass.data[NEATO_ROBOTS] = self.my_neato.robots File “/srv/homeassistant/lib/python3.8/site-packages/pybotvac/account.py”, line 123, in robots self.refresh_robots() File “/srv/homeassistant/lib/python3.8/site-packages/pybotvac/account.py”, line 164, in refresh_robots resp = self._session.get(“users/me/robots”) File “/srv/homeassistant/lib/python3.8/site-packages/pybotvac/session.py”, line 167, in get response = self._get(url, **kwargs) File “/srv/homeassistant/lib/python3.8/site-packages/pybotvac/session.py”, line 186, in _get self._oauth.token = self.refresh_tokens() File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/components/neato/api.py”, line 28, in refresh_tokens run_coroutine_threadsafe( File “/usr/local/lib/python3.8/concurrent/futures/_base.py”, line 439, in result return self.__get_result() File “/usr/local/lib/python3.8/concurrent/futures/_base.py”, line 388, in __get_result raise self._exception File “/srv/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/config_entry_oauth2_flow.py”, line 464, in async_ensure_token_valid new_token = await self.implementation.async_refresh_token(self.token) AttributeError: ‘OAuth2Session’ object has no attribute ‘async_refresh_token’`

I sent this to @chemelli74 but just adding here for visibility:

  1. ConfigEntryAuth is getting initialized with the session in the place where it expects an implementation, so when it calls async_refresh_token() it is doing that on the session, which is invalid, it needs to do it on the implementation
  2. it’s odd that two sessions are getting created (here: https://github.com/home-assistant/core/blob/dev/homeassistant/components/neato/__init__.py#L80-L82)
  3. you should collapse those two into a single statement: neato_session = api.ConfigEntryAuth(hass, entry, implementation)
  4. You don’t need the OAuth2Session session object created in entry setup because ConfigEntryAuth creates the session here: https://github.com/home-assistant/core/blob/dev/homeassistant/components/neato/api.py#L21