aioamazondevices 6.5.0__tar.gz → 6.5.2__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.
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/PKG-INFO +1 -1
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/pyproject.toml +1 -1
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/__init__.py +1 -1
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/api.py +71 -56
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/const.py +2 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/query.py +46 -33
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/LICENSE +0 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/README.md +0 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/exceptions.py +0 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/py.typed +0 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/sounds.py +0 -0
- {aioamazondevices-6.5.0 → aioamazondevices-6.5.2}/src/aioamazondevices/utils.py +0 -0
|
@@ -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,
|
|
@@ -61,6 +62,7 @@ from .const import (
|
|
|
61
62
|
REQUEST_AGENT,
|
|
62
63
|
SAVE_PATH,
|
|
63
64
|
SENSORS,
|
|
65
|
+
SPEAKER_GROUP_FAMILY,
|
|
64
66
|
URI_DEVICES,
|
|
65
67
|
URI_DND,
|
|
66
68
|
URI_NEXUS_GRAPHQL,
|
|
@@ -606,20 +608,19 @@ class AmazonEchoApi:
|
|
|
606
608
|
_LOGGER.info("Register device: %s", scrub_fields(login_data))
|
|
607
609
|
return login_data
|
|
608
610
|
|
|
609
|
-
async def
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
611
|
+
async def _get_sensors_states(self) -> dict[str, dict[str, AmazonDeviceSensor]]:
|
|
612
|
+
"""Retrieve devices sensors states."""
|
|
613
|
+
devices_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
|
|
614
|
+
|
|
615
|
+
endpoint_ids = list(self._endpoints.keys())
|
|
613
616
|
payload = [
|
|
614
617
|
{
|
|
615
618
|
"operationName": "getEndpointState",
|
|
616
619
|
"variables": {
|
|
617
|
-
"
|
|
618
|
-
"latencyTolerance": "LOW",
|
|
620
|
+
"endpointIds": endpoint_ids,
|
|
619
621
|
},
|
|
620
622
|
"query": QUERY_SENSOR_STATE,
|
|
621
623
|
}
|
|
622
|
-
for endpoint_id in endpoint_id_list
|
|
623
624
|
]
|
|
624
625
|
|
|
625
626
|
_, raw_resp = await self._session_request(
|
|
@@ -629,47 +630,29 @@ class AmazonEchoApi:
|
|
|
629
630
|
json_data=True,
|
|
630
631
|
)
|
|
631
632
|
|
|
632
|
-
|
|
633
|
+
sensors_state = await self._response_to_json(raw_resp)
|
|
634
|
+
_LOGGER.debug("Sensor data - %s", sensors_state)
|
|
633
635
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
636
|
+
if await self._format_human_error(sensors_state):
|
|
637
|
+
# Explicit error in returned data
|
|
638
|
+
return {}
|
|
637
639
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
640
|
+
if (
|
|
641
|
+
not (arr := sensors_state.get(ARRAY_WRAPPER))
|
|
642
|
+
or not (data := arr[0].get("data"))
|
|
643
|
+
or not (endpoints_list := data.get("listEndpoints"))
|
|
644
|
+
or not (endpoints := endpoints_list.get("endpoints"))
|
|
645
|
+
):
|
|
646
|
+
_LOGGER.error("Malformed sensor state data received: %s", sensors_state)
|
|
647
|
+
return {}
|
|
644
648
|
|
|
645
|
-
|
|
646
|
-
|
|
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 {}
|
|
649
|
+
for endpoint in endpoints:
|
|
650
|
+
serial_number = self._endpoints[endpoint.get("endpointId")]
|
|
656
651
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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")]
|
|
668
|
-
|
|
669
|
-
if serial_number in self._final_devices:
|
|
670
|
-
devices_sensors[serial_number] = self._get_device_sensor_state(
|
|
671
|
-
endpoint, serial_number
|
|
672
|
-
)
|
|
652
|
+
if serial_number in self._final_devices:
|
|
653
|
+
devices_sensors[serial_number] = self._get_device_sensor_state(
|
|
654
|
+
endpoint, serial_number
|
|
655
|
+
)
|
|
673
656
|
|
|
674
657
|
return devices_sensors
|
|
675
658
|
|
|
@@ -730,14 +713,16 @@ class AmazonEchoApi:
|
|
|
730
713
|
_LOGGER.debug(
|
|
731
714
|
"error in sensor %s - %s - %s", name, error_type, error_msg
|
|
732
715
|
)
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
716
|
+
|
|
717
|
+
if error_type != "NOT_FOUND":
|
|
718
|
+
device_sensors[name] = AmazonDeviceSensor(
|
|
719
|
+
name,
|
|
720
|
+
value,
|
|
721
|
+
error,
|
|
722
|
+
error_type,
|
|
723
|
+
error_msg,
|
|
724
|
+
scale,
|
|
725
|
+
)
|
|
741
726
|
|
|
742
727
|
return device_sensors
|
|
743
728
|
|
|
@@ -758,7 +743,7 @@ class AmazonEchoApi:
|
|
|
758
743
|
endpoint_data = await self._response_to_json(raw_resp)
|
|
759
744
|
|
|
760
745
|
if not (data := endpoint_data.get("data")) or not data.get("listEndpoints"):
|
|
761
|
-
|
|
746
|
+
await self._format_human_error(endpoint_data)
|
|
762
747
|
return {}
|
|
763
748
|
|
|
764
749
|
endpoints = data["listEndpoints"]
|
|
@@ -782,6 +767,10 @@ class AmazonEchoApi:
|
|
|
782
767
|
if not data:
|
|
783
768
|
_LOGGER.warning("Empty JSON data received")
|
|
784
769
|
data = {}
|
|
770
|
+
if isinstance(data, list):
|
|
771
|
+
# if anonymous array is returned wrap it inside
|
|
772
|
+
# generated key to convert list to dict
|
|
773
|
+
data = {ARRAY_WRAPPER: data}
|
|
785
774
|
return cast("dict[str, Any]", data)
|
|
786
775
|
except ContentTypeError as exc:
|
|
787
776
|
raise ValueError("Response not in JSON format") from exc
|
|
@@ -1153,7 +1142,9 @@ class AmazonEchoApi:
|
|
|
1153
1142
|
else:
|
|
1154
1143
|
for device_sensor in device.sensors.values():
|
|
1155
1144
|
device_sensor.error = True
|
|
1156
|
-
if
|
|
1145
|
+
if (
|
|
1146
|
+
device_dnd := dnd_sensors.get(device.serial_number)
|
|
1147
|
+
) and device.device_family != SPEAKER_GROUP_FAMILY:
|
|
1157
1148
|
device.sensors["dnd"] = device_dnd
|
|
1158
1149
|
|
|
1159
1150
|
# Update notifications
|
|
@@ -1222,11 +1213,20 @@ class AmazonEchoApi:
|
|
|
1222
1213
|
if not device or (device.get("deviceType") in DEVICE_TO_IGNORE):
|
|
1223
1214
|
continue
|
|
1224
1215
|
|
|
1216
|
+
account_name: str = device["accountName"]
|
|
1217
|
+
capabilities: list[str] = device["capabilities"]
|
|
1218
|
+
# Skip devices that cannot be used with voice features
|
|
1219
|
+
if "MICROPHONE" not in capabilities:
|
|
1220
|
+
_LOGGER.debug(
|
|
1221
|
+
"Skipping device without microphone capabilities: %s", account_name
|
|
1222
|
+
)
|
|
1223
|
+
continue
|
|
1224
|
+
|
|
1225
1225
|
serial_number: str = device["serialNumber"]
|
|
1226
1226
|
|
|
1227
1227
|
final_devices_list[serial_number] = AmazonDevice(
|
|
1228
|
-
account_name=
|
|
1229
|
-
capabilities=
|
|
1228
|
+
account_name=account_name,
|
|
1229
|
+
capabilities=capabilities,
|
|
1230
1230
|
device_family=device["deviceFamily"],
|
|
1231
1231
|
device_type=device["deviceType"],
|
|
1232
1232
|
device_owner_customer_id=device["deviceOwnerCustomerId"],
|
|
@@ -1576,3 +1576,18 @@ class AmazonEchoApi:
|
|
|
1576
1576
|
scale=None,
|
|
1577
1577
|
)
|
|
1578
1578
|
return dnd_status
|
|
1579
|
+
|
|
1580
|
+
async def _format_human_error(self, sensors_state: dict) -> bool:
|
|
1581
|
+
"""Format human readable error from malformed data."""
|
|
1582
|
+
if sensors_state.get(ARRAY_WRAPPER):
|
|
1583
|
+
error = sensors_state[ARRAY_WRAPPER][0].get("errors", [])
|
|
1584
|
+
else:
|
|
1585
|
+
error = sensors_state.get("errors", [])
|
|
1586
|
+
|
|
1587
|
+
if not error:
|
|
1588
|
+
return False
|
|
1589
|
+
|
|
1590
|
+
msg = error[0].get("message", "Unknown error")
|
|
1591
|
+
path = error[0].get("path", "Unknown path")
|
|
1592
|
+
_LOGGER.error("Error retrieving devices state: %s for path %s", msg, path)
|
|
1593
|
+
return True
|
|
@@ -41,44 +41,57 @@ query getDevicesBaseData {
|
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
43
|
QUERY_SENSOR_STATE = """
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
fragment EndpointState on Endpoint {
|
|
45
|
+
endpointId: id
|
|
46
|
+
friendlyNameObject { value { text } }
|
|
47
|
+
features {
|
|
48
|
+
name
|
|
49
|
+
properties {
|
|
48
50
|
name
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|