Core: Ecobee integration unable to generate refresh token

Created on 17 Apr 2020  路  51Comments  路  Source: home-assistant/core

The problem

Ecobee integration stopped working. Sensors and climate entities became undefined.

Environment

arch | x86_64
-- | --
dev | false
docker | true
hassio | true
os_name | Linux
os_version | 4.19.107
python_version | 3.7.7
timezone | America/Chicago
version | 0.108.3
virtualenv | false

Home Assistant 0.108.3
Supervisor 217
HassOS 3.12

  • Home Assistant Core release with the issue: 0.108.3
  • Last working Home Assistant Core release (if known): 0.108.3
  • Operating environment (Home Assistant/Supervised/Docker/venv): Supervised
  • Integration causing this issue: ecobee
  • Link to integration documentation on our website: https://www.home-assistant.io/integrations/ecobee/

Problem-relevant configuration.yaml

configured via configuration flow in ui.

Traceback/Error logs

```2020-04-17 12:59:47 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 518, in _request
response.raise_for_status()
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=xxx&client_id=xxx

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 216, in async_setup
hass, self
File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
if not await data.refresh():
File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(self.args, *self.kwargs)
File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 153, in refresh_tokens
auth_request=True,
File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 533, in _request
"ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Additional information

I've had this happen once before. I can remove the integration and reinstall it to solve the problem The link given above appears to be resolving properly when I ran a curl command to it so I am eliminating local network issues. Is this a transient error occurring randomly? Or is it a regular timeout associated with the ecobee api? Is there anything I can do to prevent it in the future?

ecobee

Most helpful comment

Alrighty, that took longer to reproduce then I had hoped but here we are. I was able to reproduce by following these steps:

  1. Ensure ecobee is configured correctly. Update from 0.111.4 to 0.112.3
  2. (this step is likely not needed but I did it just to try) reboot HA a few times ensuring that ecobee continued to work.
  3. Wait for an hour for the access token provided by ecobee to expire.
  4. Reboot HA and note that the entities are now "unavailable"
  5. Reboot HA again because on step 4 it gets stuck in trying to start HA but it has the note about still starting for a long time (10+ minutes)
  6. Note that everything ecobee continues to be unavailable.

Now, I have debug logs of all those steps. Going to try and pull in the parts around pyecobee and homeassistant.components.ecobee. I will still have the full logs so we can search through them more but I don't really want to try and sanitize the entire log.

2020-07-07 19:29:55 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'NXXXXXXXXXXXXXXXjbFS', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXm1KR', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'xXXXXXXXXXXXXXXXlTM5', 'scope': 'smartWrite'}
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXm1KR, refresh XXXXXXXXXXXXlTM5
2020-07-07 19:29:55 DEBUG (SyncWorker_12) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXm1KR'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:29:56 DEBUG (SyncWorker_12) [pyecobee] Request response: 200: <snip>
2020-07-07 19:29:56 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:32:49 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:32:49 DEBUG (SyncWorker_34) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'xXXXXXXXXXXXXXXXlTM5', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:32:50 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXTk0v', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'yXXXXXXXXXXXXXXXg3S7', 'scope': 'smartWrite'}
2020-07-07 19:32:50 DEBUG (SyncWorker_34) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXTk0v, refresh XXXXXXXXXXXXg3S7
2020-07-07 19:32:50 DEBUG (SyncWorker_30) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXTk0v'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:32:50 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: <snip>
2020-07-07 19:32:50 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:35:54 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXTk0v'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:35:54 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 19:35:54 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:37:31 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'yXXXXXXXXXXXXXXXg3S7', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXGRZL', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'AXXXXXXXXXXXXXXXtpzX', 'scope': 'smartWrite'}
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXGRZL, refresh XXXXXXXXXXXXtpzX
2020-07-07 19:37:31 DEBUG (SyncWorker_16) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXGRZL'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:37:32 DEBUG (SyncWorker_16) [pyecobee] Request response: 200: <snip>
2020-07-07 19:37:32 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:40:35 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXGRZL'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:40:35 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 19:40:35 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:42:38 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:42:38 DEBUG (SyncWorker_33) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'AXXXXXXXXXXXXXXXtpzX', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:42:39 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXqtNr', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'XXXXXXXXXXXXXXXXUeIZ', 'scope': 'smartWrite'}
2020-07-07 19:42:39 DEBUG (SyncWorker_33) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXqtNr, refresh XXXXXXXXXXXXUeIZ
2020-07-07 19:42:39 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:42:39 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 19:42:39 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:45:43 DEBUG (SyncWorker_24) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:45:43 DEBUG (SyncWorker_24) [pyecobee] Request response: 200: <snip>
2020-07-07 19:45:43 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:48:46 DEBUG (SyncWorker_20) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:48:46 DEBUG (SyncWorker_20) [pyecobee] Request response: 200: <snip>
2020-07-07 19:48:46 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:51:49 DEBUG (SyncWorker_26) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:51:49 DEBUG (SyncWorker_26) [pyecobee] Request response: 200: <snip>
2020-07-07 19:51:49 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:54:52 DEBUG (SyncWorker_2) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:54:52 DEBUG (SyncWorker_2) [pyecobee] Request response: 200: <snip>
2020-07-07 19:54:52 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:57:55 DEBUG (SyncWorker_35) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:57:55 DEBUG (SyncWorker_35) [pyecobee] Request response: 200: <snip>
2020-07-07 19:57:55 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:00:58 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:00:59 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:00:59 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:04:01 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:04:01 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 20:04:01 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:07:04 DEBUG (SyncWorker_19) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:07:04 DEBUG (SyncWorker_19) [pyecobee] Request response: 200: <snip>
2020-07-07 20:07:04 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:10:07 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:10:09 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:10:09 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:13:10 DEBUG (SyncWorker_30) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:13:10 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: <snip>
2020-07-07 20:13:10 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:16:11 DEBUG (SyncWorker_16) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:16:11 DEBUG (SyncWorker_16) [pyecobee] Request response: 200: <snip>
2020-07-07 20:16:11 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:19:15 DEBUG (SyncWorker_34) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:19:15 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: <snip>
2020-07-07 20:19:15 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:22:19 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:22:19 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 20:22:19 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:25:22 DEBUG (SyncWorker_36) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:25:22 DEBUG (SyncWorker_36) [pyecobee] Request response: 200: <snip>
2020-07-07 20:25:22 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:28:25 DEBUG (SyncWorker_34) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:28:25 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: <snip>
2020-07-07 20:28:25 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:31:28 DEBUG (SyncWorker_31) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:31:28 DEBUG (SyncWorker_31) [pyecobee] Request response: 200: <snip>
2020-07-07 20:31:28 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:34:31 DEBUG (SyncWorker_15) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:34:31 DEBUG (SyncWorker_15) [pyecobee] Request response: 200: <snip>
2020-07-07 20:34:31 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:37:34 DEBUG (SyncWorker_11) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:37:34 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: <snip>
2020-07-07 20:37:34 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:40:37 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:40:37 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:40:37 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:43:40 DEBUG (SyncWorker_14) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:43:40 DEBUG (SyncWorker_14) [pyecobee] Request response: 500: {'status': {'code': 14, 'message': 'Authentication token has expired. Refresh your tokens. '}}
2020-07-07 20:43:40 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing expired ecobee tokens
2020-07-07 20:43:40 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'XXXXXXXXXXXXXXXXUeIZ', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXX7QJF', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'LXXXXXXXXXXXXXXX8aGD', 'scope': 'smartWrite'}
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXX7QJF, refresh XXXXXXXXXXXX8aGD
2020-07-07 20:46:43 DEBUG (SyncWorker_2) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:46:43 DEBUG (SyncWorker_2) [pyecobee] Request response: 200: <snip>
2020-07-07 20:46:43 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:49:44 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:49:44 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:49:44 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:51:38 DEBUG (SyncWorker_13) [pyecobee] Making request to thermostat endpoint to set climate hold: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: None, body: {'selection': {'selectionType': 'thermostats', 'selectionMatch': '521757101845'}, 'functions': [{'type': 'setHold', 'params': {'holdType': 'nextTransition', 'holdClimateRef': 'smart1'}}]}
2020-07-07 20:51:39 DEBUG (SyncWorker_13) [pyecobee] Request response: 200: {'status': {'code': 0, 'message': ''}}
2020-07-07 20:51:39 DEBUG (SyncWorker_8) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:51:39 DEBUG (SyncWorker_8) [pyecobee] Request response: 200: <snip>
2020-07-07 20:51:39 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:54:50 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:54:50 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:54:50 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:57:53 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:57:53 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:57:53 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where things start going bad even though it seems the requests are working.
------------------------------------------

2020-07-07 20:59:02 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 20:59:02 DEBUG (SyncWorker_31) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'LXXXXXXXXXXXXXXX8aGD', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 20:59:03 DEBUG (SyncWorker_31) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXX7H8c', 'token_type': 'Bearer', 'expires_in': 3598, 'refresh_token': '5XXXXXXXXXXXXXXXnNo0', 'scope': 'smartWrite'}
2020-07-07 20:59:03 DEBUG (SyncWorker_31) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXX7H8c, refresh XXXXXXXXXXXXnNo0
2020-07-07 20:59:03 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:59:03 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:59:04 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:59:06 DEBUG (SyncWorker_11) [pyecobee] Making request to thermostat endpoint to set climate hold: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: None, body: {'selection': {'selectionType': 'thermostats', 'selectionMatch': '521757101845'}, 'functions': [{'type': 'setHold', 'params': {'holdType': 'nextTransition', 'holdClimateRef': 'sleep'}}]}
2020-07-07 20:59:06 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: {'status': {'code': 0, 'message': ''}}
2020-07-07 20:59:07 DEBUG (SyncWorker_35) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:59:07 DEBUG (SyncWorker_35) [pyecobee] Request response: 200: <snip>
2020-07-07 20:59:07 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is a reboot where it actually looks like things are failing based upon the log.
------------------------------------------

2020-07-07 21:04:15 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 21:04:15 DEBUG (SyncWorker_28) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: 'refresh_token', 'refresh_token': 'XXXXXXXXXXXXXX8aGD', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 21:04:15 DEBUG (SyncWorker_28) [pyecobee] Request response: 400: {'error': 'invalid_grant', 'error_description': 'The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.', 'error_uri': 'https://tools.ietf.org/html/rfc6749#section-5.2'}
2020-07-07 21:04:15 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 564, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=XXXXXXXXXXXXXX8aGD&client_id=<MY CLIENT ID>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 220, in async_setup
    hass, self
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
    if not await data.refresh():
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 164, in refresh_tokens
    auth_request=True,
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 579, in _request
    "ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Note that I masked the tokens just incase any of them are still valid. I left the last 4 characters and tried to keep them consistant. If the last 4 are the same then you should be able to assume they are fully the same.

All 51 comments

Hey there @marthoc, mind taking a look at this issue as its been labeled with a integration (ecobee) you are listed as a codeowner for? Thanks!

I also had this happen to me recently. I am not sure which 0.108.x version I was on when it happened but I saw it after I upgraded the docker image.

I'm in the same boat here

pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Running:
Name|Value
-- | --
arch | armv7l
dev | false
docker | true
hassio | true
os_name | Linux
os_version | 4.19.106-v7l
python_version | 3.7.7
version | 0.108.5
virtualenv | false

It鈥檚 definitely the same issue as in the previous issue linked. That last issue was closed after things became less than friendly.

Here鈥檚 what I need from anyone experiencing the issue: enable debug logging for both the integration and pyecobee. Wait until the error happens. Then send me your home-assistant.log. I need to see the sequence of events leading up to the error occurring to trace where the problem lies.

Your help is needed!

My ecobee integration is currently broken with this error message due to too many restarts of Home Assistant. I will leave it in this state in an effort to assist with debugging.

I am on Home Assistant version 0.107.7 with HassOS 2.12 on a Raspberry Pi. I added the following to my configuration.yaml for debugging (not sure if this is the right way to do it):

logger:
  default: info
  logs:
    homeassistant.components.ecobee: debug
    pyecobee: debug

After restarting Home Assistant, I got the following in home-assistant.log:

2020-04-25 15:47:19 INFO (MainThread) [homeassistant.setup] Setting up ecobee
2020-04-25 15:47:19 INFO (MainThread) [homeassistant.setup] Setup of domain ecobee took 0.0 seconds.
2020-04-25 15:47:19 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-04-25 15:47:19 DEBUG (SyncWorker_2) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': '123456', 'client_id': '456789'}, body: None
2020-04-25 15:47:19 DEBUG (SyncWorker_2) [pyecobee] Request response: 400: {'error': 'invalid_grant', 'error_description': 'The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.', 'error_uri': 'https://tools.ietf.org/html/rfc6749#section-5.2'}
2020-04-25 15:47:20 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 513, in _request
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=123456&client_id=456789
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 148, in refresh_tokens
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 522, in _request
    "ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Note I replaced the refresh_token and client_id in the above with generic values for privacy, can provide original upon request.

Awesome! Please delete the integration then reauthorize (leaving the debug logging in place). When the error happens again, those are the logs I want!

Will do. Reauthorizing the integration just now brought it back to life. Though I've noticed this problem seems to manifest itself when you restart Home Assistant. My understanding is that home-assistant.log gets wiped upon restart, is there another way to retain the debug log?

I tried restarting Home Assistant via UI and command line several times hoping to trigger the error condition but it didn't work. Then somewhere in the process of updating HassOS to 3.13 and HA to latest 0.108.9 and between multiple reboots, I triggered it. This is all that was captured in the logs (again, I replaced the client id and refresh token with generic values for privacy):

2020-04-26 14:00:25 INFO (MainThread) [homeassistant.setup] Setting up ecobee
2020-04-26 14:00:25 INFO (MainThread) [homeassistant.setup] Setup of domain ecobee took 0.0 seconds.
2020-04-26 14:00:25 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-04-26 14:00:25 DEBUG (SyncWorker_16) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': '123456', 'client_id': '456789'}, body: None
2020-04-26 14:00:25 DEBUG (SyncWorker_16) [pyecobee] Request response: 400: {
2020-04-26 14:00:26 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 518, in _request
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=123456&client_id=456789
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 153, in refresh_tokens
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 533, in _request
    "ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Is this helpful at all? I feel like you want more detailed debugs leading up to the problem but given that this error is triggered somewhere in the process of restarting HA and the fact that logs are not retained across reboots, makes it difficult to catch. FWIW, I tried adding this shell script to my configuration to see if I can backup home-assistant.log but it doesn't seem to be working, not sure why.

shell_command:
  backup_logs: cp /config/home-assistant.log /backup/logs/home-assistant-`date +"%Y%m%d%H%M"`.log

and then automation:

- alias: "Backup Log file"
  trigger:
    platform: homeassistant
    event: shutdown
  action:
    service: shell_command.backup_logs

Same issue here. I've had to remove and relink Ecobee about 5 times in the last 2 months. I have a custom naming scheme so this means I have to rename all resulting entities each time. No major changes other than a restart or upgrading to a new version of Hass.

Here's the log lines containing 'ecobee' that I get...

2020-05-05 15:41:29 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-05-05 15:41:29 DEBUG (SyncWorker_7) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'client_id': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}, body: None
...
2020-05-05 15:41:29 DEBUG (SyncWorker_7) [pyecobee] Request response: 400: {
  "error": "invalid_grant",
  "error_description": "The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.",
  "error_uri": "https://tools.ietf.org/html/rfc6749#section-5.2"
}
...
2020-05-05 15:41:29 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 518, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=co4jNIVWCVoR4pEbQQV5QSieAurqbuoG&client_id=T5gYKIhMMtBefONahsaBwO6IbdpgxfIx

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 216, in async_setup
    hass, self
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
    if not await data.refresh():
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 153, in refresh_tokens
    auth_request=True,
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 533, in _request
    "ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Does this give you something useful, @marthoc?

@MartinHjelmare Can I run something by you here?

As background: ecobee's API uses an auth token and a refresh token. The auth token is good for 1 hour, the refresh token is good for 1 year, or until it is used to refresh tokens, when it is then expired (a new refresh token is issued along with the new auth token on a successful refresh). When the auth token expires, pyecobee raises an exception and the integration refreshes the tokens. The new refresh token gets stored in the config entry by the refresh method:

   async def refresh(self) -> bool:
        """Refresh ecobee tokens and update config entry."""
        _LOGGER.debug("Refreshing ecobee tokens and updating config entry")
        if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
            self._hass.config_entries.async_update_entry(
                self._entry,
                data={
                    CONF_API_KEY: self.ecobee.config[ECOBEE_API_KEY],
                    CONF_REFRESH_TOKEN: self.ecobee.config[ECOBEE_REFRESH_TOKEN],
                },
            )
            return True
        _LOGGER.error("Error refreshing ecobee tokens")
        return False

At startup of HA, the integration loads the stored refresh token from the entry, then refreshes tokens to get a new access token. As long as it hasn't been 1 year since HA was started, the refresh procedure should yield a new access token.

The problem (that has shown up in this issue and several other issues since the conversion to config entries) is that occasionally when a user restarts HA, the refresh token raises an invalid exception (meaning, either it has expired after 1 year or it has already been used to refresh tokens - this exception gets raised in pyecobee when the API response indicates that the tokens have become invalid).

I have been digging trying to figure out why this would be happening. One of the only things I can think of is that the following (from the refresh method above) is not always actually updating the entry with the new refresh token:

            self._hass.config_entries.async_update_entry(
                self._entry,
                data={
                    CONF_API_KEY: self.ecobee.config[ECOBEE_API_KEY],
                    CONF_REFRESH_TOKEN: self.ecobee.config[ECOBEE_REFRESH_TOKEN],
                },
            )

So, when HA restarts, it loads an old refresh token from the entry and the ecobee API flags it as invalid.

Any thoughts/suggestions?

It sounds weird that the config entry file wouldn't get updated when we update the config entry. There's 1 second delay, but we have guards in place to make sure that the data is written to file before stopping.

I don't see anything obvious that looks wrong when looking at the code in home assistant and in the ecobee library.

As a workaround, is there a way to detect this and just start a re-auth workflow without having to delete and re-add the whole integration? Sorry if I'm messing up terminology. This is what used to happen. The front end (non-Lovelace, non-integration) would show that Ecobee isn't authorized and you would get prompted to do it again.

@MartinHjelmare I think I have confirmed my suspicion after looking at @randoogle's logs (sent to me after followup in #35403). See below:

2020-05-12 18:19:16 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-05-12 18:19:16 DEBUG (SyncWorker_5) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'sI5R4FAOwJj3peYIC6Kk8E1oI48AWE6S', 'client_id': '[redacted]'}, body: None
2020-05-12 18:19:17 DEBUG (SyncWorker_5) [pyecobee] Request response: 200: {
  "access_token": "mJMTfyPTbRxMukjhZV3qvMF89SaCZbDo",
  "token_type": "Bearer",
  "expires_in": 3599,
  "refresh_token": "w3ODyJW41bvPyHJJgYAjgADk8QlToWAh",
  "scope": "smartWrite"
}
2020-05-12 18:19:18 DEBUG (SyncWorker_16) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer mJMTfyPTbRxMukjhZV3qvMF89SaCZbDo'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-05-12 18:19:18 DEBUG (SyncWorker_16) [pyecobee] Request response: 200: { '[redacted]' }
2020-05-12 18:19:18 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-05-12 18:21:14 INFO (MainThread) [homeassistant.bootstrap] Config directory: /config
2020-05-12 18:21:14 INFO (MainThread) [homeassistant.setup] Setting up homeassistant
2020-05-12 18:21:14 INFO (MainThread) [homeassistant.setup] Setup of domain homeassistant took 0.0 seconds.
2020-05-12 18:21:14 INFO (SyncWorker_15) [homeassistant.loader] Loaded ecobee from homeassistant.components.ecobee
2020-05-12 18:21:16 INFO (MainThread) [homeassistant.setup] Setting up ecobee
2020-05-12 18:21:16 INFO (MainThread) [homeassistant.setup] Setup of domain ecobee took 0.0 seconds.
2020-05-12 18:21:17 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-05-12 18:21:17 DEBUG (SyncWorker_12) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'sI5R4FAOwJj3peYIC6Kk8E1oI48AWE6S', 'client_id': '[redacted]'}, body: None
2020-05-12 18:21:18 DEBUG (SyncWorker_12) [pyecobee] Request response: 400: {
  "error": "invalid_grant",
  "error_description": "The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.",
  "error_uri": "https://tools.ietf.org/html/rfc6749#section-5.2"
}

We can see at 2020-05-12 18:19:17 a new refresh token is requested using the old token (sI5R4FAOwJj3peYIC6Kk8E1oI48AWE6S) and a new token gets issued (w3ODyJW41bvPyHJJgYAjgADk8QlToWAh). The user then restarted Home Assistant. At 2020-05-12 18:21:14 is the start of startup after a restart, and when the ecobee integration attempts to refresh, the old token is used (sI5R4FAOwJj3peYIC6Kk8E1oI48AWE6S) rather than the new token, which could only be the result of the new token not being saved in the config entry.

The log snippet above omits the chatter of other components for brevity, but I will send you the full log if you wouldn't mind taking a look to see if anything else jumps out.

Yes, because we can see in the log that a good response is returned from ecobee.

To clarify: I suppose we don鈥檛 know that a true response is returned, but I can see from the ecobee log message that that payload will return true - it鈥檚 JSON and it contains the correct keys.

Any updates on this? Should I start digging a little?

@marthoc one thing I noticed is this log entry on HA bootstrapping its config occurred AFTER the ecobee token was refreshed:

2020-05-12 18:21:14 INFO (MainThread) [homeassistant.bootstrap] Config directory: /config

Could it be possible that the in-memory config is updated with the new token, but HA hasn't finished loading all its config during "slow" startups, and the in-memory config gets replaced later?

For testing this theory, a several minute delay could be added when a token refresh is requested:

  await asyncio.sleep(5 * 60)  // delay 5 minutes before refreshing ecobee tokens
  if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
      ...

This kind of appears to be the case in bootstrap.py where the above log message is emitted: https://github.com/home-assistant/core/blob/dev/homeassistant/bootstrap.py

What I can't find is a way to determine IF HASS has fully initialized its config or not (or any other indicator that HASS startup has completed). If there was, then the asynchronous ecobee token refresh code should wait until that has completed. That would be safe even if async_update_entry internally waited to update the config until HA was initialized, since there would still be a large race condition window under that scenario.

From my current understanding, it seems like ecobee token refreshing/startup should not occur until after the EVENT_HOMEASSISTANT_START event, since it is storing data back into config and there is a potential race condition where the new tokens could be lost. I haven't had time to investigated how to make and test this change to the ecobee integration.

However, I do wonder with the change in HASS 0.111 to immediately start HASS core with the integrations started loading AFTER start whether this issue will disappear.

I still have the issue with 0.111.2 unfortunately.

Is there a temporary work around for this that I'm missing?

Is there a temporary work around for this that I'm missing?

While it's not ideal, the only way I have been able to get around this issue is by removing the integration, removing the app from the ecobee portal, and then re-adding the ecobee integration (via the UI), including the whole pin authorization process.

You don鈥檛 need to remove the app. Just delete and re-add the integration, put in the dev api key, add the app using the 4 character code and it will replace the existing app. I have to do this a lot and ecobee鈥檚 website runs like garbage so I do whatever I can to make the process quicker.

anyone tried pairing the thermostat as a homekit device instead of using the integration? I might give this a try as I'm having to re-pair using the integration every couple of days.

I haven't tried homekit. We should figure out how to fix this the right way, though. @marthoc you determined it's a problem saving new tokens in the config entry. Is that correct?

The call to async_update_entry isn't working here?

Yeah this is driving me nuts...especially because I鈥檝e had numerous out-of-memory issues causing HassIO to force restarts multiple times a day (since moving from v107 to v110). So my Ecobee integration hasn鈥檛 been able to recover in any of the restarts. So I鈥檓 now watching this thread with great interest...

I鈥檝e just updated to 111.4 to see if anything changes.

I just pushed a PR that will make the debug logging for the dependency more explicit so that we can trace more precisely where the problem lies. @rsnodgrass may be correct that there is a race condition going on here but we can't know for sure until we see where the failing lies, in HA or in the dependency. I've asked for this to get put into a point release but we will see. Savvy testers could update the dependency themselves to 0.2.7 to get the improved debug logging.

Just upgraded python-ecobee-api and reauthenticated. I'll let you know what logs look like

FYI I just experienced this issue and had to re-setup my app, remove it from HA, and re-add it - now it appears to be working. I'll update my logging to have better output in case this happens again - thanks!

My Ecobee lost it's token and forced a re-installl today again... it worked for 3-4 restarts but then failed today.

I've had debug logging turned on for a week or so now... what logging would be helpful to provide? And, to whom should I direct the info.?

Or is there anything in particular that I should look for in my logs that may help?

@cajuncoding Hi, the debug logging from the FIRST restart where the tokens fail is what is needed. Later restarts could wipe out any trace of what happened.

I had what I believe is this issue and also a similar issue for SmartThings pop up when trying to upgrade from 0.111.4 to 0.112.0 and 0.112.2. I didn't have debug logging set but in my testing the other night I can say for sure that I was able to readily reproduce the issue. I will do the upgrade today, set my logging level and see what information I can provide today.

@rmevans9 you need to have manually updated python-ecobee-api to get the debug logging, since it has not been included into a released version (even as of 0.112.3 released today, as far as I can tell).

I will be sure to do that when I go to test this.

Alrighty, that took longer to reproduce then I had hoped but here we are. I was able to reproduce by following these steps:

  1. Ensure ecobee is configured correctly. Update from 0.111.4 to 0.112.3
  2. (this step is likely not needed but I did it just to try) reboot HA a few times ensuring that ecobee continued to work.
  3. Wait for an hour for the access token provided by ecobee to expire.
  4. Reboot HA and note that the entities are now "unavailable"
  5. Reboot HA again because on step 4 it gets stuck in trying to start HA but it has the note about still starting for a long time (10+ minutes)
  6. Note that everything ecobee continues to be unavailable.

Now, I have debug logs of all those steps. Going to try and pull in the parts around pyecobee and homeassistant.components.ecobee. I will still have the full logs so we can search through them more but I don't really want to try and sanitize the entire log.

2020-07-07 19:29:55 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'NXXXXXXXXXXXXXXXjbFS', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXm1KR', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'xXXXXXXXXXXXXXXXlTM5', 'scope': 'smartWrite'}
2020-07-07 19:29:55 DEBUG (SyncWorker_32) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXm1KR, refresh XXXXXXXXXXXXlTM5
2020-07-07 19:29:55 DEBUG (SyncWorker_12) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXm1KR'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:29:56 DEBUG (SyncWorker_12) [pyecobee] Request response: 200: <snip>
2020-07-07 19:29:56 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:32:49 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:32:49 DEBUG (SyncWorker_34) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'xXXXXXXXXXXXXXXXlTM5', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:32:50 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXTk0v', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'yXXXXXXXXXXXXXXXg3S7', 'scope': 'smartWrite'}
2020-07-07 19:32:50 DEBUG (SyncWorker_34) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXTk0v, refresh XXXXXXXXXXXXg3S7
2020-07-07 19:32:50 DEBUG (SyncWorker_30) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXTk0v'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:32:50 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: <snip>
2020-07-07 19:32:50 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:35:54 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXTk0v'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:35:54 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 19:35:54 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:37:31 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'yXXXXXXXXXXXXXXXg3S7', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXGRZL', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'AXXXXXXXXXXXXXXXtpzX', 'scope': 'smartWrite'}
2020-07-07 19:37:31 DEBUG (SyncWorker_30) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXGRZL, refresh XXXXXXXXXXXXtpzX
2020-07-07 19:37:31 DEBUG (SyncWorker_16) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXGRZL'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:37:32 DEBUG (SyncWorker_16) [pyecobee] Request response: 200: <snip>
2020-07-07 19:37:32 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:40:35 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXGRZL'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:40:35 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 19:40:35 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where nothing changed.
------------------------------------------

2020-07-07 19:42:38 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 19:42:38 DEBUG (SyncWorker_33) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'AXXXXXXXXXXXXXXXtpzX', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 19:42:39 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXXqtNr', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'XXXXXXXXXXXXXXXXUeIZ', 'scope': 'smartWrite'}
2020-07-07 19:42:39 DEBUG (SyncWorker_33) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXXqtNr, refresh XXXXXXXXXXXXUeIZ
2020-07-07 19:42:39 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:42:39 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 19:42:39 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:45:43 DEBUG (SyncWorker_24) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:45:43 DEBUG (SyncWorker_24) [pyecobee] Request response: 200: <snip>
2020-07-07 19:45:43 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:48:46 DEBUG (SyncWorker_20) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:48:46 DEBUG (SyncWorker_20) [pyecobee] Request response: 200: <snip>
2020-07-07 19:48:46 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:51:49 DEBUG (SyncWorker_26) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:51:49 DEBUG (SyncWorker_26) [pyecobee] Request response: 200: <snip>
2020-07-07 19:51:49 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:54:52 DEBUG (SyncWorker_2) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:54:52 DEBUG (SyncWorker_2) [pyecobee] Request response: 200: <snip>
2020-07-07 19:54:52 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 19:57:55 DEBUG (SyncWorker_35) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 19:57:55 DEBUG (SyncWorker_35) [pyecobee] Request response: 200: <snip>
2020-07-07 19:57:55 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:00:58 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:00:59 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:00:59 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:04:01 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:04:01 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 20:04:01 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:07:04 DEBUG (SyncWorker_19) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:07:04 DEBUG (SyncWorker_19) [pyecobee] Request response: 200: <snip>
2020-07-07 20:07:04 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:10:07 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:10:09 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:10:09 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:13:10 DEBUG (SyncWorker_30) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:13:10 DEBUG (SyncWorker_30) [pyecobee] Request response: 200: <snip>
2020-07-07 20:13:10 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:16:11 DEBUG (SyncWorker_16) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:16:11 DEBUG (SyncWorker_16) [pyecobee] Request response: 200: <snip>
2020-07-07 20:16:11 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:19:15 DEBUG (SyncWorker_34) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:19:15 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: <snip>
2020-07-07 20:19:15 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:22:19 DEBUG (SyncWorker_9) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:22:19 DEBUG (SyncWorker_9) [pyecobee] Request response: 200: <snip>
2020-07-07 20:22:19 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:25:22 DEBUG (SyncWorker_36) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:25:22 DEBUG (SyncWorker_36) [pyecobee] Request response: 200: <snip>
2020-07-07 20:25:22 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:28:25 DEBUG (SyncWorker_34) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:28:25 DEBUG (SyncWorker_34) [pyecobee] Request response: 200: <snip>
2020-07-07 20:28:25 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:31:28 DEBUG (SyncWorker_31) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:31:28 DEBUG (SyncWorker_31) [pyecobee] Request response: 200: <snip>
2020-07-07 20:31:28 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:34:31 DEBUG (SyncWorker_15) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:34:31 DEBUG (SyncWorker_15) [pyecobee] Request response: 200: <snip>
2020-07-07 20:34:31 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:37:34 DEBUG (SyncWorker_11) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:37:34 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: <snip>
2020-07-07 20:37:34 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:40:37 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:40:37 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:40:37 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:43:40 DEBUG (SyncWorker_14) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXXqtNr'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:43:40 DEBUG (SyncWorker_14) [pyecobee] Request response: 500: {'status': {'code': 14, 'message': 'Authentication token has expired. Refresh your tokens. '}}
2020-07-07 20:43:40 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing expired ecobee tokens
2020-07-07 20:43:40 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'XXXXXXXXXXXXXXXXUeIZ', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXX7QJF', 'token_type': 'Bearer', 'expires_in': 3599, 'refresh_token': 'LXXXXXXXXXXXXXXX8aGD', 'scope': 'smartWrite'}
2020-07-07 20:43:40 DEBUG (SyncWorker_11) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXX7QJF, refresh XXXXXXXXXXXX8aGD
2020-07-07 20:46:43 DEBUG (SyncWorker_2) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:46:43 DEBUG (SyncWorker_2) [pyecobee] Request response: 200: <snip>
2020-07-07 20:46:43 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:49:44 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:49:44 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:49:44 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:51:38 DEBUG (SyncWorker_13) [pyecobee] Making request to thermostat endpoint to set climate hold: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: None, body: {'selection': {'selectionType': 'thermostats', 'selectionMatch': '521757101845'}, 'functions': [{'type': 'setHold', 'params': {'holdType': 'nextTransition', 'holdClimateRef': 'smart1'}}]}
2020-07-07 20:51:39 DEBUG (SyncWorker_13) [pyecobee] Request response: 200: {'status': {'code': 0, 'message': ''}}
2020-07-07 20:51:39 DEBUG (SyncWorker_8) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:51:39 DEBUG (SyncWorker_8) [pyecobee] Request response: 200: <snip>
2020-07-07 20:51:39 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:54:50 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:54:50 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:54:50 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:57:53 DEBUG (SyncWorker_10) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7QJF'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:57:53 DEBUG (SyncWorker_10) [pyecobee] Request response: 200: <snip>
2020-07-07 20:57:53 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is the reboot where things start going bad even though it seems the requests are working.
------------------------------------------

2020-07-07 20:59:02 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 20:59:02 DEBUG (SyncWorker_31) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: {'grant_type': 'refresh_token', 'refresh_token': 'LXXXXXXXXXXXXXXX8aGD', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 20:59:03 DEBUG (SyncWorker_31) [pyecobee] Request response: 200: {'access_token': 'XXXXXXXXXXXX7H8c', 'token_type': 'Bearer', 'expires_in': 3598, 'refresh_token': '5XXXXXXXXXXXXXXXnNo0', 'scope': 'smartWrite'}
2020-07-07 20:59:03 DEBUG (SyncWorker_31) [pyecobee] Refreshed tokens from ecobee: access XXXXXXXXXXX7H8c, refresh XXXXXXXXXXXXnNo0
2020-07-07 20:59:03 DEBUG (SyncWorker_33) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:59:03 DEBUG (SyncWorker_33) [pyecobee] Request response: 200: <snip>
2020-07-07 20:59:04 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee
2020-07-07 20:59:06 DEBUG (SyncWorker_11) [pyecobee] Making request to thermostat endpoint to set climate hold: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: None, body: {'selection': {'selectionType': 'thermostats', 'selectionMatch': '521757101845'}, 'functions': [{'type': 'setHold', 'params': {'holdType': 'nextTransition', 'holdClimateRef': 'sleep'}}]}
2020-07-07 20:59:06 DEBUG (SyncWorker_11) [pyecobee] Request response: 200: {'status': {'code': 0, 'message': ''}}
2020-07-07 20:59:07 DEBUG (SyncWorker_35) [pyecobee] Making request to thermostat endpoint to get thermostats: url: https://api.ecobee.com/1/thermostat, headers: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer XXXXXXXXXXX7H8c'}, params: {'json': '{"selection": {"selectionType": "registered", "includeRuntime": "true", "includeSensors": "true", "includeProgram": "true", "includeEquipmentStatus": "true", "includeEvents": "true", "includeWeather": "true", "includeSettings": "true"}}'}, body: None
2020-07-07 20:59:07 DEBUG (SyncWorker_35) [pyecobee] Request response: 200: <snip>
2020-07-07 20:59:07 DEBUG (MainThread) [homeassistant.components.ecobee] Updating ecobee

------------- REBOOT HERE ----------------
This is a reboot where it actually looks like things are failing based upon the log.
------------------------------------------

2020-07-07 21:04:15 DEBUG (MainThread) [homeassistant.components.ecobee] Refreshing ecobee tokens and updating config entry
2020-07-07 21:04:15 DEBUG (SyncWorker_28) [pyecobee] Making request to token endpoint to refresh tokens: url: https://api.ecobee.com/token, headers: {}, params: 'refresh_token', 'refresh_token': 'XXXXXXXXXXXXXX8aGD', 'client_id': '<MY CLIENT ID>'}, body: None
2020-07-07 21:04:15 DEBUG (SyncWorker_28) [pyecobee] Request response: 400: {'error': 'invalid_grant', 'error_description': 'The authorization grant, token or credentials are invalid, expired, revoked, do not match the redirection URI used in the authorization request, or was issued to another client.', 'error_uri': 'https://tools.ietf.org/html/rfc6749#section-5.2'}
2020-07-07 21:04:15 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry ecobee for ecobee
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 564, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=XXXXXXXXXXXXXX8aGD&client_id=<MY CLIENT ID>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 220, in async_setup
    hass, self
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
    if not await data.refresh():
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 164, in refresh_tokens
    auth_request=True,
  File "/usr/local/lib/python3.7/site-packages/pyecobee/__init__.py", line 579, in _request
    "ecobee tokens invalid; re-authentication required"
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Note that I masked the tokens just incase any of them are still valid. I left the last 4 characters and tried to keep them consistant. If the last 4 are the same then you should be able to assume they are fully the same.

@rmevans9 Thank you for this, I think it is the clearest indication that my theory is correct: the code to update the config entry isn鈥檛 (always) doing so.

At 20:59:03 we see that the tokens are successfully refreshed (extra debug code I added to pyecobee confirms that step succeeds and returns True) - refresh token retrieved is nNo0.

After the reboot, at 21:04:15 when a refresh is attempted, refresh token 8aGD is used, which is the token from the previous refresh.

@MartinHjelmare I hate to keep tagging you on this issue, but I think this is the clearest indication I have yet that it鈥檚 not the ecobee integration code that is failing here...

Ok. It's not clear why that happens.

@marthoc is there anything else in the logs you may want to see around this? To your note that this indicates it is not the ecobee integration I would point out that although I did not consider my smartthings integration in this test it _does_ exhibit the same problem especially when I upgrade to 0.112.x

I'm experiencing the same issue, just updated from 0.111.4 to 0.114.4 / Supervisor 4.13 and still have this error. My ecobee integration is completely down. 鈽癸笍 Started happening maybe a week ago or so?

Logger: homeassistant.config_entries
Source: components/ecobee/__init__.py:105
First occurred: 7:56:52 PM (1 occurrences)
Last logged: 7:56:52 PM

Error setting up entry ecobee for ecobee
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 564, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=***REDACTED***&client_id=***REDACTED***

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 222, in async_setup
    result = await component.async_setup_entry(  # type: ignore
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
    if not await data.refresh():
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 159, in refresh_tokens
    response = self._request(
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 578, in _request
    raise InvalidTokenError(
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Any workaround I can try? I'm not experienced in the internals of HA but if there's something quick and easy I can try, happy to help test!

I ended up just removing and re-adding the integration... not ideal since ecobee's website is garbage... but it worked.

My recommendation is to add the HomeKit Controller integration and add your Ecobee thermostats through that. It's local, doesn't require any Apple hardware or relationship, and is much more stable than their cloud interface. It is more limited and doesn't support the Ecobee-specific services shown here, but it may be good enough as-is. If you need the additional services, you can add both the HomeKit Controller and Ecobee integrations and use them concurrently.

I'm still having this problem with version 245. In fact I can't even add the integration anymore as the same error as OP shows up:

requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=

@j0dan there must be more to that error... can you find if there is a pyecobee exception that is being thrown?

I have also been getting this error pretty regularly since at least 0.115.3. Removing and reconfiguring the ecobee integration appears to be the only solution so far. There must be a better way to handle this? This is happening often within days of re-adding the integration.

Same error as others:

Logger: homeassistant.config_entries
Source: components/ecobee/__init__.py:105
First occurred: 1:06:48 PM (1 occurrences)
Last logged: 1:06:48 PM
Error setting up entry ecobee for ecobee

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 564, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=[TOKEN]&client_id=[CLIENT_ID]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 228, in async_setup
    result = await component.async_setup_entry(hass, self)  # type: ignore
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
    if not await data.refresh():
  File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
    if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 159, in refresh_tokens
    response = self._request(
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 578, in _request
    raise InvalidTokenError(
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

[TOKEN] and [CLIENT_ID] removed.

I have noticed sometimes when restarting homeassistant-core as a docker container, it will sometimes attempt to complete some networking tasks before networking is available (likely before updating from 0.115.3 to 0.115.6). I don't currently have any logs remaining showing this though.

As you can see above, I think I鈥檝e tracked this to an underlying issue in the way that the refreshed keys are saved to the config entry. It does not appear to have anything to do with the integration or pyecobee code as such. If someone with more knowledge of the workings of HA wants to take a run at tracking down the issue, I would be happy to assist.

@j0dan there must be more to that error... can you find if there is a pyecobee exception that is being thrown?

I can't even add the integration. It sits at adding and after a restart this is in the logs:

2020-10-08 13:38:02 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 564, in _request
    response.raise_for_status()
  File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=xHiFCgbU31nKlFDYRloK6FKioEdsOE8q&client_id=MCt2u6kH6uCixkjvD3bl3Go2Er2DFXtk

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 131, in async_init
    result = await self._async_handle_step(
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 204, in _async_handle_step
    result: Dict = await getattr(flow, method)(user_input)
  File "/usr/src/homeassistant/homeassistant/components/ecobee/config_flow.py", line 107, in async_step_import
    if await self.hass.async_add_executor_job(ecobee.refresh_tokens):
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 159, in refresh_tokens
    response = self._request(
  File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 578, in _request
    raise InvalidTokenError(
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

issues .. after reboots it dropped off again ...

arch | x86_64
-- | --
chassis | vm
dev | false
docker | true
docker_version | 19.03.11
hassio | true
host_os | HassOS 4.12
installation_type | Home Assistant OS
os_name | Linux
os_version | 5.4.56
python_version | 3.8.3
supervisor | 2020.10.1
timezone | America/New_York
version | 0.113.3
virtualenv | false

Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 219, in async_setup
result = await component.async_setup_entry( # type: ignore
File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 58, in async_setup_entry
if not await data.refresh():
File "/usr/src/homeassistant/homeassistant/components/ecobee/__init__.py", line 105, in refresh
if await self._hass.async_add_executor_job(self.ecobee.refresh_tokens):
File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(self.args, *self.kwargs)
File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 159, in refresh_tokens
response = self._request(
File "/usr/local/lib/python3.8/site-packages/pyecobee/__init__.py", line 578, in _request
raise InvalidTokenError(
pyecobee.errors.InvalidTokenError: ecobee tokens invalid; re-authentication required

Mine worked for a series of reboots and then just lost connection again -- gotta delete, re-add and re-authenticate now, again . . .

just had this happen to me for the first time...i'm on 0.116.3 if that matters.

Having same issue here
(could not figure out how to properly quote the code part)

########################### Version

Home Assistant Core Integration
version: 0.118.1
installation_type: Home Assistant Core
dev: false
hassio: false
docker: false
virtualenv: true
python_version: 3.7.3
os_name: Linux
os_version: 4.19.75-v7l+
arch: armv7l
timezone: America/Chicago

Home Assistant Cloud

logged_in: false
can_reach_cert_server: ok
can_reach_cloud_auth: ok
can_reach_cloud: ok

Lovelace

dashboards: 1
mode: storage
views: 2
resources: 1'


Logger: homeassistant.components.websocket_api.http.connection
Source: components/ecobee/climate.py:586
Integration: Home Assistant WebSocket API (documentation, issues)
First occurred: 6:43:45 PM (4 occurrences)
Last logged: 6:44:30 PM`

