Skip to content

Commit de8fe93

Browse files
authored
Create dedicated methods for GET and POST (#7)
1 parent 5541261 commit de8fe93

2 files changed

Lines changed: 35 additions & 42 deletions

File tree

tahoma_api/client.py

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
""" Python wrapper for the Tahoma API """
22
import urllib.parse
3-
from typing import Any, List, Optional
3+
from typing import Any, Dict, List, Optional, Union
44

55
import aiohttp
66
import humps
7+
from aiohttp import ClientResponse
78

89
from tahoma_api.exceptions import BadCredentialsException, TooManyRequestsException
910
from tahoma_api.models import Command, CommandMode, Device, State
1011

12+
JSON = Union[Dict[str, Any], List[Dict[str, Any]]]
13+
1114
API_URL = "https://tahomalink.com/enduser-mobile-web/enduserAPI/" # /doc for API doc
1215

1316

@@ -41,7 +44,7 @@ async def login(self) -> bool:
4144
Caller must provide one of [userId+userPassword, userId+ssoToken, accessToken, jwt]
4245
"""
4346
payload = {"userId": self.username, "userPassword": self.password}
44-
response = await self.__do_http_request("POST", "login", payload)
47+
response = await self.__post("login", payload)
4548

4649
if response.get("success"):
4750
self.__roles = response.get("roles")
@@ -57,9 +60,8 @@ async def get_devices(self, refresh: bool = False) -> List[Device]:
5760
if self.devices and not refresh:
5861
return self.devices
5962

60-
response = await self.__do_http_request("GET", "setup/devices")
61-
62-
devices = [Device(**d) for d in response]
63+
response = await self.__get("setup/devices")
64+
devices = [Device(**d) for d in humps.decamelize(response)]
6365
self.devices = devices
6466

6567
return devices
@@ -68,10 +70,10 @@ async def get_state(self, deviceurl: str) -> List[State]:
6870
"""
6971
Retrieve states of requested device
7072
"""
71-
response = await self.__do_http_request(
72-
"GET", f"setup/devices/{urllib.parse.quote_plus(deviceurl)}/states"
73+
response = await self.__get(
74+
f"setup/devices/{urllib.parse.quote_plus(deviceurl)}/states"
7375
)
74-
state = [State(**s) for s in response]
76+
state = [State(**s) for s in humps.decamelize(response)]
7577

7678
return state
7779

@@ -85,7 +87,7 @@ async def register_event_listener(self) -> str:
8587
timeout : listening sessions are expected to call the /events/{listenerId}/fetch
8688
API on a regular basis.
8789
"""
88-
response = await self.__do_http_request("POST", "events/register")
90+
response = await self.__post("events/register")
8991
listener_id = response.get("id")
9092

9193
return listener_id
@@ -97,7 +99,7 @@ async def fetch_event_listener(self, listener_id: str) -> List[Any]:
9799
Per-session rate-limit : 1 calls per 1 SECONDS period for this particular
98100
operation (polling)
99101
"""
100-
response = await self.__do_http_request("POST", f"events/{listener_id}/fetch")
102+
response = await self.__post(f"events/{listener_id}/fetch")
101103

102104
return response
103105

@@ -121,58 +123,49 @@ async def execute_action_group(
121123
if mode in supported_modes:
122124
endpoint = f"{endpoint}/{mode}"
123125

124-
response = await self.__do_http_request("POST", endpoint, payload)
126+
response = await self.__post(endpoint, payload)
125127

126128
return response
127129

128130
async def get_current_execution(self, exec_id: str) -> List[Any]:
129131
""" Get an action group execution currently running """
130-
response = await self.__do_http_request("GET", f"/exec/current/{exec_id}")
132+
response = await self.__get(f"/exec/current/{exec_id}")
131133
# TODO Strongly type executions
132134

133135
return response
134136

135137
async def get_current_executions(self) -> List[Any]:
136138
""" Get all action groups executions currently running """
137-
response = await self.__do_http_request("GET", "/exec/current")
139+
response = await self.__get("/exec/current")
138140
# TODO Strongly type executions
139141

140142
return response
141143

142-
async def __do_http_request(
143-
self, method: str, endpoint: str, payload: Optional[Any] = None
144-
) -> Any:
145-
"""Make a request to the TaHoma API"""
146-
supported_methods = ["GET", "POST"]
147-
result = response = None
148-
149-
if method not in supported_methods:
150-
raise Exception
151-
152-
if method == "GET":
153-
async with self.session.get(f"{self.api_url}{endpoint}") as response:
154-
result = await response.json()
155-
156-
if method == "POST":
157-
async with self.session.post(
158-
f"{self.api_url}{endpoint}", data=payload
159-
) as response:
160-
result = await response.json()
161-
162-
if result is None or response is None:
163-
return # TODO throw error
164-
165-
# TODO replace by our own library
166-
result = humps.decamelize(result)
167-
144+
async def __get(self, endpoint: str) -> Any:
145+
""" Make a GET request to the TaHoma API """
146+
async with self.session.get(f"{self.api_url}{endpoint}") as response:
147+
await self.check_response(response)
148+
return await response.json()
149+
150+
async def __post(self, endpoint: str, payload: Optional[JSON] = None,) -> Any:
151+
""" Make a POST request to the TaHoma API """
152+
async with self.session.post(
153+
f"{self.api_url}{endpoint}", data=payload
154+
) as response:
155+
await self.check_response(response)
156+
return await response.json()
157+
158+
@staticmethod
159+
async def check_response(response: ClientResponse) -> None:
160+
""" Check the response returned by the TaHoma API"""
168161
if response.status == 200:
169-
return result
170-
162+
return
171163
# 401
172164
# {'errorCode': 'AUTHENTICATION_ERROR',
173165
# 'error': 'Too many requests, try again later : login with xxx@xxx.tld'}
174166
# 'error': 'Bad credentials'}
175167
# 'error': 'Your setup cannot be accessed through this application'}
168+
result = await response.json()
176169
if response.status == 401:
177170
if result.get("errorCode") == "AUTHENTICATION_ERROR":
178171
message = result.get("error")

tahoma_api/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def __init__(
3333
deviceurl: str,
3434
controllable_name: str,
3535
definition: Dict[str, Any],
36-
states: List[Dict[str, Any]],
3736
data_properties: Optional[List[Dict[str, Any]]] = None,
3837
widget: Optional[str] = None,
3938
ui_class: str,
4039
qualified_name: Optional[str] = None,
40+
states: Optional[List[Dict[str, Any]]] = None,
4141
type: str,
4242
**_: Any
4343
) -> None:

0 commit comments

Comments
 (0)