aioamazondevices 3.1.19__py3-none-any.whl → 3.1.23__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.1.19"
3
+ __version__ = "3.1.23"
4
4
 
5
5
 
6
6
  from .api import AmazonDevice, AmazonEchoApi
aioamazondevices/api.py CHANGED
@@ -146,6 +146,15 @@ class AmazonEchoApi:
146
146
  self.session: ClientSession
147
147
  self._devices: dict[str, Any] = {}
148
148
 
149
+ lang_object = Language.make(territory=self._login_country_code.upper())
150
+ lang_maximized = lang_object.maximize()
151
+ self._language = f"{lang_maximized.language}-{lang_maximized.region}"
152
+ _LOGGER.debug(
153
+ "Initialize library with domain <%s> and language <%s>",
154
+ self._domain,
155
+ self._language,
156
+ )
157
+
149
158
  def _load_website_cookies(self) -> dict[str, str]:
150
159
  """Get website cookies, if avaliables."""
151
160
  if not self._login_stored_data:
@@ -210,22 +219,23 @@ class AmazonEchoApi:
210
219
  code_challenge = self._create_s256_code_challenge(code_verifier)
211
220
 
212
221
  oauth_params = {
213
- "openid.oa2.response_type": "code",
214
- "openid.oa2.code_challenge_method": "S256",
215
- "openid.oa2.code_challenge": code_challenge,
216
222
  "openid.return_to": f"https://www.amazon.{self._domain}/ap/maplanding",
223
+ "openid.oa2.code_challenge_method": "S256",
217
224
  "openid.assoc_handle": self._assoc_handle,
218
225
  "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select",
226
+ "pageId": self._assoc_handle,
219
227
  "accountStatusPolicy": "P1",
220
228
  "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select",
221
229
  "openid.mode": "checkid_setup",
222
230
  "openid.ns.oa2": "http://www.amazon.com/ap/ext/oauth/2",
223
231
  "openid.oa2.client_id": f"device:{client_id}",
232
+ "language": self._language.replace("-", "_"),
224
233
  "openid.ns.pape": "http://specs.openid.net/extensions/pape/1.0",
234
+ "openid.oa2.code_challenge": code_challenge,
225
235
  "openid.oa2.scope": "device_auth_access",
226
- "forceMobileLayout": "true",
227
236
  "openid.ns": "http://specs.openid.net/auth/2.0",
228
237
  "openid.pape.max_auth_age": "0",
238
+ "openid.oa2.response_type": "code",
229
239
  }
230
240
 
231
241
  return (
@@ -273,8 +283,10 @@ class AmazonEchoApi:
273
283
  """Create HTTP client session."""
274
284
  if not hasattr(self, "session") or self.session.closed:
275
285
  _LOGGER.debug("Creating HTTP session (aiohttp)")
286
+ headers = DEFAULT_HEADERS
287
+ headers.update({"Accept-Language": self._language})
276
288
  self.session = ClientSession(
277
- headers=DEFAULT_HEADERS,
289
+ headers=headers,
278
290
  cookies=self._cookies,
279
291
  )
280
292
 
@@ -323,6 +335,7 @@ class AmazonEchoApi:
323
335
  )
324
336
 
325
337
  headers = DEFAULT_HEADERS
338
+ headers.update({"Accept-Language": self._language})
326
339
  if self._csrf_cookie and CSRF_COOKIE not in headers:
327
340
  csrf = {CSRF_COOKIE: self._csrf_cookie}
328
341
  _LOGGER.debug("Adding <%s> to headers", csrf)
@@ -479,11 +492,6 @@ class AmazonEchoApi:
479
492
  )
480
493
  raise CannotRegisterDevice(f"{HTTPStatus(resp.status).phrase}: {msg}")
481
494
 
482
- await self._save_to_file(
483
- await resp.text(),
484
- url=register_url,
485
- extension=JSON_EXTENSION,
486
- )
487
495
  success_response = resp_json["response"]["success"]
488
496
 
489
497
  tokens = success_response["tokens"]
@@ -530,16 +538,43 @@ class AmazonEchoApi:
530
538
  location_details = network_detail["locationDetails"]["locationDetails"]
531
539
  default_location = location_details["Default_Location"]
532
540
  amazon_bridge = default_location["amazonBridgeDetails"]["amazonBridgeDetails"]
