aioamazondevices 6.5.0__tar.gz → 6.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aioamazondevices
3
- Version: 6.5.0
3
+ Version: 6.5.1
4
4
  Summary: Python library to control Amazon devices
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aioamazondevices"
3
- version = "6.5.0"
3
+ version = "6.5.1"
4
4
  requires-python = ">=3.12"
5
5
  description = "Python library to control Amazon devices"
6
6
  authors = [
@@ -1,6 +1,6 @@
1
1
  """aioamazondevices library."""
2
2
 
3
- __version__ = "6.5.0"
3
+ __version__ = "6.5.1"
4
4
 
5
5
 
6
6
  from .api import AmazonDevice, AmazonEchoApi
@@ -40,6 +40,7 @@ from .const import (
40
40
  AMAZON_CLIENT_OS,
41
41
  AMAZON_DEVICE_SOFTWARE_VERSION,
42
42
  AMAZON_DEVICE_TYPE,
43
+ ARRAY_WRAPPER,
43
44
  BIN_EXTENSION,
44
45
  COUNTRY_GROUPS,
45
46
  CSRF_COOKIE,
@@ -606,20 +607,19 @@ class AmazonEchoApi:
606
607
  _LOGGER.info("Register device: %s", scrub_fields(login_data))
607
608
  return login_data
608
609
 
609
- async def _get_sensors_state(
610
- self, endpoint_id_list: list[str]
611
- ) -> dict[str, Any] | list[dict[str, Any]]:
612
- """Get sensor State."""
610
+ async def _get_sensors_states(self) -> dict[str, dict[str, AmazonDeviceSensor]]:
611
+ """Retrieve devices sensors states."""
612
+ devices_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
613
+
614
+ endpoint_ids = list(self._endpoints.keys())
613
615
  payload = [
614
616
  {
615
617
  "operationName": "getEndpointState",
616
618
  "variables": {
617
- "endpointId": endpoint_id,
618
- "latencyTolerance": "LOW",
619
+ "endpointIds": endpoint_ids,
619
620
  },
620
621
  "query": QUERY_SENSOR_STATE,
621
622
  }
622
- for endpoint_id in endpoint_id_list
623
623
  ]
624
624
 
625
625
  _, raw_resp = await self._session_request(
@@ -629,47 +629,29 @@ class AmazonEchoApi:
629
629
  json_data=True,
630
630
  )
631
631
 
632
- return await self._response_to_json(raw_resp)
632
+ sensors_state = await self._response_to_json(raw_resp)
633
+ _LOGGER.debug("Sensor data - %s", sensors_state)
633
634
 
634
- async def _get_sensors_states(self) -> dict[str, dict[str, AmazonDeviceSensor]]:
635
- """Retrieve devices sensors states."""
636
- devices_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
637
-
638
- # batch endpoints into groups of 3 to reduce number of requests
639
- endpoint_ids = list(self._endpoints.keys())
640
- batches = [endpoint_ids[i : i + 3] for i in range(0, len(endpoint_ids), 3)]
641
- for endpoint_id_batch in batches:
642
- sensors_state = await self._get_sensors_state(endpoint_id_batch)
643
- _LOGGER.debug("Sensor data - %s", sensors_state)
635
+ if await self._format_human_error(sensors_state):
636
+ # Explicit error in returned data
637
+ return {}
644
638
 
645
- if not isinstance(sensors_state, list) and (
646
- error := sensors_state.get("errors")
647
- ):
648
- if isinstance(error, list):
649
- error = error[0]
650
- msg = error.get("message", "Unknown error")
651
- path = error.get("path", "Unknown path")
652
- _LOGGER.error(
653
- "Error retrieving devices state: %s for path %s", msg, path
654
- )
655
- return {}
639
+ if (
640
+ not (arr := sensors_state.get(ARRAY_WRAPPER))
641
+ or not (data := arr[0].get("data"))
642
+ or not (endpoints_list := data.get("listEndpoints"))
643
+ or not (endpoints := endpoints_list.get("endpoints"))
644
+ ):
645
+ _LOGGER.error("Malformed sensor state data received: %s", sensors_state)
646
+ return {}
656
647
 
657
- for endpoint_data in sensors_state:
658
- if (
659
- not isinstance(endpoint_data, dict)
660
- or not (data := endpoint_data.get("data"))
661
- or not (endpoint := data.get("endpoint"))
662
- ):
663
- _LOGGER.error(
664
- "Malformed sensor state data received: %s", endpoint_data
665
- )
666
- return {}
667
- serial_number = self._endpoints[endpoint.get("endpointId")]
648
+ for endpoint in endpoints:
649
+ serial_number = self._endpoints[endpoint.get("endpointId")]
668
650
 
669
- if serial_number in self._final_devices:
670
- devices_sensors[serial_number] = self._get_device_sensor_state(
671
- endpoint, serial_number
672
- )
651
+ if serial_number in self._final_devices:
652
+ devices_sensors[serial_number] = self._get_device_sensor_state(
653
+ endpoint, serial_number
654
+ )
673
655
 
674
656
  return devices_sensors
675
657
 
@@ -758,7 +740,7 @@ class AmazonEchoApi:
758
740
  endpoint_data = await self._response_to_json(raw_resp)
759
741
 
760
742
  if not (data := endpoint_data.get("data")) or not data.get("listEndpoints"):
761
- _LOGGER.error("Malformed endpoint data received: %s", endpoint_data)
743
+ await self._format_human_error(endpoint_data)
762
744
  return {}
763
745
 
764
746
  endpoints = data["listEndpoints"]
@@ -782,6 +764,10 @@ class AmazonEchoApi:
782
764
  if not data:
783
765
  _LOGGER.warning("Empty JSON data received")
784
766
  data = {}
767
+ if isinstance(data, list):
768
+ # if anonymous array is returned wrap it inside
769
+ # generated key to convert list to dict
770
+ data = {ARRAY_WRAPPER: data}
785
771
  return cast("dict[str, Any]", data)
786
772
  except ContentTypeError as exc:
787
773
  raise ValueError("Response not in JSON format") from exc
@@ -1576,3 +1562,18 @@ class AmazonEchoApi:
1576
1562
  scale=None,
1577
1563
  )
1578
1564
  return dnd_status
1565
+
1566
+ async def _format_human_error(self, sensors_state: dict) -> bool:
1567
+ """Format human readable error from malformed data."""
1568
+ if sensors_state.get(ARRAY_WRAPPER):
1569
+ error = sensors_state[ARRAY_WRAPPER][0].get("errors", [])
1570
+ else:
1571
+ error = sensors_state.get("errors", [])
1572
+
1573
+ if not error:
1574
+ return False
1575
+
1576
+ msg = error[0].get("message", "Unknown error")
1577
+ path = error[0].get("path", "Unknown path")
1578
+ _LOGGER.error("Error retrieving devices state: %s for path %s", msg, path)
1579
+ return True
@@ -4,6 +4,8 @@ import logging
4
4
 
5
5
  _LOGGER = logging.getLogger(__package__)
6
6
 
7
+ ARRAY_WRAPPER = "generatedArrayWrapper"
8
+
7
9
  HTTP_ERROR_199 = 199
8
10
  HTTP_ERROR_299 = 299
9
11
 
@@ -41,44 +41,57 @@ query getDevicesBaseData {
41
41
  """
42
42
 
43
43
  QUERY_SENSOR_STATE = """
44
- query getEndpointState($endpointId: String!, $latencyTolerance: LatencyToleranceValue) {
45
- endpoint(id: $endpointId) {
46
- endpointId: id
47
- features(latencyToleranceValue: $latencyTolerance) {
44
+ fragment EndpointState on Endpoint {
45
+ endpointId: id
46
+ friendlyNameObject { value { text } }
47
+ features {
48
+ name
49
+ properties {
48
50
  name
49
- instance
50
- properties {
51
+ type
52
+ accuracy
53
+ error { type message }
54
+ __typename
55
+ ... on Illuminance {
56
+ illuminanceValue { value }
57
+ timeOfSample
58
+ timeOfLastChange
59
+ }
60
+ ... on Reachability {
61
+ reachabilityStatusValue
62
+ timeOfSample
63
+ timeOfLastChange
64
+ }
65
+ ... on DetectionState {
66
+ detectionStateValue
67
+ timeOfSample
68
+ timeOfLastChange
69
+ }
70
+ ... on TemperatureSensor {
51
71
  name
52
- type
53
- accuracy
54
- error { type message }
55
- __typename
56
- ... on Illuminance {
57
- illuminanceValue { value }
58
- timeOfSample
59
- timeOfLastChange
60
- }
61
- ... on Reachability {
62
- reachabilityStatusValue
63
- timeOfSample
64
- timeOfLastChange
65
- }
66
- ... on DetectionState {
67
- detectionStateValue
68
- timeOfSample
69
- timeOfLastChange
70
- }
71
- ... on TemperatureSensor {
72
- name
73
- value {
74
- value
75
- scale
76
- }
77
- timeOfSample
78
- timeOfLastChange
72
+ value {
73
+ value
74
+ scale
79
75
  }
76
+ timeOfSample
77
+ timeOfLastChange
80
78
  }
81
79
  }
82
80
  }
83
81
  }
82
+
83
+
84
+ query getEndpointState($endpointIds: [String]!) {
85
+ listEndpoints(
86
+ listEndpointsInput: {
87
+ latencyTolerance: LOW,
88
+ endpointIds: $endpointIds,
89
+ includeHouseholdDevices: true
90
+ }
91
+ ) {
92
+ endpoints {
93
+ ...EndpointState
94
+ }
95
+ }
96
+ }
84
97
  """