aioamazondevices 3.0.10__tar.gz → 3.1.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.
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/PKG-INFO +1 -1
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/pyproject.toml +1 -1
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/__init__.py +1 -1
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/api.py +114 -5
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/const.py +56 -3
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/LICENSE +0 -0
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/README.md +0 -0
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/exceptions.py +0 -0
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/py.typed +0 -0
- {aioamazondevices-3.0.10 → aioamazondevices-3.1.1}/src/aioamazondevices/sounds.py +0 -0
@@ -42,9 +42,13 @@ from .const import (
|
|
42
42
|
NODE_BLUETOOTH,
|
43
43
|
NODE_DEVICES,
|
44
44
|
NODE_DO_NOT_DISTURB,
|
45
|
+
NODE_IDENTIFIER,
|
45
46
|
NODE_PREFERENCES,
|
46
47
|
SAVE_PATH,
|
48
|
+
SENSORS,
|
49
|
+
URI_IDS,
|
47
50
|
URI_QUERIES,
|
51
|
+
URI_SENSORS,
|
48
52
|
)
|
49
53
|
from .exceptions import (
|
50
54
|
CannotAuthenticate,
|
@@ -54,6 +58,15 @@ from .exceptions import (
|
|
54
58
|
)
|
55
59
|
|
56
60
|
|
61
|
+
@dataclass
|
62
|
+
class AmazonDeviceSensor:
|
63
|
+
"""Amazon device sensor class."""
|
64
|
+
|
65
|
+
name: str
|
66
|
+
value: Any
|
67
|
+
scale: str | None
|
68
|
+
|
69
|
+
|
57
70
|
@dataclass
|
58
71
|
class AmazonDevice:
|
59
72
|
"""Amazon device class."""
|
@@ -70,6 +83,9 @@ class AmazonDevice:
|
|
70
83
|
do_not_disturb: bool
|
71
84
|
response_style: str | None
|
72
85
|
bluetooth_state: bool
|
86
|
+
entity_id: str
|
87
|
+
appliance_id: str
|
88
|
+
sensors: dict[str, AmazonDeviceSensor]
|
73
89
|
|
74
90
|
|
75
91
|
class AmazonSequenceType(StrEnum):
|
@@ -125,6 +141,7 @@ class AmazonEchoApi:
|
|
125
141
|
self._list_for_clusters: dict[str, str] = {}
|
126
142
|
|
127
143
|
self.session: ClientSession
|
144
|
+
self._devices: dict[str, Any] = {}
|
128
145
|
|
129
146
|
def _load_website_cookies(self) -> dict[str, str]:
|
130
147
|
"""Get website cookies, if avaliables."""
|
@@ -485,6 +502,84 @@ class AmazonEchoApi:
|
|
485
502
|
await self._save_to_file(login_data, "login_data", JSON_EXTENSION)
|
486
503
|
return login_data
|
487
504
|
|
505
|
+
async def _get_devices_ids(self) -> list[dict[str, str]]:
|
506
|
+
"""Retrieve devices entityId and applianceId."""
|
507
|
+
_, raw_resp = await self._session_request(
|
508
|
+
"GET",
|
509
|
+
url=f"https://alexa.amazon.{self._domain}{URI_IDS}",
|
510
|
+
)
|
511
|
+
json_data = await raw_resp.json()
|
512
|
+
|
513
|
+
network_detail = orjson.loads(json_data["networkDetail"])
|
514
|
+
# Navigate through the nested structure step by step
|
515
|
+
location_details = network_detail["locationDetails"]["locationDetails"]
|
516
|
+
default_location = location_details["Default_Location"]
|
517
|
+
amazon_bridge = default_location["amazonBridgeDetails"]["amazonBridgeDetails"]
|
518
|
+
lambda_bridge = amazon_bridge["LambdaBridge_AAA/SonarCloudService"]
|
519
|
+
appliance_details = lambda_bridge["applianceDetails"]["applianceDetails"]
|
520
|
+
|
521
|
+
entity_ids_list: list[dict[str, str]] = []
|
522
|
+
# Process each appliance that starts with AAA_SonarCloudService
|
523
|
+
for appliance_key, appliance_data in appliance_details.items():
|
524
|
+
if not appliance_key.startswith("AAA_SonarCloudService"):
|
525
|
+
continue
|
526
|
+
|
527
|
+
entity_id = appliance_data["entityId"]
|
528
|
+
appliance_id = appliance_data["applianceId"]
|
529
|
+
|
530
|
+
# Create identifier object for this appliance
|
531
|
+
identifier = {
|
532
|
+
"entityId": entity_id,
|
533
|
+
"applianceId": appliance_id,
|
534
|
+
}
|
535
|
+
|
536
|
+
# Update device information for each device in the identifier list
|
537
|
+
for device_identifier in appliance_data["alexaDeviceIdentifierList"]:
|
538
|
+
serial_number = device_identifier["dmsDeviceSerialNumber"]
|
539
|
+
|
540
|
+
# Add identifier information to the device
|
541
|
+
self._devices[serial_number] |= {NODE_IDENTIFIER: identifier}
|
542
|
+
|
543
|
+
# Add to entity IDs list for sensor retrieval
|
544
|
+
entity_ids_list.append({"entityId": entity_id, "entityType": "ENTITY"})
|
545
|
+
|
546
|
+
return entity_ids_list
|
547
|
+
|
548
|
+
async def _get_sensors_states(
|
549
|
+
self, entity_ids_list: list[dict[str, str]]
|
550
|
+
) -> dict[str, dict[str, AmazonDeviceSensor]]:
|
551
|
+
"""Retrieve devices sensors states."""
|
552
|
+
_data = {"stateRequests": entity_ids_list}
|
553
|
+
_, raw_resp = await self._session_request(
|
554
|
+
"POST",
|
555
|
+
url=f"https://alexa.amazon.{self._domain}{URI_SENSORS}",
|
556
|
+
input_data=_data,
|
557
|
+
json_data=True,
|
558
|
+
)
|
559
|
+
json_data = await raw_resp.json()
|
560
|
+
|
561
|
+
final_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
|
562
|
+
for sensors in json_data["deviceStates"]:
|
563
|
+
_id = sensors["entity"]["entityId"]
|
564
|
+
dict_sensors: dict[str, AmazonDeviceSensor] = {}
|
565
|
+
for sensor in sensors["capabilityStates"]:
|
566
|
+
sensor_json = orjson.loads(sensor)
|
567
|
+
if sensor_json["name"] in SENSORS:
|
568
|
+
_value = sensor_json["value"]
|
569
|
+
_value_dict = isinstance(_value, dict)
|
570
|
+
_name = sensor_json["name"]
|
571
|
+
dict_sensors.update(
|
572
|
+
{
|
573
|
+
_name: AmazonDeviceSensor(
|
574
|
+
name=_name,
|
575
|
+
value=(_value["value"] if _value_dict else _value),
|
576
|
+
scale=_value.get("scale") if _value_dict else None,
|
577
|
+
)
|
578
|
+
}
|
579
|
+
)
|
580
|
+
final_sensors.update({_id: dict_sensors})
|
581
|
+
return final_sensors
|
582
|
+
|
488
583
|
async def login_mode_interactive(self, otp_code: str) -> dict[str, Any]:
|
489
584
|
"""Login to Amazon interactively via OTP."""
|
490
585
|
_LOGGER.debug("Logging-in for %s [otp code %s]", self._login_email, otp_code)
|
@@ -574,7 +669,7 @@ class AmazonEchoApi:
|
|
574
669
|
self,
|
575
670
|
) -> dict[str, AmazonDevice]:
|
576
671
|
"""Get Amazon devices data."""
|
577
|
-
|
672
|
+
self._devices = {}
|
578
673
|
for key in URI_QUERIES:
|
579
674
|
_, raw_resp = await self._session_request(
|
580
675
|
method=HTTPMethod.GET,
|
@@ -597,17 +692,28 @@ class AmazonEchoApi:
|
|
597
692
|
|
598
693
|
for data in json_data[key]:
|
599
694
|
dev_serial = data.get("serialNumber") or data.get("deviceSerialNumber")
|
600
|
-
if previous_data :=
|
601
|
-
|
695
|
+
if previous_data := self._devices.get(dev_serial):
|
696
|
+
self._devices[dev_serial] = previous_data | {key: data}
|
602
697
|
else:
|
603
|
-
|
698
|
+
self._devices[dev_serial] = {key: data}
|
699
|
+
|
700
|
+
entity_ids_list = await self._get_devices_ids()
|
701
|
+
devices_sensors = await self._get_sensors_states(entity_ids_list)
|
604
702
|
|
605
703
|
final_devices_list: dict[str, AmazonDevice] = {}
|
606
|
-
for device in
|
704
|
+
for device in self._devices.values():
|
607
705
|
devices_node = device[NODE_DEVICES]
|
608
706
|
preferences_node = device.get(NODE_PREFERENCES)
|
609
707
|
do_not_disturb_node = device[NODE_DO_NOT_DISTURB]
|
610
708
|
bluetooth_node = device[NODE_BLUETOOTH]
|
709
|
+
identifier_node = device.get(NODE_IDENTIFIER, {})
|
710
|
+
|
711
|
+
# Add sensors
|
712
|
+
if identifier_node:
|
713
|
+
for _device_id, _device_sensors in devices_sensors.items():
|
714
|
+
if _device_id == identifier_node["entityId"]:
|
715
|
+
sensors = _device_sensors
|
716
|
+
|
611
717
|
# Remove stale, orphaned and virtual devices
|
612
718
|
if (
|
613
719
|
NODE_DEVICES not in device
|
@@ -633,6 +739,9 @@ class AmazonEchoApi:
|
|
633
739
|
preferences_node["responseStyle"] if preferences_node else None
|
634
740
|
),
|
635
741
|
bluetooth_state=bluetooth_node["online"],
|
742
|
+
entity_id=identifier_node.get("entityId"),
|
743
|
+
appliance_id=identifier_node.get("applianceId"),
|
744
|
+
sensors=sensors,
|
636
745
|
)
|
637
746
|
|
638
747
|
self._list_for_clusters.update(
|
@@ -51,20 +51,45 @@ NODE_DEVICES = "devices"
|
|
51
51
|
NODE_DO_NOT_DISTURB = "doNotDisturbDeviceStatusList"
|
52
52
|
NODE_PREFERENCES = "devicePreferences"
|
53
53
|
NODE_BLUETOOTH = "bluetoothStates"
|
54
|
+
NODE_IDENTIFIER = "identifier"
|
55
|
+
NODE_SENSORS = "sensors"
|
54
56
|
|
55
57
|
URI_QUERIES = {
|
56
58
|
NODE_DEVICES: "/api/devices-v2/device",
|
57
59
|
NODE_DO_NOT_DISTURB: "/api/dnd/device-status-list",
|
58
60
|
NODE_PREFERENCES: "/api/device-preferences",
|
59
61
|
NODE_BLUETOOTH: "/api/bluetooth",
|
62
|
+
# "/api/ping"
|
63
|
+
# "/api/np/command"
|
64
|
+
# "/api/np/player"
|
65
|
+
# "/api/device-wifi-details"
|
66
|
+
# "/api/activities"
|
67
|
+
# "/api/behaviors/v2/automations"
|
68
|
+
# "/api/notifications"
|
60
69
|
}
|
61
70
|
|
71
|
+
URI_IDS = "/api/phoenix"
|
72
|
+
URI_SENSORS = "/api/phoenix/state"
|
73
|
+
|
74
|
+
SENSORS = [
|
75
|
+
"babyCryDetectionState",
|
76
|
+
"beepingApplianceDetectionState",
|
77
|
+
"coughDetectionState",
|
78
|
+
"dogBarkDetectionState",
|
79
|
+
"humanPresenceDetectionState",
|
80
|
+
"illuminance",
|
81
|
+
"temperature",
|
82
|
+
"waterSoundsDetectionState",
|
83
|
+
]
|
84
|
+
SENSOR_STATE_OFF = "NOT_DETECTED"
|
85
|
+
|
62
86
|
# File extensions
|
63
87
|
SAVE_PATH = "out"
|
64
88
|
HTML_EXTENSION = ".html"
|
65
89
|
JSON_EXTENSION = ".json"
|
66
90
|
BIN_EXTENSION = ".bin"
|
67
91
|
|
92
|
+
SPEAKER_GROUP_FAMILY = "WHA"
|
68
93
|
SPEAKER_GROUP_MODEL = "Speaker Group"
|
69
94
|
|
70
95
|
DEVICE_TO_IGNORE: list[str] = [
|
@@ -81,6 +106,10 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
81
106
|
"model": "Echo Show 5",
|
82
107
|
"hw_version": "Gen3",
|
83
108
|
},
|
109
|
+
"A15996VY63BQ2D": {
|
110
|
+
"model": "Echo Show 8",
|
111
|
+
"hw_version": "Gen2",
|
112
|
+
},
|
84
113
|
"A1Q6UGEXJZWJQ0": {
|
85
114
|
"model": "Fire TV Stick 4K",
|
86
115
|
"hw_version": "Gen2",
|
@@ -89,10 +118,26 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
89
118
|
"model": "Echo Dot",
|
90
119
|
"hw_version": "Gen3",
|
91
120
|
},
|
121
|
+
"A1TD5Z1R8IWBHA ": {
|
122
|
+
"model": "Fire HD 8",
|
123
|
+
"hw_version": "Gen12",
|
124
|
+
},
|
125
|
+
"A1VGB7MHSIEYFK": {
|
126
|
+
"model": "Fire TV Cube",
|
127
|
+
"hw_version": "Gen3",
|
128
|
+
},
|
129
|
+
"A1WZKXFLI43K86": {
|
130
|
+
"model": "FireTV 4k MAX",
|
131
|
+
"hw_version": "Gen2",
|
132
|
+
},
|
92
133
|
"A1Z88NGR2BK6A2": {
|
93
134
|
"model": "Echo Show 8",
|
94
135
|
"hw_version": "Gen1",
|
95
136
|
},
|
137
|
+
"A265XOI9586NML": {
|
138
|
+
"model": "Fire TV Stick with Alexa Voice Remote",
|
139
|
+
"hw_version": None,
|
140
|
+
},
|
96
141
|
"A271DR1789MXDS": {
|
97
142
|
"model": "Fire Tablet 7",
|
98
143
|
"hw_version": "Gen12",
|
@@ -143,7 +188,11 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
143
188
|
},
|
144
189
|
"A3C9PE6TNYLTCH": {
|
145
190
|
"model": "Speaker Group",
|
146
|
-
"hw_version":
|
191
|
+
"hw_version": None,
|
192
|
+
},
|
193
|
+
"A3EVMLQTU6WL1W": {
|
194
|
+
"model": "FireTV 4k MAX",
|
195
|
+
"hw_version": "Gen1",
|
147
196
|
},
|
148
197
|
"A3RMGO6LYLH7YN": {
|
149
198
|
"model": "Echo Dot",
|
@@ -155,7 +204,7 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
155
204
|
},
|
156
205
|
"A3VRME03NAXFUB": {
|
157
206
|
"model": "Echo Flex",
|
158
|
-
"hw_version":
|
207
|
+
"hw_version": None,
|
159
208
|
},
|
160
209
|
"A4ZP7ZC4PI6TO": {
|
161
210
|
"model": "Echo Show 3",
|
@@ -173,6 +222,10 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
173
222
|
"model": "Echo Dot",
|
174
223
|
"hw_version": "Gen2",
|
175
224
|
},
|
225
|
+
"ADVBD696BHNV5": {
|
226
|
+
"model": "Fire TV Stick",
|
227
|
+
"hw_version": "Gen1",
|
228
|
+
},
|
176
229
|
"AIPK7MM90V7TB": {
|
177
230
|
"model": "Echo Show 10",
|
178
231
|
"hw_version": "Gen3",
|
@@ -182,7 +235,7 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
182
235
|
"hw_version": "Gen1",
|
183
236
|
},
|
184
237
|
"AKPGW064GI9HE": {
|
185
|
-
"model": "
|
238
|
+
"model": "Fire TV Stick 4K",
|
186
239
|
"hw_version": "Gen1",
|
187
240
|
},
|
188
241
|
"ATNLRCEBX3W4P": {
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|