From d047de351cd976a77067c10a41413eb51ebd47f6 Mon Sep 17 00:00:00 2001 From: Sergey Isachenko Date: Mon, 18 Sep 2017 14:46:38 +0300 Subject: [PATCH] fixing slow execution --- teslajsonpy/BatterySensor.py | 2 - teslajsonpy/BinarySensor.py | 4 -- teslajsonpy/Charger.py | 2 - teslajsonpy/Climate.py | 2 - teslajsonpy/GPS.py | 2 - teslajsonpy/Lock.py | 1 - teslajsonpy/connection.py | 79 ++++++++++++++++-------------------- teslajsonpy/controller.py | 40 +++++++++++++----- 8 files changed, 63 insertions(+), 69 deletions(-) diff --git a/teslajsonpy/BatterySensor.py b/teslajsonpy/BatterySensor.py index 5ef0c15b..cf2d8ab0 100644 --- a/teslajsonpy/BatterySensor.py +++ b/teslajsonpy/BatterySensor.py @@ -23,8 +23,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x5 - self.update() - def update(self): self.__controller.update(self.__id) data = self.__controller.get_charging_params(self.__id) diff --git a/teslajsonpy/BinarySensor.py b/teslajsonpy/BinarySensor.py index 3c9e6b2d..326525a0 100644 --- a/teslajsonpy/BinarySensor.py +++ b/teslajsonpy/BinarySensor.py @@ -20,8 +20,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x1 - self.update() - def update(self): self.__controller.update(self.__id) data = self.__controller.get_drive_params(self.__id) @@ -56,8 +54,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x2 - self.update() - def update(self): self.__controller.update(self.__id) data = self.__controller.get_charging_params(self.__id) diff --git a/teslajsonpy/Charger.py b/teslajsonpy/Charger.py index bce5b8f3..61f5d1e7 100644 --- a/teslajsonpy/Charger.py +++ b/teslajsonpy/Charger.py @@ -20,8 +20,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x8 - self.update() - def update(self): self.__controller.update(self.__id) data = self.__controller.get_charging_params(self.__id) diff --git a/teslajsonpy/Climate.py b/teslajsonpy/Climate.py index 669a06f7..2bb73179 100644 --- a/teslajsonpy/Climate.py +++ b/teslajsonpy/Climate.py @@ -109,8 +109,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x4 - self.update() - def get_inside_temp(self): return self.__inside_temp diff --git a/teslajsonpy/GPS.py b/teslajsonpy/GPS.py index d3a73d10..d666b538 100644 --- a/teslajsonpy/GPS.py +++ b/teslajsonpy/GPS.py @@ -26,8 +26,6 @@ def __init__(self, data, controller): self.uniq_name = 'Tesla model {} {} {}'.format( str(self.__vin[3]).upper(), self.__vin, self.type) - self.update() - def get_location(self): return self.__location diff --git a/teslajsonpy/Lock.py b/teslajsonpy/Lock.py index d6d1954c..c80dd892 100644 --- a/teslajsonpy/Lock.py +++ b/teslajsonpy/Lock.py @@ -23,7 +23,6 @@ def __init__(self, data, controller): str(self.__vin[3]).upper(), self.__vin, self.type) self.bin_type = 0x7 - self.update() def update(self): self.__controller.update(self.__id) diff --git a/teslajsonpy/connection.py b/teslajsonpy/connection.py index 53beeea9..d535d5ea 100644 --- a/teslajsonpy/connection.py +++ b/teslajsonpy/connection.py @@ -2,48 +2,29 @@ import datetime from urllib.parse import urlencode from urllib.request import Request, build_opener +from urllib.error import HTTPError import json +from time import sleep class Connection(object): """Connection to Tesla Motors API""" - - def __init__(self, - email='', - password='', - access_token='', - ): - """Initialize connection object - - Sets the vehicles field, a list of Vehicle objects - associated with your account - Required parameters: - email: your login for teslamotors.com - password: your password for teslamotors.com - - Optional parameters: - access_token: API access token - proxy_url: URL for proxy server - proxy_user: username for proxy server - proxy_password: password for proxy server - """ + def __init__(self, email, password, logger): + """Initialize connection object""" self.user_agent = 'Model S 2.1.79 (SM-G900V; Android REL 4.4.4; en_US'; - self.client_id = "81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384" - self.client_secret = "c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3" + self.client_id = "e4a9949fcfa04068f59abb5a658f2bac0a3428e4652315490b659d5ab3f35a9e" + self.client_secret = "c75f14bbadc8bee3a7594412c31416f8300256d7668ea7e6e7f06727bfb9d220" self.baseurl = 'https://owner-api.teslamotors.com' self.api = '/api/1/' - - if access_token: - self.__sethead(access_token) - else: - self.oauth = { - "grant_type": "password", - "client_id": self.client_id, - "client_secret": self.client_secret, - "email": email, - "password": password} - self.expiration = 0 + self.oauth = { + "grant_type": "password", + "client_id": self.client_id, + "client_secret": self.client_secret, + "email": email, + "password": password} + self.expiration = 0 + self.logger = logger def get(self, command): """Utility command to get data from API""" @@ -54,14 +35,15 @@ def post(self, command, data={}): now = calendar.timegm(datetime.datetime.now().timetuple()) if now > self.expiration: auth = self.__open("/oauth/token", data=self.oauth) - self.__sethead(auth['access_token'], - auth['created_at'] + auth['expires_in'] - 86400) + self.__sethead(auth['access_token']) return self.__open("%s%s" % (self.api, command), headers=self.head, data=data) - def __sethead(self, access_token, expiration=float('inf')): + def __sethead(self, access_token): """Set HTTP header""" self.access_token = access_token - self.expiration = expiration + now = calendar.timegm(datetime.datetime.now().timetuple()) + self.expiration = now + 600 + print(self.expiration) self.head = {"Authorization": "Bearer %s" % access_token, "User-Agent": self.user_agent } @@ -72,13 +54,20 @@ def __open(self, url, headers={}, data=None, baseurl=""): baseurl = self.baseurl req = Request("%s%s" % (baseurl, url), headers=headers) try: - req.data = urlencode(data).encode('utf-8') # Python 3 - except: - try: - req.add_data(urlencode(data)) # Python 2 - except: - pass + req.data = urlencode(data).encode('utf-8') + except TypeError: + pass opener = build_opener() - resp = opener.open(req) + self.logger.error(req.full_url) + while True: + try: + resp = opener.open(req) + except HTTPError as ex: + self.logger.error('HTTPError: %s %s. Sleeping 1 second', ex.code, ex.reason) + sleep(1) + continue + break charset = resp.info().get('charset', 'utf-8') - return json.loads(resp.read().decode(charset)) + data = json.loads(resp.read().decode(charset)) + opener.close() + return data diff --git a/teslajsonpy/controller.py b/teslajsonpy/controller.py index 975671bf..03430c75 100644 --- a/teslajsonpy/controller.py +++ b/teslajsonpy/controller.py @@ -1,5 +1,4 @@ import time -from threading import RLock from teslajsonpy.connection import Connection from teslajsonpy.BatterySensor import Battery @@ -8,11 +7,12 @@ from teslajsonpy.BinarySensor import ParkingSensor, ChargerConnectionSensor from teslajsonpy.Charger import ChargerSwitch from teslajsonpy.GPS import GPS +from json import dumps class Controller: - def __init__(self, email, password, update_interval): - self.__connection = Connection(email, password) + def __init__(self, email, password, update_interval, logger): + self.__connection = Connection(email, password, logger) self.__vehicles = [] self.update_interval = update_interval self.__climate = {} @@ -20,12 +20,12 @@ def __init__(self, email, password, update_interval): self.__state = {} self.__driving = {} self.__last_update_time = {} - self.__lock = RLock() - + self.__logger = logger cars = self.__connection.get('vehicles')['response'] - + self.debug_msg('Found cars: {}'.format(dumps(cars))) for car in cars: self.__last_update_time[car['id']] = 0 + self.debug_msg('Initializing car with ID: {}'.format(car['id'])) self.update(car['id']) self.__vehicles.append(Climate(car, self)) self.__vehicles.append(Battery(car, self)) @@ -36,10 +36,17 @@ def __init__(self, email, password, update_interval): self.__vehicles.append(ParkingSensor(car, self)) self.__vehicles.append(GPS(car, self)) + def debug_msg(self, msg): + if self.__logger: + print(msg) + self.__logger.debug(msg) + def post(self, vehicle_id, command, data={}): + self.debug_msg('vehicles/%i/%s' % (vehicle_id, command)) return self.__connection.post('vehicles/%i/%s' % (vehicle_id, command), data) def get(self, vehicle_id, command): + self.debug_msg('vehicles/%i/%s' % (vehicle_id, command)) return self.__connection.get('vehicles/%i/%s' % (vehicle_id, command)) def data_request(self, vehicle_id, name): @@ -51,12 +58,14 @@ def command(self, vehicle_id, name, data={}): def list_vehicles(self): return self.__vehicles - def wake_up(self, car_id): - self.post(car_id, 'wake_up') + def wake_up(self, vehicle_id): + self.debug_msg('{} {}'.format(vehicle_id, 'wake_up')) + self.post(vehicle_id, 'wake_up') def update(self, car_id): - if time.time() - self.__last_update_time[car_id] > self.update_interval: - self.__lock.acquire() + cur_time = time.time() + if cur_time - self.__last_update_time[car_id] > self.update_interval: + self.wake_up(car_id) data = self.get(car_id, 'data')['response'] self.__climate[car_id] = data['climate_state'] @@ -64,7 +73,16 @@ def update(self, car_id): self.__state[car_id] = data['vehicle_state'] self.__driving[car_id] = data['drive_state'] self.__last_update_time[car_id] = time.time() - self.__lock.release() + self.debug_msg( + 'Update requested:\n\t' + 'Cat_ID: {}\n\t' + 'TS: \n\t\t' + 'Last Update:{}\n\t\t' + 'Current: {} \n\t\t' + 'Delta: {}\n\t' + 'Data: {}'.format( + car_id, self.__last_update_time[car_id], cur_time, cur_time - self.__last_update_time[car_id], + dumps(data))) def get_climate_params(self, car_id): return self.__climate[car_id]