def set_driver(self, mdrv, val, default=0, force=False, report=True): #LOGGER.debug(f'{self.lpfx} {mdrv},{val} default={default} force={force},report={report}') if val is None: # Restore from DB for existing nodes try: val = self.getDriver(mdrv) LOGGER.info(f'{self.lpfx} {val}') except: LOGGER.warning( f'{self.lpfx} getDriver({mdrv}) failed which can happen on new nodes, using {default}' ) val = default if val is None else int(val) try: if not mdrv in self.__my_drivers or val != self.__my_drivers[ mdrv] or force: self.setDriver(mdrv, val, report=report) info = '' if self.id in NODE_DEF_MAP and mdrv in NODE_DEF_MAP[self.id]: info += f"'{NODE_DEF_MAP[self.id][mdrv]['name']}' = " info += f"'{NODE_DEF_MAP[self.id][mdrv]['keys'][val]}'" if val in NODE_DEF_MAP[ self.id][mdrv]['keys'] else "'NOT IN NODE_DEF_MAP'" self.__my_drivers[mdrv] = val LOGGER.debug(f'{self.lpfx} set_driver({mdrv},{val}) {info}') #else: # LOGGER.debug(f'{self.lpfx} not necessary') except: LOGGER.error(f'{self.lpfx} set_driver({mdrv},{val}) failed') return None return val
def set_listen(self, val): LOGGER.warning('Set to {}'.format(val)) if self.isy_hue_emu is not False: if val == 0: self.isy_hue_emu.stop_listener() else: self.isy_hue_emu.start_listener() self.listen_cnt = HueEmuController.LISTEN_TIMEOUT self.setDriver('GV2', val)
def longPoll(self): self.heartbeat() if self.initializing: return if self.get_listen() == 1: LOGGER.warning('Listen Count = {}'.format(self.listen_cnt)) if self.listen_cnt > 0: self.listen_cnt -= 1 else: self.set_listen(0)
def update_status(self): # Reconnect? if self.camect is False: LOGGER.warning( f'{self.lpfx}: reconnecting since camect={self.camect}') self.camect = self.controller.reconnect_host(self.host) if self.camect is False: return False for cam in self.list_cameras(): if cam['id'] in self.cams_by_id: #LOGGER.debug(f"{self.lpfx}: Check camera: {cam}") self.cams_by_id[cam['id']].update_status(cam)
def check_profile(self,thermostats): self.profile_info = get_profile_info(LOGGER) # # First get all the climate programs so we can build the profile if necessary # climates = dict() for thermostatId, thermostat in thermostats.items(): # Only get program data if we have the node. fullData = self.getThermostatSelection(thermostatId,includeProgram=True) if fullData is not False: programs = fullData['thermostatList'][0]['program'] climates[thermostatId] = list() for climate in programs['climates']: climates[thermostatId].append({'name': climate['name'], 'ref':climate['climateRef']}) LOGGER.debug("check_profile: climates={}".format(climates)) # # Set Default profile version if not Found # cdata = deepcopy(self.polyConfig['customData']) LOGGER.info('check_profile: profile_info={}'.format(self.profile_info)) LOGGER.info('check_profile: customData={}'.format(cdata)) if not 'profile_info' in cdata: update_profile = True elif self.profile_info['version'] == cdata['profile_info']['version']: # Check if the climates are different update_profile = False LOGGER.info('check_profile: update_profile={} checking climates.'.format(update_profile)) if 'climates' in cdata: current = cdata['climates'] if not update_profile: # Check if the climates have changed. for id in climates: if id in current: if len(climates[id]) == len(current[id]): for i in range(len(climates[id])): if climates[id][i] != current[id][i]: update_profile = True else: update_profile = True else: update_profile = True else: update_profile = True else: update_profile = True LOGGER.warning('check_profile: update_profile={}'.format(update_profile)) if update_profile: self.write_profile(climates) self.poly.installprofile() cdata['profile_info'] = self.profile_info cdata['climates'] = climates self.saveCustomDataWait(cdata)
def _getOAuth(self): # Do we have it? sdata = self._getOAuthInit() LOGGER.debug("_getOAuth: sdata={}".format(sdata)) if sdata is not False: LOGGER.debug('Init={}'.format(sdata)) self.serverdata['api_key'] = sdata['api_key'] self.serverdata['api_client'] = sdata['api_client'] else: #LOGGER.error(self.poly.init) url = 'https://{}/authorize?response_type=code&client_id={}&redirect_uri={}&state={}'.format(ECOBEE_API_URL,self.api_key,self.redirect_url,self.poly.init['worker']) msg = 'No existing Authorization found, Please <a target="_blank" href="{}">Authorize access to your Ecobee Account</a>'.format(url) self.addNotice({'oauth': msg}) LOGGER.warning(msg) self.waiting_on_tokens = "OAuth"
def get_driver(self, mdrv, default=None): # Restore from DB for existing nodes try: val = self.getDriver(mdrv) LOGGER.info(f"{self.lpfx} {mdrv}={val}") if val is None: LOGGER.info( f"{self.lpfx} getDriver({mdrv}) returned None which can happen on new nodes, using {default}" ) val = default except: LOGGER.warning( f"{self.lpfx} getDriver({mdrv}) failed which can happen on new nodes, using {default}" ) val = default return val
def check_api(self): """ Check if api being used is old and user needs to re-auth """ msg = None if 'api_key' in self.polyConfig['customData']: if self.polyConfig['customData']['api_key'] != self.api_key: msg = 'You are using old api key "{}".'.format(self.polyConfig['customData']['api_key']) return False elif 'tokenData' in self.polyConfig['customData']: msg = 'No api key found, if you have previously authorized, ' if msg is not None: msg += ' Please <a target="_blank" href="https://www.ecobee.com/consumerportal/">Signin to your Ecobee account</a>. Click on Profile > My Apps > Remove App of the old Nodeserver, and resart this NodeServer' LOGGER.warning(msg) self.addNotice({'check_api': msg}) return False return True
def set_driver(self,mdrv,val,default=0,force=False,report=True,prec=0,uom=None): LOGGER.debug(f'{self.lpfx} {mdrv},{val} default={default} force={force},report={report}') if val is None: # Restore from DB for existing nodes try: val = self.getDriver(mdrv) LOGGER.info(f'{self.lpfx} {val}') except: LOGGER.warning(f'{self.lpfx} getDriver({mdrv}) failed which can happen on new nodes, using {default}') if val is None: val = default elif prec == 0: try: val = int(val) except Exception as err: LOGGER.error(f'{self.lpfx} Error converting {val} to integer, will use default={default} for {mdrv}',exc_info=True) else: try: val = myfloat(val,prec) except Exception as err: LOGGER.error(f'{self.lpfx} Error converting {val} to float, will use default={default} for {mdrv}',exc_info=True) try: if not mdrv in self.__my_drivers or val != self.__my_drivers[mdrv] or force: self.setDriver(mdrv,val,report=report,uom=uom) try: info = '' if self.id in NODE_DEF_MAP and mdrv in NODE_DEF_MAP[self.id]: info += f"'{NODE_DEF_MAP[self.id][mdrv]['name']}' = " if 'keys' in NODE_DEF_MAP[self.id][mdrv]: info += f"'{NODE_DEF_MAP[self.id][mdrv]['keys'][val]}'" if val in NODE_DEF_MAP[self.id][mdrv]['keys'] else "'NOT IN NODE_DEF_MAP'" else: info += str(val) self.__my_drivers[mdrv] = val LOGGER.info(f'{self.lpfx} set_driver({mdrv},{val}) {info}') except Exception as err: LOGGER.error(f'{self.lpfx} Internal error getting node driver info for {mdrv}',exc_info=True) LOGGER.info(f'{self.lpfx} set_driver({mdrv},{val})') #else: # LOGGER.debug(f'{self.lpfx} not necessary') except: LOGGER.error(f'{self.lpfx} set_driver({mdrv},{val}) failed',exc_info=True) return None return val
def ecobeeDelete(self): if 'access_token' in self.tokenData: res = self.session.delete("/oauth2/acess_tokens/"+self.tokenData['access_token']) if res is False: return False if 'error' in res: LOGGER.error('ecobeePost: error="{}" {}'.format(res['error'], res['error_description'])) return False res_data = res['data'] res_code = res['code'] if 'status' in res_data: if 'code' in res_data['status']: if res_data['status']['code'] == 204: LOGGER.info("Revoke successful") return True else: LOGGER.error('Bad return code {}:{}'.format(res_data['status']['code'],res_data['status']['message'])) else: LOGGER.warning("No access_token to revoke...") return False
def _getOAuthInit(self): """ See if we have the oauth data stored already """ sdata = {} if self._cloud: error = False if 'clientId' in self.poly.init['oauth']: sdata['api_client'] = self.poly.init['oauth']['clientId'] else: LOGGER.warning('Unable to find Client ID in the init oauth data: {}'.format(self.poly.init['oauth'])) error = True if 'clientSecret' in self.poly.init['oauth']: sdata['api_key'] = self.poly.init['oauth']['clientSecret'] else: LOGGER.warning('Unable to find Client Secret in the init oauth data: {}'.format(self.poly.init['oauth'])) error = True if error: return False return sdata
def start(self): LOGGER.info('Started LutronCaseta NodeServer') self.poly.add_custom_config_docs("<b>To obtain oauth code, follow <a href='{}' target='_blank'>this link</a> and copy the 'code' portion of the error page url</b>".format(AUTHORIZE_URL)) # This grabs the server.json data and checks profile_version is up to date serverdata = self.poly.get_server_data(check_profile=True) self.setDriver('ST', 1) LOGGER.info('Started Lutron Caseta NodeServer {}'.format(serverdata['version'])) if self.getDriver('GV1') is None: LOGGER.warning('Updating myself since there is no GV1') self.addNode(self,update=True) self.set_debug_level() self.mainloop = mainloop asyncio.set_event_loop(mainloop) self.hb = 0 self.devices = dict() self.heartbeat() self.check_params() if not self.lutron_bridge_ip and not self.oauth_code: return # Get or generate private key self.private_key = self.get_priv_key() LOGGER.info("Private key loaded") # get or generate certifiate self.certificate = self.get_certificate() LOGGER.info("Certificate loaded") # Create an ssl socket to smartbridge raw_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_socket = ssl.wrap_socket(raw_socket, keyfile='./caseta.key', certfile='./caseta.crt', ssl_version=ssl.PROTOCOL_TLSv1_2) # User socket to get smartbridge certificate if self.get_bridge_cert(ssl_socket): LOGGER.info("Bridge certificate saved") self.bridge_connect() ssl_socket.close() self.discover()
def callback(self, event): # {'type': 'alert', 'desc': 'Out Front Door just saw a person.', 'url': 'https://home.camect.com/home/...', # 'cam_id': '96f69defdef1d0b6602a', 'cam_name': 'Out Front Door', 'detected_obj': ['person']} LOGGER.debug(f'{event}') try: if event['type'] == 'mode': # Can't really use this: {'type': 'mode', 'desc': 'HOME'} self.set_mode_by_name(event['desc']) self.controller.set_mode_all() elif 'cam_id' in event: # Anything with cam get's passed to the camera if event['cam_id'] in self.cams_by_id: self.cams_by_id[event['cam_id']].callback(event) else: LOGGER.warning( f"{self.lpfx}: Event for unknown cam_id={event['cam_id']}: {event}" ) else: LOGGER.error( f'{self.lpfx}: Unknwon event, not type=mode or cam_id: {event}' ) except: LOGGER.error(f'{self.lpfx}: in callback: ', exc_info=True)
def l_warning(self, name, string): LOGGER.warning("%s:%s:%s: %s" % (self.id, self.name, name, string))
def purge(self,do_delete=False): LOGGER.info("%s starting do_delete=%s",self.lpfx,do_delete) self.removeNoticesAll() #LOGGER.debug("%s config=",self.lpfx,config) # # Check for removed activities or devices # # This can change while we are checking if another hub is being added... #LOGGER.debug("%s",self.controller.poly.config) # These are all the nodes from the config, not the real nodes we added... nodes = self.controller.poly.config['nodes'].copy() # Pattern match hub address s pch = re.compile('h([a-f0-9]+)$') # Pattern match activity and device addresses pcad = re.compile('(.)(\d+)$') activities = self.harmony_config['info']['activities'] devices = self.harmony_config['info']['devices'] msg_pfx = "Deleting" if do_delete else "Want to delete" delete_cnt = 0 # Check if we still have them. for node in nodes: address = node['address'] if address != self.address: #LOGGER.info("%s Checking Node: %s",self.lpfx,node) LOGGER.info("%s Checking Node: %s",self.lpfx,address) match = pch.match(address) LOGGER.debug(" Match Hub: %s", match) if match: id = match.group(1) #LOGGER.debug("Got: %s %s", type,match) LOGGER.debug('%s Check if Hub %s "%s" id=%s still exists',self.lpfx,address,node['name'],id) ret = next((d for d in self.hubs if d['address'] == address), None) LOGGER.debug('%s Got: %s',self.lpfx,ret) if ret is None: delete_cnt += 1 msg = '%s Hub that is no longer found %s "%s"' % (msg_pfx,address,node['name']) LOGGER.warning('%s %s',self.lpfx,msg) self.addNotice(msg) if do_delete: self.controller.poly.delNode(address) else: match = pcad.match(address) LOGGER.debug(" Match AD: %s", match) if match: type = match.group(1) id = int(match.group(2)) LOGGER.debug(" np: %s", node['primary']) if node['primary'] in self.nodes: pname = self.nodes[node['primary']].name else: pname = node['primary'] #LOGGER.debug("Got: %s %s", type,match) if type == 'a': LOGGER.debug('%s Check if Activity %s "%s" id=%s still exists',self.lpfx,address,node['name'],id) item = next((d for d in activities if int(d['id']) == id), None) LOGGER.debug('%s Got: %s',self.lpfx,item) if item is None or item['cnt'] == 0: delete_cnt += 1 msg = '%s Activity for "%s" that is no longer used %s "%s"' % (msg_pfx,pname,address,node['name']) LOGGER.warning('%s %s',self.lpfx,msg) self.addNotice(msg) if do_delete: self.controller.poly.delNode(address) elif type == 'd': LOGGER.debug('%s Check if Device %s "%s" id=%s still exists',self.lpfx,address,node['name'],id) item = next((d for d in devices if int(d['id']) == id), None) LOGGER.debug('%s Got: %s',self.lpfx,item) if item is None or item['cnt'] == 0: delete_cnt += 1 msg = '%s Device for "%s" that is no longer used %s "%s"' % (msg_pfx,pname,address,node['name']) LOGGER.warning('%s %s',self.lpfx,msg) self.addNotice(msg) if do_delete: self.controller.poly.delNode(address) else: LOGGER.warning('%s Unknown type "%s" "%s" id=%s still exists',self.lpfx,type,address,node['name']) if delete_cnt > 0 and not do_delete: self.addNotice("Please run 'Purge Execute' on %s in Admin Console" % self.name) LOGGER.info("%s done",self.lpfx) self.purge_run = True
def _discover(self): # Clear the hubs now so we clear some that may have been improperly added. self.clear_hubs() # Set all hubs to not found for hub in self.hubs: hub['found'] = False # # Look for the hubs... # self.setDriver('GV7', 2) auto_discover = self.getDriver('GV8') discover_result = None if auto_discover is None: auto_discover = 1 else: auto_discover = int(auto_discover) if (auto_discover == 0): self.l_info('discover','harmony_discover: skipping since auto discover={0}...'.format(auto_discover)) discover_result = list() else: self.l_info('discover','harmony_discover: starting...') sys.path.insert(0,"pyharmony") from pyharmony import discovery as harmony_discovery harmony_discovery.logger = LOGGER try: discover_result = harmony_discovery.discover(scan_attempts=10,scan_interval=1) except (OSError) as err: self.setDriver('GV7', 9) self.l_error('discover','pyharmony discover failed. May need to restart this nodeserver: {}'.format(err), exc_info=True) self.l_info('discover','harmony_discover: {0}'.format(discover_result)) # # Add the nodes # self.setDriver('GV7', 3) # # First from customParams. # for param in self.polyConfig['customParams']: # Look for customParam starting with hub_ match = re.match( "hub_(.*)", param, re.I) self.l_info('discover','param={} match={}'.format(param,match)) if match is not None: # The hub address is everything following the hub_ address = match.group(1) self.l_info('discover','process param={0} address={1}'.format(param,address)) # Get the customParam value which is json code # { "name": "HarmonyHub FamilyRoom", "host": "192.168.1.86" } cfg = self.polyConfig['customParams'][param] cfgd = None try: cfgd = json.loads(cfg) except: err = sys.exc_info()[0] self.l_error('discover','failed to parse cfg={0} Error: {1}'.format(cfg,err)) if cfgd is not None: # Check that name and host are defined. addit = True if not 'name' in cfgd: self.l_error('discover','No name in customParam {0} value={1}'.format(param,cfg)) addit = False if not 'host' in cfgd: self.l_error('discover','No host in customParam {0} value={1}'.format(param,cfg)) addit = False if addit: hub_hash = {'address': address, 'name': get_valid_node_name(cfgd['name']), 'host': cfgd['host'], 'port': 5222, 'found': True, 'custom': True} index = next((idx for (idx, hub) in enumerate(self.hubs) if hub['name'] == hub_name), None) if index is None: self.hubs.append(hub_hash) else: self.hubs[index] = hub_hash # # Next the discovered ones # tst = time.strftime("%m%d%Y-%H%M%S") ust = 'uuid-save-%s' % (tst) if discover_result is not None: LOGGER.debug("hubs.list=%s",self.hubs) for config in discover_result: LOGGER.debug("hub config: %s",config) addit = True if 'current_fw_version' in config: if config['current_fw_version'] == '4.15.206': self.l_error('discover','current_fw_version={} which is not supported. See: {}'. format( config['current_fw_version'], 'https://community.logitech.com/s/question/0D55A00008D4bZ4SAJ/harmony-hub-firmware-update-fixes-vulnerabilities' )) addit = False else: self.l_error('discover','current_fw_version not in config? Will try to use anyway {}'.format(config)) if addit: # See if the hub is already in the list. hub_address = 'h'+id_to_address(config['uuid'],13) hub_name = get_valid_node_name(config['friendlyName']) index = next((idx for (idx, hub) in enumerate(self.hubs) if hub['name'] == hub_name), None) LOGGER.debug('found index=%s',index) if index is None: # Not seen, or is a different name hub_hash = { 'address': hub_address, 'name': hub_name, } self.hubs.append(hub_hash) else: # Keep the same address for this hub name. hub_hash = self.hubs[index] if 'uuid' in hub_hash: if hub_hash['uuid'] != config['uuid']: LOGGER.warning("Seems that hub '%s' uuid changed from '%s' to '%s' will continue using old address %s",hub_name,hub_hash['uuid'],config['uuid'],hub_address) hub_hash[ust] = hub_hash['uuid'] # These always use the latest data. hub_hash['date_time'] = tst hub_hash['host'] = config['ip'] hub_hash['port'] = config['port'] hub_hash['found'] = True hub_hash['save'] = True hub_hash['uuid'] = config['uuid'] # # Write warnings about previously known Hubs # for hub in self.hubs: if not 'found' in hub or not hub['found']: LOGGER.warning("Previously known hub '%s' did not respond to discover",hub['name']) self.save_hubs() # # Build the profile # It needs the hub_list set, so we will reset it later. if self._build_profile(): # # Now really add them. self.add_hubs() # Check on the purge self.purge(do_delete=False)
def delete(self): LOGGER.warning("Nodeserver is being deleted...")
def check_params(self): """ Check all user params are available and valid """ self.removeNoticesAll() # Assume it's good unless it's not self.config_st = True # TODO: Only when necessary self.update_profile() # Temperature Units default_temperature_unit = "F" if "temperature_unit" in self.polyConfig["customParams"]: self.temperature_unit = self.polyConfig["customParams"][ "temperature_unit"] else: self.temperature_unit = default_temperature_unit LOGGER.error( f"{self.lpfx} temperature unit not defined in customParams, Using default {self.temperature_unit}" ) self.temperature_uom = 4 if self.controller.temperature_unit == "C" else 17 LOGGER.info( f"temperature_unit={self.temperature_unit} temerature_uom={self.temperature_uom}" ) # Host default_host = "Your_ELK_IP_Or_Host:PortNum" if "host" in self.polyConfig["customParams"]: self.host = self.polyConfig["customParams"]["host"] else: self.host = default_host LOGGER.error( f"{self.lpfx} host not defined in customParams, please add it. Using {self.host}" ) # Code default_code = "Your_ELK_User_Code_for_Polyglot" # Fix messed up code if "keypad_code" in self.polyConfig["customParams"]: self.user_code = int(self.polyConfig["customParams"]["user_code"]) elif "user_code" in self.polyConfig["customParams"]: try: self.user_code = int( self.polyConfig["customParams"]["user_code"]) except: self.user_code = default_code self.addNotice( "ERROR user_code is not an integer, please fix, save and restart this nodeserver", "host", ) else: self.user_code = default_code LOGGER.error( f"{self.lpfx} user_code not defined in customParams, please add it. Using {self.user_code}" ) # Areas self.use_areas = self.getCustomParam("areas") self.use_areas_list = () if self.use_areas == "": errs = "No areas defined in config so none will be added" LOGGER.error(errs) self.addNotice(errs, "areas") else: if self.use_areas is None: self.use_areas = "1" try: self.use_areas_list = parse_range(self.use_areas) except: errs = f"ERROR: Failed to parse areas range '{self.use_areas}' will not add any areas: {sys.exc_info()[1]}" LOGGER.error(errs) self.addNotice(errs, "areas") self.config_st = False # Outputs self.use_outputs = self.getCustomParam("outputs") self.use_outputs_list = () if self.use_outputs == "" or self.use_outputs is None: LOGGER.warning( "No outputs defined in config so none will be added") else: try: self.use_outputs_list = parse_range(self.use_outputs) except: errs = f"ERROR: Failed to parse outputs range '{self.use_outputs}' will not add any outputs: {sys.exc_info()[1]}" LOGGER.error(errs) self.addNotice(errs, "outputs") self.config_st = False #self.use_keypads = self.getCustomParam("keypads") #self.use_keypads_list = () #if self.use_keypads == "" or self.use_keypads is None: # LOGGER.warning("No keypads defined in config so none will be added") #else: # try: # self.use_keypads_list = parse_range(self.use_keypads) # except: # errs = f"ERROR: Failed to parse keypads range '{self.use_keypads}' will not add any keypads: {sys.exc_info()[1]}" # LOGGER.error(errs) # self.addNotice(errs, "keypads") # self.config_st = False # Make sure they are in the params self.addCustomParam({ "temperature_unit": self.temperature_unit, "host": self.host, "user_code": self.user_code, "areas": self.use_areas, "outputs": self.use_outputs, #"keypads": self.use_keypads }) # Add a notice if they need to change the keypad/password from the default. if self.host == default_host: # This doesn't pass a key to test the old way. self.addNotice( "Please set proper host in configuration page, and restart this nodeserver", "host", ) self.config_st = False if self.user_code == default_code: # This doesn't pass a key to test the old way. self.addNotice( "Please set proper user_code in configuration page, and restart this nodeserver", "code", ) self.config_st = False
def start(self): LOGGER.info('Started Ecobee v2 NodeServer') self.removeNoticesAll() self.heartbeat() self.serverdata = get_server_data(LOGGER) LOGGER.info('Ecobee NodeServer Version {}'.format(self.serverdata['version'])) nsv = 'nodeserver_version' ud = False cust_data = self.polyConfig['customData'] if not nsv in cust_data: LOGGER.info("Adding {}={} to customData".format(nsv,self.serverdata['version'])) cust_data[nsv] = self.serverdata['version'] ud = True elif cust_data[nsv] != self.serverdata['version']: LOGGER.info("Update {} from {} to {} in customData".format(nsv,cust_data[nsv],self.serverdata['version'])) cust_data[nsv] = self.serverdata['version'] ud = True # Delete the saved token data we were doing for a while # For PG3 we can start doing it again, but not in PG2 since it costs $$ # Can't iterate over keys, since the keys get removed, causes python crash keys = list(cust_data.keys()) for key in keys: if re.match('tokenData2020.*',key): LOGGER.info("Deleting old customData key {}".format(key)) del cust_data[key] if ud: self.saveCustomDataWait(cust_data) #LOGGER.debug("init=\n"+json.dumps(self.poly.init,sort_keys=True,indent=2)) LOGGER.debug("customData=\n"+json.dumps(cust_data,sort_keys=True,indent=2)) self.set_debug_mode() self.get_session() # Anything special to do in pgtest development mode? #if self.poly.init['development']: # # Cloud uses OAuth, local users PIN # self.pg_test = False if self._cloud: self.grant_type = 'authorization_code' self.api_key = self.serverdata['api_key'] # TODO: Need a better way to tell if we are on pgtest! # "logBucket": "pgc-test-logbucket-19y0vctj4zlk5", if self.poly.stage == 'test': self.pg_test = True LOGGER.warning("Looks like we are running on to pgtest") self.redirect_url = 'https://pgtest.isy.io/api/oauth/callback' else: LOGGER.warning("Looks like we are running on to pgc") self.redirect_url = 'https://polyglot.isy.io/api/oauth/callback' else: self.grant_type = 'ecobeePin' self.api_key = self.serverdata['api_key_pin'] self.redirect_url = None # Force to false, and successful communication will fix it #self.set_ecobee_st(False) Causes it to always stay false. # Make sure they are using the latest API if self.check_api(): if 'tokenData' in self.polyConfig['customData']: self.tokenData = self.polyConfig['customData']['tokenData'] if self._checkTokens(): LOGGER.info("start: Calling discover...") self.discover() else: LOGGER.info('No tokenData, will need to authorize...') self.authorize() self.reportDrivers() else: LOGGER.info('No tokenData, will need to authorize...') self._reAuth("Using old api key.") self.ready = True LOGGER.debug('done')