533
- lambda_bridge = amazon_bridge.get("LambdaBridge_AAA/SonarCloudService")
534
- if not lambda_bridge:
535
- # Some very old devices lack the key for sensors data
536
- return []
537
- appliance_details = lambda_bridge["applianceDetails"]["applianceDetails"]
538
541
 
542
+ # New devices are based on LambdaBridge_AAA structure
543
+ lambda_bridge_aaa = amazon_bridge.get("LambdaBridge_AAA/SonarCloudService")
544
+ appliance_details_aaa = (
545
+ lambda_bridge_aaa["applianceDetails"]["applianceDetails"]
546
+ if lambda_bridge_aaa
547
+ else {}
548
+ )
549
+
550
+ entity_ids_list: list[dict[str, str]] = await self._get_entities_ids(
551
+ appliance_details_aaa, "AAA_SonarCloudService"
552
+ )
553
+
554
+ # Old devices are based on LambdaBridge_AlexaBridge structure
555
+ for bridge_key, bridge_value in amazon_bridge.items():
556
+ if "LambdaBridge_AlexaBridge/" in bridge_key:
557
+ # Value key: "LambdaBridge_AlexaBridge/XXXXXXXXXXXXXX@XXXXXXXXXXXXXX"
558
+ # Value subkey: "AlexaBridge_XXXXXXXXXXXXXX@XXXXXXXXXXXXXX_XXXXXXXXXXXX"
559
+ subkey = bridge_key.split("_")[1].replace("/", "_")
560
+
561
+ appliance_details_alexa = bridge_value["applianceDetails"][
562
+ "applianceDetails"
563
+ ]
564
+ entity_ids_list.extend(
565
+ await self._get_entities_ids(appliance_details_alexa, subkey)
566
+ )
567
+
568
+ return entity_ids_list
569
+
570
+ async def _get_entities_ids(
571
+ self, appliance_details: dict[str, Any], searchkey: str
572
+ ) -> list[dict[str, str]]:
573
+ """Extract entityId and applianceId."""
539
574
  entity_ids_list: list[dict[str, str]] = []
540
- # Process each appliance that starts with AAA_SonarCloudService
575
+ # Process each appliance that starts with "searchkey"
541
576
  for appliance_key, appliance_data in appliance_details.items():
542
- if not appliance_key.startswith("AAA_SonarCloudService"):
577
+ if not appliance_key.startswith(searchkey):
543
578
  continue
544
579
 
545
580
  entity_id = appliance_data["entityId"]
@@ -662,7 +697,7 @@ class AmazonEchoApi:
662
697
  register_device = await self._register_device(device_login_data)
663
698
  self._login_stored_data = register_device
664
699
 
665
- _LOGGER.info("Register device: %s", register_device)
700
+ _LOGGER.info("Register device: %s", scrub_fields(register_device))
666
701
  return register_device
667
702
 
668
703
  async def login_mode_stored_data(self) -> dict[str, Any]:
@@ -704,7 +739,6 @@ class AmazonEchoApi:
704
739
  _LOGGER.debug("Response code: |%s|", response_code)
705
740
 
706
741
  response_data = await raw_resp.text()
707
- _LOGGER.debug("Response data: |%s|", response_data)
708
742
 
709
743
  if not self._csrf_cookie:
710
744
  self._csrf_cookie = raw_resp.cookies.get(CSRF_COOKIE, Morsel()).value
@@ -712,7 +746,7 @@ class AmazonEchoApi:
712
746
 
713
747
  json_data = {} if len(response_data) == 0 else await raw_resp.json()
714
748
 
715
- _LOGGER.debug("JSON data: |%s|", json_data)
749
+ _LOGGER.debug("JSON data: |%s|", scrub_fields(json_data))
716
750
 
717
751
  for data in json_data[key]:
718
752
  dev_serial = data.get("serialNumber") or data.get("deviceSerialNumber")
@@ -821,10 +855,6 @@ class AmazonEchoApi:
821
855
  message_source: AmazonMusicSource | None = None,
822
856
  ) -> None:
823
857
  """Send message to specific device."""
824
- lang_object = Language.make(territory=self._login_country_code.upper())
825
- lang_maximized = lang_object.maximize()
826
- locale = f"{lang_maximized.language}-{lang_maximized.region}"
827
-
828
858
  if not self._login_stored_data:
829
859
  _LOGGER.warning("Trying to send message before login")
830
860
  return
