aioamazondevices 6.5.4__tar.gz → 8.0.0__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.
Files changed (18) hide show
  1. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/PKG-INFO +10 -4
  2. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/README.md +9 -3
  3. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/pyproject.toml +1 -1
  4. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/src/aioamazondevices/__init__.py +1 -1
  5. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/src/aioamazondevices/api.py +42 -139
  6. aioamazondevices-8.0.0/src/aioamazondevices/const/__init__.py +1 -0
  7. aioamazondevices-8.0.0/src/aioamazondevices/const/common.py +26 -0
  8. aioamazondevices-6.5.4/src/aioamazondevices/const.py → aioamazondevices-8.0.0/src/aioamazondevices/const/devices.py +2 -169
  9. aioamazondevices-8.0.0/src/aioamazondevices/const/http.py +36 -0
  10. aioamazondevices-8.0.0/src/aioamazondevices/const/metadata.py +44 -0
  11. aioamazondevices-6.5.4/src/aioamazondevices/query.py → aioamazondevices-8.0.0/src/aioamazondevices/const/queries.py +1 -1
  12. aioamazondevices-8.0.0/src/aioamazondevices/const/schedules.py +61 -0
  13. {aioamazondevices-6.5.4/src/aioamazondevices → aioamazondevices-8.0.0/src/aioamazondevices/const}/sounds.py +2 -1
  14. aioamazondevices-8.0.0/src/aioamazondevices/structures.py +65 -0
  15. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/src/aioamazondevices/utils.py +1 -1
  16. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/LICENSE +0 -0
  17. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/src/aioamazondevices/exceptions.py +0 -0
  18. {aioamazondevices-6.5.4 → aioamazondevices-8.0.0}/src/aioamazondevices/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aioamazondevices
3
- Version: 6.5.4
3
+ Version: 8.0.0
4
4
  Summary: Python library to control Amazon devices
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -81,7 +81,6 @@ The script accept command line arguments or a library_test.json config file:
81
81
  "single_device_name": "Echo Dot Livingroom",
82
82
  "cluster_device_name": "Everywhere",
83
83
  "login_data_file": "out/login_data.json",
84
- "save_raw_data": true,
85
84
  "test": true
86
85
  }
87
86
  ```
@@ -142,6 +141,15 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
142
141
  <sub><b>Flo</b></sub>
143
142
  </a>
144
143
  </td>
144
+ <td align="center">
145
+ <a href="https://github.com/francescolf">
146
+ <img src="https://avatars.githubusercontent.com/u/14892143?v=4" width="100;" alt="francescolf"/>
147
+ <br />
148
+ <sub><b>Francesco Lo Faro</b></sub>
149
+ </a>
150
+ </td>
151
+ </tr>
152
+ <tr>
145
153
  <td align="center">
146
154
  <a href="https://github.com/lchavezcuu">
147
155
  <img src="https://avatars.githubusercontent.com/u/22165856?v=4" width="100;" alt="lchavezcuu"/>
@@ -149,8 +157,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
149
157
  <sub><b>Luis Chavez</b></sub>
150
158
  </a>
151
159
  </td>
152
- </tr>
153
- <tr>
154
160
  <td align="center">
155
161
  <a href="https://github.com/maxmati">
156
162
  <img src="https://avatars.githubusercontent.com/u/509560?v=4" width="100;" alt="maxmati"/>
@@ -56,7 +56,6 @@ The script accept command line arguments or a library_test.json config file:
56
56
  "single_device_name": "Echo Dot Livingroom",
57
57
  "cluster_device_name": "Everywhere",
58
58
  "login_data_file": "out/login_data.json",
59
- "save_raw_data": true,
60
59
  "test": true
61
60
  }
62
61
  ```
@@ -117,6 +116,15 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
117
116
  <sub><b>Flo</b></sub>
118
117
  </a>
119
118
  </td>
119
+ <td align="center">
120
+ <a href="https://github.com/francescolf">
121
+ <img src="https://avatars.githubusercontent.com/u/14892143?v=4" width="100;" alt="francescolf"/>
122
+ <br />
123
+ <sub><b>Francesco Lo Faro</b></sub>
124
+ </a>
125
+ </td>
126
+ </tr>
127
+ <tr>
120
128
  <td align="center">
