sherif-fanous/Pyecobee

Credentials expire randomly after 1-4 weeks

88gts opened this issue · 4 comments

88gts commented

Hi,

I am running calls frequently, at least 10 times per hour. They work consistently but after 1-4 weeks, the credentials expire and I have to reconfigure it with a new 4 digit app code on the ecobee website. Does anyone else experience this? The credentials have expired after 3 weeks and just 1 week, so it seems inconsistent.

Thanks

[30/Sep/2020 09:20:04] ERROR - EcobeeAuthorizationException raised:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/pyecobee/utilities.py", line 349, in process_http_response
    error_response.error_uri)
EcobeeAuthorizationException: ecobee authorization error encountered for URL => https://api.ecobee.com/token?code=XXX&client_id=XXX&grant_type=refresh_token
HTTP error code => 400
Error type => 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

In my experience that usually means the following situation

  1. Your access token expired
  2. You attempted to refresh the access token using the refresh token
  3. The refresh token you attempted to use to perform the refresh also expired

The most common use case for when point 3 occurs is that somehow a new set of access and refresh tokens were generated at some other time. Whenever a new set of tokens is generated including the refresh token, the previous access and refresh tokens are revoked. This could be as a result of another app/script or a bug in your code somehow that occasionally fails to persist the newly generated tokens.

88gts commented

very odd, now it appears to expire almost daily, with any change to my environment. do you see any issues with this script? it runs every 5m to refresh the token and poll for status.

import shelve
from datetime import datetime
import time
from time import sleep
import pytz
from pyecobee import *
import logger
from logger import *

def persist_to_shelf(file_name, ecobee_service):
    pyecobee_db = shelve.open(file_name, protocol=2)
    pyecobee_db[ecobee_service.thermostat_name] = ecobee_service
    time.sleep(1)
    pyecobee_db.close()

def refresh_tokens(ecobee_service):
    token_response = ecobee_service.refresh_tokens()
    logger.debug('TokenResponse returned from ecobee_service.refresh_tokens():\n{0}'.format(
        token_response.pretty_format()))
    persist_to_shelf('/var/www/scripts/notify/ecobee/pyecobee_db', ecobee_service)
    
if __name__ == '__main__':
    thermostat_name = 'Home'
    pyecobee_db = shelve.open('/var/www/scripts/notify/ecobee/pyecobee_db', protocol=2)
    ecobee_service = pyecobee_db['Home']
    token_response = ecobee_service.refresh_tokens()
    pyecobee_db[ecobee_service.thermostat_name] = ecobee_service
    pyecobee_db.close()

    selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='',include_equipment_status=True)
    thermostat_response = ecobee_service.request_thermostats(selection)    
    print thermostat_response

Well, I see a few potential issues with this code

1- You initialize thermostat_name to Home, but you don't seem to be using this variable anywhere. You actually retrieve the persisted ecobee_service object by hardcoding the key value Home again, but then when you actually update your shelve you don't use either of the hardcoded values but instead use ecobee_service.thermostat_name! Are you sure ecobee_service.thermostat_name == 'Home'?

2-You are opening the shelve file twice and closing it twice and actually persisting ecobee_service into the shelve twice too (Once in main and another time in the persist_to_shelf function so I think something fishy is going on here. Here's what I'd do:

Completely remove the persist_to_shelf function from your code and remove the line where you are calling it from within the refresh_tokens function, so basically your script should look something like this

import logger
import shelve
import time

from datetime import datetime
from logger import *
from time import sleep

import pytz
from pyecobee import *

def refresh_tokens(ecobee_service):
    token_response = ecobee_service.refresh_tokens()
    logger.debug('TokenResponse returned from ecobee_service.refresh_tokens():\n{0}'.format(
        token_response.pretty_format()))
    
if __name__ == '__main__':
    thermostat_name = 'Home'

    pyecobee_db = shelve.open('/var/www/scripts/notify/ecobee/pyecobee_db', protocol=2)
    ecobee_service = pyecobee_db[thermostat_name]

    refresh_tokens(ecobee_service)

    pyecobee_db[thermostat_name] = ecobee_service
    pyecobee_db.close()

    selection = Selection(selection_type=SelectionType.REGISTERED.value, selection_match='',include_equipment_status=True)
    thermostat_response = ecobee_service.request_thermostats(selection)    
    print thermostat_response
88gts commented

Thank you for the edits, I remember playing around with the persist_to_shelf function to get this to work and didn't think through the complications. Updated and will report back if any issues persist. Thanks!