diff --git a/axis/vapix/models/api.py b/axis/vapix/models/api.py index ad5ce04e..f88107ec 100644 --- a/axis/vapix/models/api.py +++ b/axis/vapix/models/api.py @@ -30,7 +30,7 @@ class ApiRequest(ABC, Generic[ApiDataT]): error_codes: dict[int, str] = field(init=False) @abstractmethod - def process_raw(self, raw: str) -> ApiDataT: + def process_raw(self, raw: bytes) -> ApiDataT: """Process raw data.""" diff --git a/axis/vapix/models/api_discovery.py b/axis/vapix/models/api_discovery.py index 0a99d11f..8b6b71de 100644 --- a/axis/vapix/models/api_discovery.py +++ b/axis/vapix/models/api_discovery.py @@ -197,7 +197,7 @@ def __post_init__(self) -> None: "method": "getApiList", } - def process_raw(self, raw: str) -> ListApisT: + def process_raw(self, raw: bytes) -> ListApisT: """Prepare API description dictionary.""" data: ListApisResponseT = orjson.loads(raw) apis = data.get("data", {}).get("apiList", []) @@ -230,7 +230,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/models/basic_device_info.py b/axis/vapix/models/basic_device_info.py index 616763d9..f773f2d4 100644 --- a/axis/vapix/models/basic_device_info.py +++ b/axis/vapix/models/basic_device_info.py @@ -123,7 +123,7 @@ def __post_init__(self) -> None: "method": "getAllProperties", } - def process_raw(self, raw: str) -> GetAllPropertiesT: + def process_raw(self, raw: bytes) -> GetAllPropertiesT: """Prepare API description dictionary.""" data: GetAllPropertiesResponseT = orjson.loads(raw) device_information = data.get("data", {}).get("propertyList", {}) @@ -166,7 +166,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/models/light_control.py b/axis/vapix/models/light_control.py index f1b6cf60..c8309dec 100644 --- a/axis/vapix/models/light_control.py +++ b/axis/vapix/models/light_control.py @@ -260,7 +260,7 @@ def __post_init__(self) -> None: "method": "getLightInformation", } - def process_raw(self, raw: str) -> dict[str, LightInformation]: + def process_raw(self, raw: bytes) -> dict[str, LightInformation]: """Prepare light information dictionary.""" data: GetLightInformationResponseT = orjson.loads(raw) return LightInformation.from_list(data["data"]["items"]) @@ -316,7 +316,7 @@ def __post_init__(self) -> None: "method": "getServiceCapabilities", } - def process_raw(self, raw: str) -> ServiceCapabilities: + def process_raw(self, raw: bytes) -> ServiceCapabilities: """Prepare light information dictionary.""" data: GetServiceCapabilitiesResponseT = orjson.loads(raw) return ServiceCapabilities.from_dict(data["data"]) @@ -345,7 +345,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -417,7 +417,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> bool: + def process_raw(self, raw: bytes) -> bool: """If light is on or off.""" data: GetLightStatusResponseT = orjson.loads(raw) return data["data"]["status"] @@ -448,7 +448,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id, "enabled": self.enabled}, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -475,7 +475,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> Range: + def process_raw(self, raw: bytes) -> Range: """If light is on or off.""" data: GetValidRangesResponseT = orjson.loads(raw) return Range.from_dict(data["data"]["ranges"][0]) @@ -506,7 +506,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id, "intensity": self.intensity}, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -533,7 +533,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> int: + def process_raw(self, raw: bytes) -> int: """If light is on or off.""" data: GetIntensityResponseT = orjson.loads(raw) return data["data"]["intensity"] @@ -570,7 +570,7 @@ def __post_init__(self) -> None: }, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -599,7 +599,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id, "LEDID": self.led_id}, } - def process_raw(self, raw: str) -> int: + def process_raw(self, raw: bytes) -> int: """Process light intensity.""" data: GetIntensityResponseT = orjson.loads(raw) return data["data"]["intensity"] @@ -628,7 +628,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> int: + def process_raw(self, raw: bytes) -> int: """If light is on or off.""" data: GetIntensityResponseT = orjson.loads(raw) return data["data"]["intensity"] @@ -659,7 +659,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id, "enabled": self.enabled}, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -686,7 +686,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> list[Range]: + def process_raw(self, raw: bytes) -> list[Range]: """If light is on or off.""" data: GetValidRangesResponseT = orjson.loads(raw) return Range.from_list(data["data"]["ranges"]) @@ -720,7 +720,7 @@ def __post_init__(self) -> None: }, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -747,7 +747,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> int: + def process_raw(self, raw: bytes) -> int: """Angle of illumination.""" data: GetAngleOfIlluminationResponseT = orjson.loads(raw) return data["data"]["angleOfIllumination"] @@ -776,7 +776,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> int: + def process_raw(self, raw: bytes) -> int: """Angle of illumination.""" data: GetAngleOfIlluminationResponseT = orjson.loads(raw) return data["data"]["angleOfIllumination"] @@ -807,7 +807,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id, "enabled": self.enabled}, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No return data to process.""" @@ -834,7 +834,7 @@ def __post_init__(self) -> None: "params": {"lightID": self.light_id}, } - def process_raw(self, raw: str) -> bool: + def process_raw(self, raw: bytes) -> bool: """If light is on or off.""" data: GetLightSynchronizationDayNightModeResponseT = orjson.loads(raw) return data["data"]["synchronize"] @@ -858,7 +858,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/models/mqtt.py b/axis/vapix/models/mqtt.py index 3163d0b3..27d5742b 100644 --- a/axis/vapix/models/mqtt.py +++ b/axis/vapix/models/mqtt.py @@ -397,7 +397,7 @@ def __post_init__(self) -> None: "params": self.client_config.to_dict(), } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """Prepare view area dictionary.""" @@ -421,7 +421,7 @@ def __post_init__(self) -> None: "method": "activateClient", } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """Prepare view area dictionary.""" @@ -458,7 +458,7 @@ def __post_init__(self) -> None: "method": "getClientStatus", } - def process_raw(self, raw: str) -> ClientConfigStatus: + def process_raw(self, raw: bytes) -> ClientConfigStatus: """Prepare view area dictionary.""" data: GetClientStatusResponseT = orjson.loads(raw) return ClientConfigStatus.from_dict(data["data"]) @@ -484,7 +484,7 @@ def __post_init__(self) -> None: "method": "getEventPublicationConfig", } - def process_raw(self, raw: str) -> EventPublicationConfig: + def process_raw(self, raw: bytes) -> EventPublicationConfig: """Prepare view area dictionary.""" data: GetEventPublicationConfigResponseT = orjson.loads(raw) return EventPublicationConfig.from_dict(data["data"]["eventPublicationConfig"]) @@ -513,5 +513,5 @@ def __post_init__(self) -> None: "params": self.config.to_dict(), } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """Prepare view area dictionary.""" diff --git a/axis/vapix/models/pir_sensor_configuration.py b/axis/vapix/models/pir_sensor_configuration.py index bae1e4a6..e5c7d908 100644 --- a/axis/vapix/models/pir_sensor_configuration.py +++ b/axis/vapix/models/pir_sensor_configuration.py @@ -131,7 +131,7 @@ def __post_init__(self) -> None: "method": "listSensors", } - def process_raw(self, raw: str) -> ListSensorsT: + def process_raw(self, raw: bytes) -> ListSensorsT: """Prepare Pir sensor configuration dictionary.""" data: ListSensorsResponseT = orjson.loads(raw) sensors = data.get("data", {}).get("sensors", []) @@ -169,7 +169,7 @@ def __post_init__(self) -> None: }, } - def process_raw(self, raw: str) -> float | None: + def process_raw(self, raw: bytes) -> float | None: """Prepare sensitivity value.""" data: GetSensitivityResponseT = orjson.loads(raw) return data.get("data", {}).get("sensitivity") @@ -201,7 +201,7 @@ def __post_init__(self) -> None: }, } - def process_raw(self, raw: str) -> None: + def process_raw(self, raw: bytes) -> None: """No expected data in response.""" return None @@ -224,7 +224,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/models/stream_profile.py b/axis/vapix/models/stream_profile.py index f8a80a79..07fd2d30 100644 --- a/axis/vapix/models/stream_profile.py +++ b/axis/vapix/models/stream_profile.py @@ -107,7 +107,7 @@ def __post_init__(self) -> None: "params": {"streamProfileName": profile_list}, } - def process_raw(self, raw: str) -> ListStreamProfilesT: + def process_raw(self, raw: bytes) -> ListStreamProfilesT: """Prepare API description dictionary.""" data: ListStreamProfilesResponseT = orjson.loads(raw) stream_profiles = data.get("data", {}).get("streamProfile", []) @@ -140,7 +140,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/models/view_area.py b/axis/vapix/models/view_area.py index 0801ec34..0358ca4e 100644 --- a/axis/vapix/models/view_area.py +++ b/axis/vapix/models/view_area.py @@ -162,7 +162,7 @@ def __post_init__(self) -> None: "method": "list", } - def process_raw(self, raw: str) -> ListViewAreasT: + def process_raw(self, raw: bytes) -> ListViewAreasT: """Prepare view area dictionary.""" data: ListViewAreasResponseT = orjson.loads(raw) items = data.get("data", {}).get("viewAreas", []) @@ -264,7 +264,7 @@ def __post_init__(self) -> None: "method": "getSupportedVersions", } - def process_raw(self, raw: str) -> list[str]: + def process_raw(self, raw: bytes) -> list[str]: """Process supported versions.""" data: GetSupportedVersionsResponseT = orjson.loads(raw) return data.get("data", {}).get("apiVersions", []) diff --git a/axis/vapix/vapix.py b/axis/vapix/vapix.py index ad6a001a..682c5615 100644 --- a/axis/vapix/vapix.py +++ b/axis/vapix/vapix.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Callable import httpx +import orjson from packaging import version import xmltodict @@ -332,22 +333,33 @@ async def request( async def request2(self, api_request: ApiRequest["ApiDataT"]) -> "ApiDataT": """Make a request to the device.""" - url = self.device.config.url + api_request.path - LOGGER.debug("%s %s", url, api_request.data) + bytes_data = await self.do_request( + api_request.method, + api_request.path, + content=orjson.dumps(api_request.data), + ) + return api_request.process_raw(bytes_data) + + async def do_request( + self, + method: str, + path: str, + content: bytes | None = None, + params: str | None = None, + ) -> bytes: + """Make a request to the device.""" + url = self.device.config.url + path + LOGGER.debug("%s, %s, %s, %s", method, url, content, params) try: response = await self.device.config.session.request( - api_request.method, + method, url, + content=content, + params=params, auth=self.auth, timeout=TIME_OUT, - json=api_request.data, ) - response.raise_for_status() - - except httpx.HTTPStatusError as errh: - LOGGER.debug("%s, %s", response, errh) - raise_error(response.status_code) except httpx.TimeoutException: raise RequestError("Timeout") @@ -360,8 +372,19 @@ async def request2(self, api_request: ApiRequest["ApiDataT"]) -> "ApiDataT": LOGGER.debug("%s", err) raise RequestError("Unknown error: {}".format(err)) + try: + response.raise_for_status() + + except httpx.HTTPStatusError as errh: + LOGGER.debug("%s, %s", response, errh) + raise_error(response.status_code) + if LOGGER.isEnabledFor(logging.DEBUG): - LOGGER.debug("Response: %s from %s", response.text, self.device.config.host) + LOGGER.debug( + "Response: %s from %s %s", + response.content, + self.device.config.host, + path, + ) - return api_request.process_raw(response.text) - return response.text + return response.content