Skip to content

Commit

Permalink
Merge pull request #37 from sander76/3.1.0
Browse files Browse the repository at this point in the history
3.1.0
  • Loading branch information
kingy444 authored Mar 22, 2024
2 parents d9b8e39 + ff104f5 commit d9b3cc8
Show file tree
Hide file tree
Showing 15 changed files with 393 additions and 249 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
python-version: ["3.7", "3.8", "3.9"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v1
Expand Down
10 changes: 9 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,12 @@ Changelog
- Fix tests
- Remove unneeded declerations
- Fix shade position reporting for v2 shades
- Dandle empty hub data being returned
- Handle empty hub data being returned

**v3.1.0**
- General docstring updates
- Handle kwargs in websessions for management of timeout internally
- Update error handling in tools
- Handle empty values and zeros better
- Add type 53 (Sonnette) and yype 95 (Aura Illuminated, Roller). Note: *Type 95 do not support light control*
- Handle PowerType 11 + 12. Both are fixed and cannot be edited
2 changes: 1 addition & 1 deletion aiopvapi/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Aio PowerView api version."""

__version__ = "3.0.2"
__version__ = "3.1.0"
7 changes: 4 additions & 3 deletions aiopvapi/automations.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,22 @@ def _get_to_actual_data(self, raw):
return raw
return raw.get("scene")

async def get_automations(self, fetch_scene_data: bool = True) -> PowerviewData:
async def get_automations(self, fetch_scene_data: bool = True, **kwargs) -> PowerviewData:
"""Get a list of automations.
:returns PowerviewData object
:raises PvApiError when an error occurs.
"""
resources = await self.get_resources()
resources = await self.get_resources(**kwargs)
if self.api_version < 3:
resources = resources[ATTR_SCHEDULED_EVENT_DATA]

_LOGGER.debug("Raw automation data: %s", resources)

processed = {entry[ATTR_ID]: Automation(entry, self.request) for entry in resources}

if fetch_scene_data is True:
for automation in processed.values():
await automation.fetch_associated_scene_data()

_LOGGER.debug("Raw automation data: %s", resources)
return PowerviewData(raw=resources, processed=processed)
118 changes: 64 additions & 54 deletions aiopvapi/helpers/aiorequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@


class PvApiError(Exception):
"""General Api error. Means we have a problem communication with
the PowerView hub."""
"""General Api error."""


class PvApiResponseStatusError(PvApiError):
Expand All @@ -22,15 +21,15 @@ class PvApiMaintenance(PvApiError):


class PvApiConnectionError(PvApiError):
"""Problem connecting to PowerView hub."""
"""Problem connecting to PowerView Hub."""


class PvApiEmptyData(PvApiError):
"""PowerView hub returned empty data."""
"""PowerView Hub returned empty data."""


class AioRequest:
"""Request class managing hub connection."""
"""Request class managing Powerview Hub connection."""

def __init__(
self,
Expand All @@ -40,6 +39,7 @@ def __init__(
timeout: int = 15,
api_version: int | None = None,
) -> None:
"""Initialize request class."""
self.hub_ip = hub_ip
self._timeout = timeout
if loop:
Expand All @@ -56,7 +56,7 @@ def __init__(

@property
def api_path(self) -> str:
"""Returns the initial api call path"""
"""Return the initial api call path."""
if self.api_version and self.api_version >= 3:
return "home"
return "api"
Expand Down Expand Up @@ -90,80 +90,92 @@ async def check_response(self, response, valid_response_codes):
# finally, return the result
return _val

async def get(self, url: str, params: str = None) -> dict:
"""
Get a resource.
async def get(self, url: str, params: str = None, suppress_timeout: bool = False, **kwargs) -> dict:
"""Get a resource.
:param url:
:param params:
:return:
:param url: The URL to fetch.
:param params: Dictionary or bytes to be sent in the query string of the new request
(optional).
:param suppress_timeout: Stermine if timeouts will return an error
:param kwargs: Keyword arguments to be passed to aiohttp ClientSession get method.
For example, timeout can be passed as kwargs.
:return: A dictionary representing the JSON response.
"""
response = None
try:
_LOGGER.debug("Sending GET request to: %s params: %s", url, params)
_LOGGER.debug("Sending GET request to: %s params: %s kwargs: %s", url, params, kwargs)
async with asyncio.timeout(self._timeout):
response = await self.websession.get(url, params=params)
response = await self.websession.get(url, params=params, **kwargs)
return await self.check_response(response, [200, 204])
except (asyncio.TimeoutError, aiohttp.ClientError) as error:
raise PvApiConnectionError(
"Failed to communicate with PowerView hub"
) from error
except TimeoutError as error:
if suppress_timeout:
_LOGGER.debug("Timeout occurred but was suppressed: %s", error)
return None
raise PvApiConnectionError("Timeout in communicating with PowerView Hub") from error
except aiohttp.ClientError as error:
raise PvApiConnectionError("Failed to communicate with PowerView Hub") from error
finally:
if response is not None:
await response.release()

async def post(self, url: str, data: dict = None):
"""
Post a resource update.
async def post(self, url: str, data: dict = None, suppress_timeout: bool = False, **kwargs):
"""Post a resource update.
:param url:
:param data: a Dict. later converted to json.
:return:
:param url: The URL to fetch.
:param data: Dictionary later converted to json. Sent in the request
:param suppress_timeout: Stermine if timeouts will return an error
:param kwargs: Keyword arguments to be passed to aiohttp ClientSession get method.
For example, timeout can be passed as kwargs.
:return: A dictionary representing the JSON response.
"""
response = None
try:
_LOGGER.debug("Sending POST request to: %s data: %s", url, data)
_LOGGER.debug("Sending POST request to: %s data: %s kwargs: %s", url, data, kwargs)
async with asyncio.timeout(self._timeout):
response = await self.websession.post(url, json=data)
response = await self.websession.post(url, json=data, **kwargs)
return await self.check_response(response, [200, 201])
except (asyncio.TimeoutError, aiohttp.ClientError) as error:
raise PvApiConnectionError(
"Failed to communicate with PowerView hub"
) from error
except TimeoutError as error:
if suppress_timeout:
_LOGGER.debug("Timeout occurred but was suppressed: %s", error)
return None
raise PvApiConnectionError("Timeout in communicating with PowerView Hub") from error
except aiohttp.ClientError as error:
raise PvApiConnectionError("Failed to communicate with PowerView Hub") from error
finally:
if response is not None:
await response.release()

async def put(self, url: str, data: dict = None, params=None):
"""
Do a put request.
:param url: string
:param data: a Dict. later converted to json.
:return:
async def put(self, url: str, data: dict = None, params=None, suppress_timeout: bool = False, **kwargs):
"""Do a put request.
:param url: The URL to fetch.
:param data: Dictionary later converted to json. Sent in the request
:param params: Dictionary or bytes to be sent in the query string of the new request
(optional).
:param suppress_timeout: Stermine if timeouts will return an error
:param kwargs: Keyword arguments to be passed to aiohttp ClientSession get method.
For example, timeout can be passed as kwargs.
:return: A dictionary representing the JSON response.
"""
response = None
try:
_LOGGER.debug(
"Sending PUT request to: %s params: %s data: %s",
url,
params,
data,
)
_LOGGER.debug("Sending PUT request to: %s params: %s data: %s kwargs: %s", url, params, data, kwargs)
async with asyncio.timeout(self._timeout):
response = await self.websession.put(url, json=data, params=params)
response = await self.websession.put(url, json=data, params=params, **kwargs)
return await self.check_response(response, [200, 204])
except (asyncio.TimeoutError, aiohttp.ClientError) as error:
raise PvApiConnectionError(
"Failed to communicate with PowerView hub"
) from error
except TimeoutError as error:
if suppress_timeout:
_LOGGER.debug("Timeout occurred but was suppressed: %s", error)
return None
raise PvApiConnectionError("Timeout in communicating with PowerView Hub") from error
except aiohttp.ClientError as error:
raise PvApiConnectionError("Failed to communicate with PowerView Hub") from error
finally:
if response is not None:
await response.release()

async def delete(self, url: str, params: dict = None):
"""
Delete a resource.
"""Delete a resource.
:param url: Endpoint
:param params: parameters
Expand All @@ -177,10 +189,8 @@ async def delete(self, url: str, params: dict = None):
async with asyncio.timeout(self._timeout):
response = await self.websession.delete(url, params=params)
return await self.check_response(response, [200, 204])
except (asyncio.TimeoutError, aiohttp.ClientError) as error:
raise PvApiConnectionError(
"Failed to communicate with PowerView hub"
) from error
except (TimeoutError, aiohttp.ClientError) as error:
raise PvApiConnectionError("Failed to communicate with PowerView Hub") from error
finally:
if response is not None:
await response.release()
Loading

0 comments on commit d9b3cc8

Please sign in to comment.