Skip to content

Commit

Permalink
Adding minor improvements (#125)
Browse files Browse the repository at this point in the history
Co-authored-by: Wolfgang Malgadey <wolfgang@malgadey.de>
  • Loading branch information
erwindouna and wmalgadey authored Dec 28, 2024
1 parent 0be233d commit 858733f
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 57 deletions.
4 changes: 3 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,7 @@
}
},
"image": "mcr.microsoft.com/vscode/devcontainers/python:3.12",
"name": "PyTado"
"name": "PyTado",
"postCreateCommand": "python3 -m venv venv && . venv/bin/activate && pip install --upgrade pip && pip install -e '.[all]' && pre-commit install",
"updateContentCommand": "python3 -m venv venv && . venv/bin/activate && pip install --upgrade pip && pip install -e '.[all]' && pre-commit install"
}
17 changes: 11 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,29 @@ repos:
exclude: tests/
args: ["--profile", "black"]

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.5.7
hooks:
- id: pyupgrade
- id: autopep8
exclude: tests/
args: [--max-line-length=100, --aggressive, --aggressive]

- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
hooks:
- id: flake8
exclude: tests/
args: [--max-line-length=100 ]
args: [--max-line-length=100]

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade

- repo: https://github.com/PyCQA/bandit
rev: '1.8.0'
hooks:
- id: bandit
exclude: tests/
args: ["--skip", "B105"]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
Expand Down
105 changes: 55 additions & 50 deletions PyTado/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __init__(
device: int | None = None,
mode: Mode = Mode.OBJECT,
params: dict[str, Any] | None = None,
):
) -> None:
self.endpoint = endpoint
self.command = command
self.action = action
Expand All @@ -92,7 +92,7 @@ def __init__(
device: int | None = None,
mode: Mode = Mode.OBJECT,
params: dict[str, Any] | None = None,
):
) -> None:
super().__init__(
endpoint=endpoint,
command=command,
Expand All @@ -113,7 +113,7 @@ def action(self) -> Action | str:
return self._action

@action.setter
def action(self, value: Action | str):
def action(self, value: Action | str) -> None:
"""Set request action"""
self._action = value

Expand All @@ -138,7 +138,7 @@ def __init__(
password: str,
http_session: requests.Session | None = None,
debug: bool = False,
):
) -> None:
if debug:
_LOGGER.setLevel(logging.DEBUG)
else:
Expand All @@ -154,7 +154,11 @@ def __init__(

self._x_api = self._check_x_line_generation()

def _log_response(self, response: requests.Response, *args, **kwargs):
@property
def is_x_line(self) -> bool:
return self._x_api

def _log_response(self, response: requests.Response, *args, **kwargs) -> None:
og_request_method = response.request.method
og_request_url = response.request.url
og_request_headers = response.request.headers
Expand All @@ -172,12 +176,10 @@ def request(self, request: TadoRequest) -> dict[str, Any]:
self._refresh_token()

headers = self._headers

data = self._configure_payload(headers, request)

url = self._configure_url(request)

http_request = requests.Request(request.action, url, headers=headers, data=data)
http_request = requests.Request(method=request.action, url=url, headers=headers, data=data)
prepped = http_request.prepare()

retries = _DEFAULT_RETRIES
Expand All @@ -201,17 +203,13 @@ def request(self, request: TadoRequest) -> dict[str, Any]:
_DEFAULT_RETRIES,
e,
)
raise e
raise TadoException(e)

if response.text is None or response.text == "":
return {}

return response.json()

@property
def is_x_line(self):
return self._x_api

def _configure_url(self, request: TadoRequest) -> str:
if request.endpoint == Endpoint.MOBILE:
url = f"{request.endpoint}{request.command}"
Expand Down Expand Up @@ -242,6 +240,7 @@ def _configure_payload(self, headers: dict[str, str], request: TadoRequest) -> b
return json.dumps(request.payload).encode("utf8")

def _set_oauth_header(self, data: dict[str, Any]) -> str:
"""Set the OAuth header and return the refresh token"""

access_token = data["access_token"]
expires_in = float(data["expires_in"])
Expand All @@ -250,15 +249,15 @@ def _set_oauth_header(self, data: dict[str, Any]) -> str:
self._token_refresh = refresh_token
self._refresh_at = datetime.now()
self._refresh_at = self._refresh_at + timedelta(seconds=expires_in)
# we subtract 30 seconds from the correct refresh time
# then we have a 30 seconds timespan to get a new refresh_token
# We subtract 30 seconds from the correct refresh time.
# Then we have a 30 seconds timespan to get a new refresh_token
self._refresh_at = self._refresh_at - timedelta(seconds=30)

self._headers["Authorization"] = "Bearer " + access_token
self._headers["Authorization"] = f"Bearer {access_token}"
return refresh_token

def _refresh_token(self) -> None:

"""Refresh the token if it is about to expire"""
if self._refresh_at >= datetime.now():
return

Expand All @@ -274,52 +273,58 @@ def _refresh_token(self) -> None:
self._session = requests.Session()
self._session.hooks["response"].append(self._log_response)

response = self._session.request(
"post",
url,
params=data,
timeout=_DEFAULT_TIMEOUT,
data=json.dumps({}).encode("utf8"),
headers={
"Content-Type": "application/json",
"Referer": "https://app.tado.com/",
},
)
try:
response = self._session.request(
"post",
url,
params=data,
timeout=_DEFAULT_TIMEOUT,
data=json.dumps({}).encode("utf8"),
headers={
"Content-Type": "application/json",
"Referer": "https://app.tado.com/",
},
)
except requests.exceptions.ConnectionError as e:
_LOGGER.error("Connection error: %s", e)
raise TadoException(e)

if response.status_code == 200:
self._set_oauth_header(response.json())
return
if response.status_code != 200:
raise TadoWrongCredentialsException(
"Failed to refresh token, probably wrong credentials. "
f"Status code: {response.status_code}"
)

raise TadoException(
f"Unknown error while refreshing token with status code {response.status_code}"
)
self._set_oauth_header(response.json())

def _login(self) -> tuple[int, str]:

headers = self._headers
headers["Content-Type"] = "application/json"
"""Login to the API and get the refresh token"""

url = "https://auth.tado.com/oauth/token"
data = {
"client_id": "tado-web-app",
"client_secret": "wZaRN7rpjn3FoNyF5IFuxg9uMzYJcvOoQ8QWiIqS3hfk6gLhVlG57j5YNoZL2Rtc",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"grant_type": "password",
"password": self._password,
"scope": "home.user",
"username": self._username,
}

response = self._session.request(
"post",
url,
params=data,
timeout=_DEFAULT_TIMEOUT,
data=json.dumps({}).encode("utf8"),
headers={
"Content-Type": "application/json",
"Referer": "https://app.tado.com/",
},
)
try:
response = self._session.request(
"post",
url,
params=data,
timeout=_DEFAULT_TIMEOUT,
data=json.dumps({}).encode("utf8"),
headers={
"Content-Type": "application/json",
"Referer": "https://app.tado.com/",
},
)
except requests.exceptions.ConnectionError as e:
_LOGGER.error("Connection error: %s", e)
raise TadoException(e)

if response.status_code == 400:
raise TadoWrongCredentialsException("Your username or password is invalid")
Expand Down

0 comments on commit 858733f

Please sign in to comment.