aioamazondevices 3.0.10__py3-none-any.whl → 3.1.1__py3-none-any.whl

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
  """aioamazondevices library."""
2
2
 
3
- __version__ = "3.0.10"
3
+ __version__ = "3.1.1"
4
4
 
5
5
 
6
6
  from .api import AmazonDevice, AmazonEchoApi
aioamazondevices/api.py CHANGED
@@ -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
- devices: dict[str, Any] = {}
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 := devices.get(dev_serial):
601
- devices[dev_serial] = previous_data | {key: data}
695
+ if previous_data := self._devices.get(dev_serial):
696
+ self._devices[dev_serial] = previous_data | {key: data}
602
697
  else:
603
- devices[dev_serial] = {key: data}
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 devices.values():
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(
aioamazondevices/const.py CHANGED
@@ -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": "None",
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": "None",
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": " Fire TV Stick 4K",
238
+ "model": "Fire TV Stick 4K",
186
239
  "hw_version": "Gen1",
187
240
  },
188
241
  "ATNLRCEBX3W4P": {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: aioamazondevices
3
- Version: 3.0.10
3
+ Version: 3.1.1
4
4
  Summary: Python library to control Amazon devices
5
5
  License: Apache-2.0
6
6
  Author: Simone Chemelli
@@ -0,0 +1,10 @@
1
+ aioamazondevices/__init__.py,sha256=c12OuL7f3dT235WVQ8T1bgMMlc3HGkq8ouiSdLB5pVI,276
2
+ aioamazondevices/api.py,sha256=5usfnZtNvzMiGvb4XcQ6waqoc6FJcLwLGIzBUfcV3Nk,35154
3
+ aioamazondevices/const.py,sha256=DzMYrcChuuz2uxaVbLVdwV3uZB1Db_-33YOPPFDYYVU,6181
4
+ aioamazondevices/exceptions.py,sha256=nPbR928NryTbnxm5QwQpCSpRItvZ3PRYKynUUxH-_v4,1345
5
+ aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
7
+ aioamazondevices-3.1.1.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
8
+ aioamazondevices-3.1.1.dist-info/METADATA,sha256=xf6vS2ibix8CMcmRtDhxUnb6Crvd6DnOh1ZxHKuzsTk,5546
9
+ aioamazondevices-3.1.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
10
+ aioamazondevices-3.1.1.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- aioamazondevices/__init__.py,sha256=Sx20malN92AJBq9P5MCjzVxISDHvKEgS-5sewNLe4NM,277
2
- aioamazondevices/api.py,sha256=92bQze0rzIUONhCmj6nYuv8VBZSTrVWISIfLWSWEvFc,30735
3
- aioamazondevices/const.py,sha256=wn-ZGYaxYLDQTWwTTSRvAd-hKiQBHKmwZ5B_Erf9eEs,4894
4
- aioamazondevices/exceptions.py,sha256=nPbR928NryTbnxm5QwQpCSpRItvZ3PRYKynUUxH-_v4,1345
5
- aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
7
- aioamazondevices-3.0.10.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
8
- aioamazondevices-3.0.10.dist-info/METADATA,sha256=5MlZN_5Riosv2hemLhHht5gjK-KLAje63b4_XqZ1blw,5547
9
- aioamazondevices-3.0.10.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
10
- aioamazondevices-3.0.10.dist-info/RECORD,,