121
129
  <a href="https://github.com/lchavezcuu">
122
130
  <img src="https://avatars.githubusercontent.com/u/22165856?v=4" width="100;" alt="lchavezcuu"/>
@@ -124,8 +132,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
124
132
  <sub><b>Luis Chavez</b></sub>
125
133
  </a>
126
134
  </td>
127
- </tr>
128
- <tr>
129
135
  <td align="center">
130
136
  <a href="https://github.com/maxmati">
131
137
  <img src="https://avatars.githubusercontent.com/u/509560?v=4" width="100;" alt="maxmati"/>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aioamazondevices"
3
- version = "6.5.4"
3
+ version = "8.0.0"
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.4"
3
+ __version__ = "8.0.0"
4
4
 
5
5
 
6
6
  from .api import AmazonDevice, AmazonEchoApi
@@ -3,15 +3,12 @@
3
3
  import asyncio
4
4
  import base64
5
5
  import hashlib
6
- import mimetypes
7
6
  import secrets
8
7
  import uuid
9
- from dataclasses import dataclass
8
+ from collections.abc import Callable, Coroutine
10
9
  from datetime import UTC, datetime, timedelta
11
- from enum import StrEnum
12
10
  from http import HTTPMethod, HTTPStatus
13
11
  from http.cookies import Morsel
14
- from pathlib import Path
15
12
  from typing import Any, cast
16
13
  from urllib.parse import parse_qs, urlencode
17
14
 
@@ -30,9 +27,13 @@ from multidict import MultiDictProxy
30
27
  from yarl import URL
31
28
 
32
29
  from . import __version__