[2331275376] ecobee access token expired; token refresh required
Traceback (most recent call last):
File "/srv/homeassistant/lib/python3.7/site-packages/pyecobee/__init__.py", line 564, in _request response.raise_for_status()
File "/srv/homeassistant/lib/python3.7/site-packages/requests/models.py", line 943, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://api.ecobee.com/1/thermostat

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py", line 140, in handle_call_service
connection.context(msg),
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/core.py", line 1451, in async_call
task.result()
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/core.py", line 1486, in _execute_service
await handler.job.target(service_call)
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/entity_component.py", line 205, in handle_service
self._platforms.values(), func, call, required_features
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 499, in entity_service_call
future.result() # pop exception if have
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/entity.py", line 664, in async_request_call
await coro
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 536, in _handle_entity_call
await result
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/climate/__init__.py", line 544, in async_service_temperature_set
await entity.async_set_temperature(*kwargs)
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/climate/__init__.py", line 405, in async_set_temperature
ft.partial(self.set_temperature, *
kwargs)
File "/usr/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(self.args, *self.kwargs)
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/ecobee/climate.py", line 648, in set_temperature
self.set_temp_hold(temp)
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/ecobee/climate.py", line 635, in set_temp_hold
self.set_auto_temp_hold(heat_temp, cool_temp)
File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/ecobee/climate.py", line 586, in set_auto_temp_hold
self.hold_preference(),
File "/srv/homeassistant/lib/python3.7/site-packages/pyecobee/__init__.py", line 337, in set_hold_temp
raise err
File "/srv/homeassistant/lib/python3.7/site-packages/pyecobee/__init__.py", line 335, in set_hold_temp
self._request("POST", ECOBEE_ENDPOINT_THERMOSTAT, log_msg_action, body=body)
File "/srv/homeassistant/lib/python3.7/site-packages/pyecobee/__init__.py", line 594, in _request
"ecobee access token expired; token refresh required"
pyecobee.errors.ExpiredTokenError: ecobee access token expired; token refresh required`

Was this page helpful?
0 / 5 - 0 ratings