@@ -832,7 +862,7 @@ class AmazonEchoApi:
832
862
  base_payload = {
833
863
  "deviceType": device.device_type,
834
864
  "deviceSerialNumber": device.serial_number,
835
- "locale": locale,
865
+ "locale": self._language,
836
866
  "customerId": device.device_owner_customer_id,
837
867
  }
838
868
 
@@ -867,7 +897,7 @@ class AmazonEchoApi:
867
897
  "expireAfter": "PT5S",
868
898
  "content": [
869
899
  {
870
- "locale": locale,
900
+ "locale": self._language,
871
901
  "display": {
872
902
  "title": "Home Assistant",
873
903
  "body": message_body,
aioamazondevices/const.py CHANGED
@@ -7,11 +7,13 @@ _LOGGER = logging.getLogger(__package__)
7
7
  DEFAULT_ASSOC_HANDLE = "amzn_dp_project_dee_ios"
8
8
 
9
9
  TO_REDACT = {
10
+ "address",
10
11
  "address1",
11
12
  "address2",
12
13
  "address3",
13
14
  "city",
14
15
  "county",
16
+ "customerId",
15
17
  "deviceAccountId",
16
18
  "deviceAddress",
17
19
  "deviceOwnerCustomerId",
@@ -82,7 +84,6 @@ DEFAULT_HEADERS = {
82
84
  ),
83
85
  "Accept-Charset": "utf-8",
84
86
  "Accept-Encoding": "gzip",
85
- "Accept-Language": "en-US",
86
87
  "Connection": "keep-alive",
87
88
  }
88
89
  CSRF_COOKIE = "csrf"
aioamazondevices/utils.py CHANGED
@@ -37,7 +37,9 @@ def scrub_fields(
37
37
  result = {}
38
38
  for k, v in obj.items():
39
39
  # If the key itself is sensitive → overwrite its value
40
- if k in field_names:
40
+ if k == "email":
41
+ result[k] = obfuscate_email(v)
42
+ elif k in field_names:
41
43
  result[k] = replacement
42
44
  else:
43
45
  # Otherwise keep walking
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: aioamazondevices
3
- Version: 3.1.19
3
+ Version: 3.1.23
4
4
  Summary: Python library to control Amazon devices
5
5
  License: Apache-2.0
6
6
  Author: Simone Chemelli
@@ -0,0 +1,11 @@
1
+ aioamazondevices/__init__.py,sha256=mZIaRiUx4hb3bx5kIhZc9PX7hxD-qnhod-h81ENTXac,277
2
+ aioamazondevices/api.py,sha256=J4e85fBrHIWPeTvP7TYsezvdHKQ0I_Pqz3HCcdmF6J8,37542
3
+ aioamazondevices/const.py,sha256=J47aHAfoA6rRgHDvn-q_S4xp8MrC6O1rEk1ZeRnN-8E,8529
4
+ aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
5
+ aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
7
+ aioamazondevices/utils.py,sha256=RzuKRhnq_8ymCoJMoQJ2vBYyuew06RSWpqQWmqdNczE,2019
8
+ aioamazondevices-3.1.23.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
9
+ aioamazondevices-3.1.23.dist-info/METADATA,sha256=xEheLDnUfjp1pQbgAMvDsWmOcG5xnDnU8eZfmYSWg4A,5235
10
+ aioamazondevices-3.1.23.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
+ aioamazondevices-3.1.23.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- aioamazondevices/__init__.py,sha256=yYJH7153YmQfYcpIzSJNgHgxNQI7bZK5Aq0emVmfVQg,277
2
- aioamazondevices/api.py,sha256=7IJF_bOSs0C1fLKeOR2Y87qyADlfGEGWlihZ2vlLaL8,36250
3
- aioamazondevices/const.py,sha256=KQbHCOvzBTcWMc3O-kLR72wJJDBbrFK9dPHJVEPMY4M,8528
4
- aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
5
- aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
7
- aioamazondevices/utils.py,sha256=1PrzAtQHigN2rGxdMVPKzbjOnwh-MLc9YWkQaVQIHT4,1941
8
- aioamazondevices-3.1.19.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
9
- aioamazondevices-3.1.19.dist-info/METADATA,sha256=eOPZwC2lraH2xYJgydkqHCnPoe96hYBy0Qmua9AltY8,5235
10
- aioamazondevices-3.1.19.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
- aioamazondevices-3.1.19.dist-info/RECORD,,