33
- from .const import (
34
- _LOGGER,
35
- ALEXA_INFO_SKILLS,
30
+ from .const.common import _LOGGER
31
+ from .const.devices import (
32
+ DEVICE_TO_IGNORE,
33
+ DEVICE_TYPE_TO_MODEL,
34
+ SPEAKER_GROUP_FAMILY,
35
+ )
36
+ from .const.http import (
36
37
  AMAZON_APP_BUNDLE_ID,
37
38
  AMAZON_APP_ID,
38
39
  AMAZON_APP_NAME,
@@ -41,34 +42,30 @@ from .const import (
41
42
  AMAZON_DEVICE_SOFTWARE_VERSION,
42
43
  AMAZON_DEVICE_TYPE,
43
44
  ARRAY_WRAPPER,
44
- BIN_EXTENSION,
45
- COUNTRY_GROUPS,
46
45
  CSRF_COOKIE,
47
46
  DEFAULT_HEADERS,
48
47
  DEFAULT_SITE,
49
- DEVICE_TO_IGNORE,
50
- DEVICE_TYPE_TO_MODEL,
51
- HTML_EXTENSION,
52
48
  HTTP_ERROR_199,
53
49
  HTTP_ERROR_299,
54
- JSON_EXTENSION,
55
- NOTIFICATION_ALARM,
56
- NOTIFICATION_MUSIC_ALARM,
57
- NOTIFICATION_REMINDER,
58
- NOTIFICATION_TIMER,
59
- NOTIFICATIONS_SUPPORTED,
60
- RECURRING_PATTERNS,
61
50
  REFRESH_ACCESS_TOKEN,
62
51
  REFRESH_AUTH_COOKIES,
63
52
  REQUEST_AGENT,
64
- SAVE_PATH,
65
- SENSORS,
66
- SPEAKER_GROUP_FAMILY,
67
53
  URI_DEVICES,
68
54
  URI_DND,
69
55
  URI_NEXUS_GRAPHQL,
70
56
  URI_NOTIFICATIONS,
71
57
  URI_SIGNIN,
58
+ )
59
+ from .const.metadata import ALEXA_INFO_SKILLS, SENSORS
60
+ from .const.queries import QUERY_DEVICE_DATA, QUERY_SENSOR_STATE
61
+ from .const.schedules import (
62
+ COUNTRY_GROUPS,
63
+ NOTIFICATION_ALARM,
64
+ NOTIFICATION_MUSIC_ALARM,
65
+ NOTIFICATION_REMINDER,
66
+ NOTIFICATION_TIMER,
67
+ NOTIFICATIONS_SUPPORTED,
68
+ RECURRING_PATTERNS,
72
69
  WEEKEND_EXCEPTIONS,
73
70
  )
74
71
  from .exceptions import (
@@ -78,70 +75,16 @@ from .exceptions import (
78
75
  CannotRetrieveData,
79
76
  WrongMethod,
80
77
  )
81
- from .query import QUERY_DEVICE_DATA, QUERY_SENSOR_STATE
78
+ from .structures import (
79
+ AmazonDevice,
80
+ AmazonDeviceSensor,
81
+ AmazonMusicSource,
82
+ AmazonSchedule,
83
+ AmazonSequenceType,
84
+ )
82
85
  from .utils import obfuscate_email, scrub_fields
83
86
 
84
87
 
85
- @dataclass
86
- class AmazonDeviceSensor:
87
- """Amazon device sensor class."""
88
-
89
- name: str
90
- value: str | int | float
91
- error: bool
92
- error_type: str | None
93
- error_msg: str | None
94
- scale: str | None
95
-
96
-
97
- @dataclass
98
- class AmazonSchedule:
99
- """Amazon schedule class."""
100
-
101
- type: str # alarm, reminder, timer
102
- status: str
103
- label: str
104
- next_occurrence: datetime | None
105
-
106
-
107
- @dataclass
108
- class AmazonDevice:
109
- """Amazon device class."""
110
-
111
- account_name: str
112
- capabilities: list[str]
113
- device_family: str
114
- device_type: str
115
- device_owner_customer_id: str
116
- household_device: bool
117
- device_cluster_members: list[str]
118
- online: bool
119
- serial_number: str
120
- software_version: str
121
- entity_id: str | None
122
- endpoint_id: str | None
123
- sensors: dict[str, AmazonDeviceSensor]
124
- notifications: dict[str, AmazonSchedule]
125
-
126
-
127
- class AmazonSequenceType(StrEnum):
128
- """Amazon sequence types."""
129
-
130
- Announcement = "AlexaAnnouncement"
131
- Speak = "Alexa.Speak"
132
- Sound = "Alexa.Sound"
133
- Music = "Alexa.Music.PlaySearchPhrase"
134
- TextCommand = "Alexa.TextCommand"
135
- LaunchSkill = "Alexa.Operation.SkillConnections.Launch"
136
-
137
-
138
- class AmazonMusicSource(StrEnum):
139
- """Amazon music sources."""
140
-
141
- Radio = "TUNEIN"
142
- AmazonMusic = "AMAZON_MUSIC"
143
-
144
-
145
88
  class AmazonEchoApi:
146
89
  """Queries Amazon for Echo devices."""
147
90
 
@@ -151,6 +94,8 @@ class AmazonEchoApi:
151
94
  login_email: str,
152
95
  login_password: str,
153
96
  login_data: dict[str, Any] | None = None,
97
+ save_to_file: Callable[[str | dict, str, str], Coroutine[Any, Any, None]]
98
+ | None = None,
154
99
  ) -> None:
155
100
  """Initialize the scanner."""
156
101
  # Check if there is a previous login, otherwise use default (US)
@@ -162,7 +107,7 @@ class AmazonEchoApi:
162
107
  self._login_password = login_password
163
108
 
164
109
  self._cookies = self._build_init_cookies()
165
- self._save_raw_data = False
110
+ self._save_to_file = save_to_file
166
111
  self._login_stored_data = login_data or {}
167
112
  self._serial = self._serial_number()
168
113
  self._account_owner_customer_id: str | None = None
@@ -183,11 +128,6 @@ class AmazonEchoApi:
183
128
  """Return current Amazon domain."""
184
129
  return self._domain
185
130
 
186
- def save_raw_data(self) -> None:
187
- """Save raw data to disk."""
188
- self._save_raw_data = True
189
- _LOGGER.debug("Saving raw data to disk")
190
-
191
131
  def _country_specific_data(self, domain: str) -> None:
192
132
  """Set country specific data."""
193
133
  # Force lower case
@@ -387,6 +327,8 @@ class AmazonEchoApi:
387
327
  headers = DEFAULT_HEADERS.copy()
388
328
  headers.update({"User-Agent": REQUEST_AGENT[agent]})
389
329
  headers.update({"Accept-Language": self._language})
330
+ headers.update({"x-amzn-client": "aioamazondevices"})
331
+ headers.update({"x-amzn-build-version": __version__})
390
332
 
391
333
  if self._csrf_cookie:
392
334
  csrf = {CSRF_COOKIE: self._csrf_cookie}
@@ -463,57 +405,16 @@ class AmazonEchoApi:
463
405
  f"Request failed: {await self._http_phrase_error(resp.status)}"
464
406
  )
465
407
 
466
- await self._save_to_file(
467
- await resp.text(),
468
- url,
469
- mimetypes.guess_extension(content_type.split(";")[0]) or ".raw",
470
- )
471
-
472
- return BeautifulSoup(await resp.read() or "", "html.parser"), resp
408
+ raw_content = await resp.read()
473
409
 
474
- async def _save_to_file(
475
- self,
476
- raw_data: str | dict,
477
- url: str,
478
- extension: str = HTML_EXTENSION,
479
- output_path: str = SAVE_PATH,
480
- ) -> None:
481
- """Save response data to disk."""
482
- if not self._save_raw_data or not raw_data:
483
- return
484
-
485
- output_dir = Path(output_path)
486
- output_dir.mkdir(parents=True, exist_ok=True)
487
-
488
- if url.startswith("http"):
489
- url_split = url.split("/")
490
- base_filename = f"{url_split[3]}-{url_split[4].split('?')[0]}"
491
- else:
492
- base_filename = url
493
- fullpath = Path(output_dir, base_filename + extension)
494
-
495
- data: str
496
- if isinstance(raw_data, dict):
497
- data = orjson.dumps(raw_data, option=orjson.OPT_INDENT_2).decode("utf-8")
498
- elif extension in [HTML_EXTENSION, BIN_EXTENSION]:
499
- data = raw_data
500
- else:
501
- data = orjson.dumps(
502
- orjson.loads(raw_data),
503
- option=orjson.OPT_INDENT_2,
504
- ).decode("utf-8")
505
-
506
- i = 2
507
- while fullpath.exists():
508
- filename = f"{base_filename}_{i!s}{extension}"
509
- fullpath = Path(output_dir, filename)
510
- i += 1
511
-
512
- _LOGGER.warning("Saving data to %s", fullpath)
410
+ if self._save_to_file:
411
+ await self._save_to_file(
412
+ raw_content.decode("utf-8"),
413
+ url,
414
+ content_type,
415
+ )
513
416
 
514
- with Path.open(fullpath, mode="w", encoding="utf-8") as file:
515
- file.write(data)
516
- file.write("\n")
417
+ return BeautifulSoup(raw_content or "", "html.parser"), resp
517
418
 
518
419
  async def _register_device(
519
420
  self,
@@ -613,6 +514,9 @@ class AmazonEchoApi:
613
514
  """Retrieve devices sensors states."""
614
515
  devices_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
615
516
 
517
+ if not self._endpoints:
518
+ return {}
519
+
616
520
  endpoint_ids = list(self._endpoints.keys())
617
521
  payload = [
618
522
  {
@@ -972,7 +876,6 @@ class AmazonEchoApi:
972
876
  await self._domain_refresh_auth_cookies()
973
877
 
974
878
  self._login_stored_data.update({"site": f"https://www.amazon.{self._domain}"})
975
- await self._save_to_file(self._login_stored_data, "login_data", JSON_EXTENSION)
976
879
 
977
880
  # Can take a little while to register device but we need it
978
881
  # to be able to pickout account customer ID
@@ -0,0 +1 @@
1
+ """aioamazondevices const package."""
@@ -0,0 +1,26 @@
1
+ """aioamazondevices Common const."""
2
+
3
+ import logging
4
+
5
+ _LOGGER = logging.getLogger(__package__)
6
+
7
+ TO_REDACT = {
8
+ "address",
9
+ "address1",
10
+ "address2",
11
+ "address3",
12
+ "city",
13
+ "county",
14
+ "customerId",
15
+ "deviceAccountId",
16
+ "deviceAddress",
17
+ "deviceOwnerCustomerId",
18
+ "given_name",
19
+ "name",
20
+ "password",
21
+ "postalCode",
22
+ "searchCustomerId",
23
+ "state",
24
+ "street",
25
+ "user_id",
26
+ }
@@ -1,117 +1,10 @@
1
- """Constants for Amazon devices."""
1
+ """aioamazondevices devices."""
2
2
 
3
- import logging
4
-
5
- _LOGGER = logging.getLogger(__package__)
6
-
7
- ARRAY_WRAPPER = "generatedArrayWrapper"
8
-
9
- HTTP_ERROR_199 = 199
10
- HTTP_ERROR_299 = 299
11
-
12
- TO_REDACT = {
13
- "address",
14
- "address1",
15
- "address2",
16
- "address3",
17
- "city",
18
- "county",
19
- "customerId",
20
- "deviceAccountId",
21
- "deviceAddress",
22
- "deviceOwnerCustomerId",
23
- "given_name",
24
- "name",
25
- "password",
26
- "postalCode",
27
- "searchCustomerId",
28
- "state",
29
- "street",
30
- "user_id",
31
- }
32
-
33
- # Amazon APP info
34
- AMAZON_APP_BUNDLE_ID = "com.amazon.echo"
35
- AMAZON_APP_ID = "MAPiOSLib/6.0/ToHideRetailLink"
36
- AMAZON_APP_NAME = "AioAmazonDevices"
37
- AMAZON_APP_VERSION = "2.2.663733.0"
38
- AMAZON_DEVICE_SOFTWARE_VERSION = "35602678"
39
- AMAZON_DEVICE_TYPE = "A2IVLV5VM2W81"
40
- AMAZON_CLIENT_OS = "18.5"
41
-
42
- DEFAULT_SITE = "https://www.amazon.com"
43
- DEFAULT_HEADERS = {
44
- "Accept-Charset": "utf-8",
45
- "Accept-Encoding": "gzip",
46
- "Connection": "keep-alive",
47
- }
48
- CSRF_COOKIE = "csrf"
49
- REQUEST_AGENT = {
50
- "Amazon": f"AmazonWebView/AmazonAlexa/{AMAZON_APP_VERSION}/iOS/{AMAZON_CLIENT_OS}/iPhone", # noqa: E501
51
- "Browser": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0", # noqa: E501
52
- }
53
-
54
- REFRESH_ACCESS_TOKEN = "access_token" # noqa: S105
55
- REFRESH_AUTH_COOKIES = "auth_cookies"
56
-
57
- URI_DEVICES = "/api/devices-v2/device"
58
- URI_DND = "/api/dnd/device-status-list"
59
- URI_NOTIFICATIONS = "/api/notifications"
60
- URI_SIGNIN = "/ap/signin"
61
- URI_NEXUS_GRAPHQL = "/nexus/v1/graphql"
62
-
63
- SENSOR_STATE_OFF = "NOT_DETECTED"
64
-
65
- # File extensions
66
- SAVE_PATH = "out"
67
- HTML_EXTENSION = ".html"
68
- JSON_EXTENSION = ".json"
69
- BIN_EXTENSION = ".bin"
3
+ from .http import AMAZON_DEVICE_TYPE
70
4
 
71
5
  SPEAKER_GROUP_FAMILY = "WHA"
72
6
  SPEAKER_GROUP_MODEL = "Speaker Group"
73
7
 
74
- SENSORS: dict[str, dict[str, str | None]] = {
75
- "temperatureSensor": {
76
- "name": "temperature",
77
- "key": "value",
78
- "subkey": "value",
79
- "scale": "scale",
80
- },
81
- "motionSensor": {
82
- "name": "detectionState",
83
- "key": "detectionStateValue",
84
- "subkey": None,
85
- "scale": None,
86
- },
87
- "lightSensor": {
88
- "name": "illuminance",
89
- "key": "illuminanceValue",
90
- "subkey": "value",
91
- "scale": None,
92
- },
93
- }
94
-
95
- ALEXA_INFO_SKILLS = [
96
- "Alexa.Calendar.PlayToday",
97
- "Alexa.Calendar.PlayTomorrow",
98
- "Alexa.Calendar.PlayNext",
99
- "Alexa.Date.Play",
100
- "Alexa.Time.Play",
101
- "Alexa.News.NationalNews",
102
- "Alexa.FlashBriefing.Play",
103
- "Alexa.Traffic.Play",
104
- "Alexa.Weather.Play",
105
- "Alexa.CleanUp.Play",
106
- "Alexa.GoodMorning.Play",
107
- "Alexa.SingASong.Play",
108
- "Alexa.FunFact.Play",
109
- "Alexa.Joke.Play",
110
- "Alexa.TellStory.Play",
111
- "Alexa.ImHome.Play",
112
- "Alexa.GoodNight.Play",
113
- ]
114
-
115
8
  DEVICE_TO_IGNORE: list[str] = [
116
9
  AMAZON_DEVICE_TYPE, # Alexa App for iOS
117
10
  "A2TF17PFR55MTB", # Alexa App for Android
@@ -480,63 +373,3 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
480
373
  "hw_version": "Gen2",
481
374
  },
482
375
  }
483
-
484
- RECURRING_PATTERNS: dict[str, str] = {
485
- "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
486
- "XXXX-WE": "FREQ=WEEKLY;BYDAY=SA,SU",
487
- "XXXX-WXX-1": "FREQ=WEEKLY;BYDAY=MO",
488
- "XXXX-WXX-2": "FREQ=WEEKLY;BYDAY=TU",
489
- "XXXX-WXX-3": "FREQ=WEEKLY;BYDAY=WE",
490
- "XXXX-WXX-4": "FREQ=WEEKLY;BYDAY=TH",
491
- "XXXX-WXX-5": "FREQ=WEEKLY;BYDAY=FR",
492
- "XXXX-WXX-6": "FREQ=WEEKLY;BYDAY=SA",
493
- "XXXX-WXX-7": "FREQ=WEEKLY;BYDAY=SU",
494
- }
495
-
496
- WEEKEND_EXCEPTIONS = {
497
- "TH-FR": {
498
- "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,SA,SU",
499
- "XXXX-WE": "FREQ=WEEKLY;BYDAY=TH,FR",
500
- },
501
- "FR-SA": {
502
- "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,SU",
503
- "XXXX-WE": "FREQ=WEEKLY;BYDAY=FR,SA",
504
- },
505
- }
506
-
507
- # Countries grouped by their weekend type
508
- COUNTRY_GROUPS = {
509
- "TH-FR": ["IR"],
510
- "FR-SA": [
511
- "AF",
512
- "BD",
513
- "BH",
514
- "DZ",
515
- "EG",
516
- "IL",
517
- "IQ",
518
- "JO",
519
- "KW",
520
- "LY",
521
- "MV",
522
- "MY",
523
- "OM",
524
- "PS",
525
- "QA",
526
- "SA",
527
- "SD",
528
- "SY",
529
- "YE",
530
- ],
531
- }
532
-
533
- NOTIFICATION_ALARM = "Alarm"
534
- NOTIFICATION_MUSIC_ALARM = "MusicAlarm"
535
- NOTIFICATION_REMINDER = "Reminder"
536
- NOTIFICATION_TIMER = "Timer"
537
- NOTIFICATIONS_SUPPORTED = [
538
- NOTIFICATION_ALARM,
539
- NOTIFICATION_MUSIC_ALARM,
540
- NOTIFICATION_REMINDER,
541
- NOTIFICATION_TIMER,
542
- ]
@@ -0,0 +1,36 @@
1
+ """aioamazondevices HTTP const."""
2
+
3
+ HTTP_ERROR_199 = 199
4
+ HTTP_ERROR_299 = 299
5
+
6
+ ARRAY_WRAPPER = "generatedArrayWrapper"
7
+
8
+ # Amazon APP info
9
+ AMAZON_APP_BUNDLE_ID = "com.amazon.echo"
10
+ AMAZON_APP_ID = "MAPiOSLib/6.0/ToHideRetailLink"
11
+ AMAZON_APP_NAME = "AioAmazonDevices"
12
+ AMAZON_APP_VERSION = "2.2.663733.0"
13
+ AMAZON_DEVICE_SOFTWARE_VERSION = "35602678"
14
+ AMAZON_DEVICE_TYPE = "A2IVLV5VM2W81"
15
+ AMAZON_CLIENT_OS = "18.5"
16
+
17
+ DEFAULT_SITE = "https://www.amazon.com"
18
+ DEFAULT_HEADERS = {
19
+ "Accept-Charset": "utf-8",
20
+ "Accept-Encoding": "gzip",
21
+ "Connection": "keep-alive",
22
+ }
23
+ CSRF_COOKIE = "csrf"
24
+ REQUEST_AGENT = {
25
+ "Amazon": f"AmazonWebView/AmazonAlexa/{AMAZON_APP_VERSION}/iOS/{AMAZON_CLIENT_OS}/iPhone", # noqa: E501
26
+ "Browser": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0", # noqa: E501
27
+ }
28
+
29
+ REFRESH_ACCESS_TOKEN = "access_token" # noqa: S105
30
+ REFRESH_AUTH_COOKIES = "auth_cookies"
31
+
32
+ URI_DEVICES = "/api/devices-v2/device"
33
+ URI_DND = "/api/dnd/device-status-list"
34
+ URI_NOTIFICATIONS = "/api/notifications"
35
+ URI_SIGNIN = "/ap/signin"
36
+ URI_NEXUS_GRAPHQL = "/nexus/v1/graphql"
@@ -0,0 +1,44 @@
1
+ """aioamazondevices Additional entities const."""
2
+
3
+ SENSOR_STATE_OFF = "NOT_DETECTED"
4
+
5
+ SENSORS: dict[str, dict[str, str | None]] = {
6
+ "temperatureSensor": {
7
+ "name": "temperature",
8
+ "key": "value",
9
+ "subkey": "value",
10
+ "scale": "scale",
11
+ },
12
+ "motionSensor": {
13
+ "name": "detectionState",
14
+ "key": "detectionStateValue",
15
+ "subkey": None,
16
+ "scale": None,
17
+ },
18
+ "lightSensor": {
19
+ "name": "illuminance",
20
+ "key": "illuminanceValue",
21
+ "subkey": "value",
22
+ "scale": None,
23
+ },
24
+ }
25
+
26
+ ALEXA_INFO_SKILLS = [
27
+ "Alexa.Calendar.PlayToday",
28
+ "Alexa.Calendar.PlayTomorrow",
29
+ "Alexa.Calendar.PlayNext",
30
+ "Alexa.Date.Play",
31
+ "Alexa.Time.Play",
32
+ "Alexa.News.NationalNews",
33
+ "Alexa.FlashBriefing.Play",
34
+ "Alexa.Traffic.Play",
35
+ "Alexa.Weather.Play",
36
+ "Alexa.CleanUp.Play",
37
+ "Alexa.GoodMorning.Play",
38
+ "Alexa.SingASong.Play",
39
+ "Alexa.FunFact.Play",
40
+ "Alexa.Joke.Play",
41
+ "Alexa.TellStory.Play",
42
+ "Alexa.ImHome.Play",
43
+ "Alexa.GoodNight.Play",
44
+ ]
@@ -1,4 +1,4 @@
1
- """GraphQL Queries."""
1
+ """aioamazondevices GraphQL queries."""
2
2
 
3
3
  QUERY_DEVICE_DATA = """
4
4
  query getDevicesBaseData {
@@ -0,0 +1,61 @@
1
+ """aioamazondevices: schedules."""
2
+
3
+ NOTIFICATION_ALARM = "Alarm"
4
+ NOTIFICATION_MUSIC_ALARM = "MusicAlarm"
5
+ NOTIFICATION_REMINDER = "Reminder"
6
+ NOTIFICATION_TIMER = "Timer"
7
+ NOTIFICATIONS_SUPPORTED = [
8
+ NOTIFICATION_ALARM,
9
+ NOTIFICATION_MUSIC_ALARM,
10
+ NOTIFICATION_REMINDER,
11
+ NOTIFICATION_TIMER,
12
+ ]
13
+
14
+ RECURRING_PATTERNS: dict[str, str] = {
15
+ "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
16
+ "XXXX-WE": "FREQ=WEEKLY;BYDAY=SA,SU",
17
+ "XXXX-WXX-1": "FREQ=WEEKLY;BYDAY=MO",
18
+ "XXXX-WXX-2": "FREQ=WEEKLY;BYDAY=TU",
19
+ "XXXX-WXX-3": "FREQ=WEEKLY;BYDAY=WE",
20
+ "XXXX-WXX-4": "FREQ=WEEKLY;BYDAY=TH",
21
+ "XXXX-WXX-5": "FREQ=WEEKLY;BYDAY=FR",
22
+ "XXXX-WXX-6": "FREQ=WEEKLY;BYDAY=SA",
23
+ "XXXX-WXX-7": "FREQ=WEEKLY;BYDAY=SU",
24
+ }
25
+
26
+ WEEKEND_EXCEPTIONS = {
27
+ "TH-FR": {
28
+ "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,SA,SU",
29
+ "XXXX-WE": "FREQ=WEEKLY;BYDAY=TH,FR",
30
+ },
31
+ "FR-SA": {
32
+ "XXXX-WD": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,SU",
33
+ "XXXX-WE": "FREQ=WEEKLY;BYDAY=FR,SA",
34
+ },
35
+ }
36
+
37
+ # Countries grouped by their weekend type
38
+ COUNTRY_GROUPS = {
39
+ "TH-FR": ["IR"],
40
+ "FR-SA": [
41
+ "AF",
42
+ "BD",
43
+ "BH",
44
+ "DZ",
45
+ "EG",
46
+ "IL",
47
+ "IQ",
48
+ "JO",
49
+ "KW",
50
+ "LY",
51
+ "MV",
52
+ "MY",
53
+ "OM",
54
+ "PS",
55
+ "QA",
56
+ "SA",
57
+ "SD",
58
+ "SY",
59
+ "YE",
60
+ ],
61
+ }
@@ -1,4 +1,5 @@
1
- """Generated by update_sounds_list.py [2025-08-28 15:45]."""
1
+ """aioamazondevices sounds."""
2
+ # Generated by update_sounds_list.py [2025-10-23 10:03].
2
3
 
3
4
  SOUNDS_LIST = {
4
5
  "air_horn_03": "Air horn",
@@ -0,0 +1,65 @@
1
+ """aioamazondevices structures module."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from enum import StrEnum
6
+
7
+
8
+ @dataclass
9
+ class AmazonDeviceSensor:
10
+ """Amazon device sensor class."""
11
+
12
+ name: str
13
+ value: str | int | float
14
+ error: bool
15
+ error_type: str | None
16
+ error_msg: str | None
17
+ scale: str | None
18
+
19
+
20
+ @dataclass
21
+ class AmazonSchedule:
22
+ """Amazon schedule class."""
23
+
24
+ type: str # alarm, reminder, timer
25
+ status: str
26
+ label: str
27
+ next_occurrence: datetime | None
28
+
29
+
30
+ @dataclass
31
+ class AmazonDevice:
32
+ """Amazon device class."""
33
+
34
+ account_name: str
35
+ capabilities: list[str]
36
+ device_family: str
37
+ device_type: str
38
+ device_owner_customer_id: str
39
+ household_device: bool
40
+ device_cluster_members: list[str]
41
+ online: bool
42
+ serial_number: str
43
+ software_version: str
44
+ entity_id: str | None
45
+ endpoint_id: str | None
46
+ sensors: dict[str, AmazonDeviceSensor]
47
+ notifications: dict[str, AmazonSchedule]
48
+
49
+
50
+ class AmazonSequenceType(StrEnum):
51
+ """Amazon sequence types."""
52
+
53
+ Announcement = "AlexaAnnouncement"
54
+ Speak = "Alexa.Speak"
55
+ Sound = "Alexa.Sound"
56
+ Music = "Alexa.Music.PlaySearchPhrase"
57
+ TextCommand = "Alexa.TextCommand"
58
+ LaunchSkill = "Alexa.Operation.SkillConnections.Launch"
59
+
60
+
61
+ class AmazonMusicSource(StrEnum):
62
+ """Amazon music sources."""
63
+
64
+ Radio = "TUNEIN"
65
+ AmazonMusic = "AMAZON_MUSIC"
@@ -3,7 +3,7 @@
3
3
  from collections.abc import Collection
4
4
  from typing import Any
5
5
 
6
- from .const import TO_REDACT
6
+ from .const.common import TO_REDACT
7
7
 
8
8
 
9
9
  def obfuscate_email(email: str) -> str: