aioamazondevices 11.0.1__tar.gz → 11.1.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-11.0.1 → aioamazondevices-11.1.2}/PKG-INFO +1 -1
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/pyproject.toml +2 -2
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/__init__.py +1 -1
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/api.py +117 -20
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/devices.py +26 -1
- aioamazondevices-11.1.2/src/aioamazondevices/const/metadata.py +86 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/queries.py +47 -31
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/http_wrapper.py +1 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/sequence.py +1 -1
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/structures.py +1 -0
- aioamazondevices-11.0.1/src/aioamazondevices/const/metadata.py +0 -46
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/LICENSE +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/README.md +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/__init__.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/http.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/schedules.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/const/sounds.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/exceptions.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/__init__.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/dnd.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/notification.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/login.py +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/py.typed +0 -0
- {aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aioamazondevices"
|
|
3
|
-
version = "11.
|
|
3
|
+
version = "11.1.2"
|
|
4
4
|
requires-python = ">=3.12"
|
|
5
5
|
description = "Python library to control Amazon devices"
|
|
6
6
|
authors = [
|
|
@@ -36,7 +36,7 @@ dependencies = [
|
|
|
36
36
|
[tool.poetry.group.dev.dependencies]
|
|
37
37
|
pytest = "^9.0"
|
|
38
38
|
pytest-cov = ">=5,<8"
|
|
39
|
-
types-python-dateutil = "^2.9.0.
|
|
39
|
+
types-python-dateutil = "^2.9.0.20260124"
|
|
40
40
|
|
|
41
41
|
[tool.semantic_release]
|
|
42
42
|
version_toml = ["pyproject.toml:project.version"]
|
|
@@ -9,6 +9,7 @@ from aiohttp import ClientSession
|
|
|
9
9
|
|
|
10
10
|
from . import __version__
|
|
11
11
|
from .const.devices import (
|
|
12
|
+
AQM_DEVICE_TYPE,
|
|
12
13
|
DEVICE_TO_IGNORE,
|
|
13
14
|
DEVICE_TYPE_TO_MODEL,
|
|
14
15
|
SPEAKER_GROUP_FAMILY,
|
|
@@ -20,7 +21,7 @@ from .const.http import (
|
|
|
20
21
|
URI_DEVICES,
|
|
21
22
|
URI_NEXUS_GRAPHQL,
|
|
22
23
|
)
|
|
23
|
-
from .const.metadata import SENSORS
|
|
24
|
+
from .const.metadata import ALEXA_INFO_SKILLS, AQM_RANGE_SENSORS, SENSORS
|
|
24
25
|
from .const.queries import QUERY_DEVICE_DATA, QUERY_SENSOR_STATE
|
|
25
26
|
from .const.schedules import (
|
|
26
27
|
NOTIFICATION_ALARM,
|
|
@@ -164,12 +165,13 @@ class AmazonEchoApi:
|
|
|
164
165
|
self, endpoint: dict[str, Any], serial_number: str
|
|
165
166
|
) -> dict[str, AmazonDeviceSensor]:
|
|
166
167
|
device_sensors: dict[str, AmazonDeviceSensor] = {}
|
|
168
|
+
device = self._final_devices[serial_number]
|
|
167
169
|
for feature in endpoint.get("features", {}):
|
|
168
170
|
if (sensor_template := SENSORS.get(feature["name"])) is None:
|
|
169
171
|
# Skip sensors that are not in the predefined list
|
|
170
172
|
continue
|
|
171
173
|
|
|
172
|
-
if not (
|
|
174
|
+
if not (sensor_template_name_value := sensor_template["name"]):
|
|
173
175
|
raise CannotRetrieveData("Unable to read sensor template")
|
|
174
176
|
|
|
175
177
|
for feature_property in feature.get("properties"):
|
|
@@ -190,7 +192,7 @@ class AmazonEchoApi:
|
|
|
190
192
|
if not value_raw:
|
|
191
193
|
_LOGGER.warning(
|
|
192
194
|
"Sensor %s [device %s] ignored due to empty value",
|
|
193
|
-
|
|
195
|
+
sensor_template_name_value,
|
|
194
196
|
serial_number,
|
|
195
197
|
)
|
|
196
198
|
continue
|
|
@@ -208,26 +210,50 @@ class AmazonEchoApi:
|
|
|
208
210
|
except (KeyError, ValueError) as exc:
|
|
209
211
|
_LOGGER.warning(
|
|
210
212
|
"Sensor %s [device %s] ignored due to errors in feature %s: %s", # noqa: E501
|
|
211
|
-
|
|
213
|
+
sensor_template_name_value,
|
|
212
214
|
serial_number,
|
|
213
215
|
feature_property,
|
|
214
216
|
repr(exc),
|
|
215
217
|
)
|
|
216
218
|
if error:
|
|
217
219
|
_LOGGER.debug(
|
|
218
|
-
"error in sensor %s - %s - %s",
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if error_type != "NOT_FOUND":
|
|
222
|
-
device_sensors[name] = AmazonDeviceSensor(
|
|
223
|
-
name,
|
|
224
|
-
value,
|
|
225
|
-
error,
|
|
220
|
+
"error in sensor %s - %s - %s",
|
|
221
|
+
sensor_template_name_value,
|
|
226
222
|
error_type,
|
|
227
223
|
error_msg,
|
|
228
|
-
scale,
|
|
229
224
|
)
|
|
230
225
|
|
|
226
|
+
if error_type == "NOT_FOUND":
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
sensor_name = sensor_template_name_value
|
|
230
|
+
|
|
231
|
+
if (
|
|
232
|
+
device.device_type == AQM_DEVICE_TYPE
|
|
233
|
+
and sensor_template_name_value == "rangeValue"
|
|
234
|
+
):
|
|
235
|
+
if not (
|
|
236
|
+
(instance := feature.get("instance"))
|
|
237
|
+
and (aqm_sensor := AQM_RANGE_SENSORS.get(instance))
|
|
238
|
+
and (aqm_sensor_name := aqm_sensor.get("name"))
|
|
239
|
+
):
|
|
240
|
+
_LOGGER.debug(
|
|
241
|
+
"No template for rangeValue (%s) - Skipping sensor",
|
|
242
|
+
instance,
|
|
243
|
+
)
|
|
244
|
+
continue
|
|
245
|
+
sensor_name = aqm_sensor_name
|
|
246
|
+
scale = aqm_sensor.get("scale")
|
|
247
|
+
|
|
248
|
+
device_sensors[sensor_name] = AmazonDeviceSensor(
|
|
249
|
+
sensor_name,
|
|
250
|
+
value,
|
|
251
|
+
error,
|
|
252
|
+
error_type,
|
|
253
|
+
error_msg,
|
|
254
|
+
scale,
|
|
255
|
+
)
|
|
256
|
+
|
|
231
257
|
return device_sensors
|
|
232
258
|
|
|
233
259
|
async def _get_devices_endpoint_data(self) -> dict[str, dict[str, Any]]:
|
|
@@ -247,13 +273,15 @@ class AmazonEchoApi:
|
|
|
247
273
|
|
|
248
274
|
endpoint_data = await self._http_wrapper.response_to_json(raw_resp, "endpoint")
|
|
249
275
|
|
|
250
|
-
if not (data := endpoint_data.get("data")) or not data.get("
|
|
276
|
+
if not (data := endpoint_data.get("data")) or not data.get("alexaVoiceDevices"):
|
|
251
277
|
await self._format_human_error(endpoint_data)
|
|
252
278
|
return {}
|
|
253
279
|
|
|
254
|
-
endpoints = data["listEndpoints"]
|
|
255
280
|
devices_endpoints: dict[str, dict[str, Any]] = {}
|
|
256
|
-
|
|
281
|
+
|
|
282
|
+
# Process Alexa Voice Enabled devices
|
|
283
|
+
# Just map endpoint ID to serial number to facilitate sensor lookup
|
|
284
|
+
for endpoint in data.get("alexaVoiceDevices", {}).get("endpoints", {}):
|
|
257
285
|
# save looking up sensor data on apps
|
|
258
286
|
if endpoint.get("alexaEnabledMetadata", {}).get("category") == "APP":
|
|
259
287
|
continue
|
|
@@ -263,6 +291,39 @@ class AmazonEchoApi:
|
|
|
263
291
|
devices_endpoints[serial_number] = endpoint
|
|
264
292
|
self._endpoints[endpoint["endpointId"]] = serial_number
|
|
265
293
|
|
|
294
|
+
# Process Air Quality Monitors if present
|
|
295
|
+
# map endpoint ID to serial number to facilitate sensor lookup but also
|
|
296
|
+
# create AmazonDevice as these are not present in api/devices-v2/device endpoint
|
|
297
|
+
for aqm_endpoint in data.get("airQualityMonitors", {}).get("endpoints", {}):
|
|
298
|
+
aqm_serial_number: str = aqm_endpoint["serialNumber"]["value"]["text"]
|
|
299
|
+
devices_endpoints[aqm_serial_number] = aqm_endpoint
|
|
300
|
+
self._endpoints[aqm_endpoint["endpointId"]] = aqm_serial_number
|
|
301
|
+
|
|
302
|
+
device_name = aqm_endpoint["friendlyNameObject"]["value"]["text"]
|
|
303
|
+
device_type = aqm_endpoint["legacyIdentifiers"]["dmsIdentifier"][
|
|
304
|
+
"deviceType"
|
|
305
|
+
]["value"]["text"]
|
|
306
|
+
software_version = aqm_endpoint["softwareVersion"]["value"]["text"]
|
|
307
|
+
|
|
308
|
+
self._final_devices[aqm_serial_number] = AmazonDevice(
|
|
309
|
+
account_name=device_name,
|
|
310
|
+
capabilities=[],
|
|
311
|
+
device_family="AIR_QUALITY_MONITOR",
|
|
312
|
+
device_type=device_type,
|
|
313
|
+
device_owner_customer_id=self._session_state_data.account_customer_id
|
|
314
|
+
or "n/a",
|
|
315
|
+
household_device=False,
|
|
316
|
+
device_cluster_members={aqm_serial_number: AQM_DEVICE_TYPE},
|
|
317
|
+
online=True,
|
|
318
|
+
serial_number=aqm_serial_number,
|
|
319
|
+
software_version=software_version,
|
|
320
|
+
entity_id=None,
|
|
321
|
+
endpoint_id=aqm_endpoint.get("endpointId"),
|
|
322
|
+
sensors={},
|
|
323
|
+
notifications_supported=False,
|
|
324
|
+
notifications={},
|
|
325
|
+
)
|
|
326
|
+
|
|
266
327
|
return devices_endpoints
|
|
267
328
|
|
|
268
329
|
async def get_devices_data(
|
|
@@ -307,9 +368,15 @@ class AmazonEchoApi:
|
|
|
307
368
|
sensors = devices_sensors.get(device.serial_number, {})
|
|
308
369
|
if sensors:
|
|
309
370
|
device.sensors = sensors
|
|
371
|
+
if reachability_sensor := sensors.get("reachability"):
|
|
372
|
+
device.online = reachability_sensor.value == "OK"
|
|
373
|
+
else:
|
|
374
|
+
device.online = False
|
|
310
375
|
else:
|
|
376
|
+
device.online = False
|
|
311
377
|
for device_sensor in device.sensors.values():
|
|
312
378
|
device_sensor.error = True
|
|
379
|
+
|
|
313
380
|
if (
|
|
314
381
|
device_dnd := dnd_sensors.get(device.serial_number)
|
|
315
382
|
) and device.device_family != SPEAKER_GROUP_FAMILY:
|
|
@@ -341,6 +408,15 @@ class AmazonEchoApi:
|
|
|
341
408
|
):
|
|
342
409
|
device.notifications[notification_type] = notification_object
|
|
343
410
|
|
|
411
|
+
# base online status of speaker groups on their members
|
|
412
|
+
for device in self._final_devices.values():
|
|
413
|
+
if device.device_family == SPEAKER_GROUP_FAMILY:
|
|
414
|
+
device.online = all(
|
|
415
|
+
d.online
|
|
416
|
+
for d in self._final_devices.values()
|
|
417
|
+
if d.serial_number in device.device_cluster_members
|
|
418
|
+
)
|
|
419
|
+
|
|
344
420
|
async def _set_device_endpoints_data(self) -> None:
|
|
345
421
|
"""Set device endpoint data."""
|
|
346
422
|
devices_endpoints = await self._get_devices_endpoint_data()
|
|
@@ -382,6 +458,11 @@ class AmazonEchoApi:
|
|
|
382
458
|
|
|
383
459
|
serial_number: str = device["serialNumber"]
|
|
384
460
|
|
|
461
|
+
_has_notification_capability = any(
|
|
462
|
+
capability in capabilities
|
|
463
|
+
for capability in ["REMINDERS", "TIMERS_AND_ALARMS"]
|
|
464
|
+
)
|
|
465
|
+
|
|
385
466
|
final_devices_list[serial_number] = AmazonDevice(
|
|
386
467
|
account_name=account_name,
|
|
387
468
|
capabilities=capabilities,
|
|
@@ -399,6 +480,7 @@ class AmazonEchoApi:
|
|
|
399
480
|
entity_id=None,
|
|
400
481
|
endpoint_id=None,
|
|
401
482
|
sensors={},
|
|
483
|
+
notifications_supported=_has_notification_capability,
|
|
402
484
|
notifications={},
|
|
403
485
|
)
|
|
404
486
|
|
|
@@ -453,7 +535,7 @@ class AmazonEchoApi:
|
|
|
453
535
|
sound_name: str,
|
|
454
536
|
) -> None:
|
|
455
537
|
"""Call Alexa.Sound to play sound."""
|
|
456
|
-
await self.
|
|
538
|
+
await self._call_alexa_command_per_cluster_member(
|
|
457
539
|
device, AmazonSequenceType.Sound, sound_name
|
|
458
540
|
)
|
|
459
541
|
|
|
@@ -474,7 +556,7 @@ class AmazonEchoApi:
|
|
|
474
556
|
text_command: str,
|
|
475
557
|
) -> None:
|
|
476
558
|
"""Call Alexa.TextCommand to issue command."""
|
|
477
|
-
await self.
|
|
559
|
+
await self._call_alexa_command_per_cluster_member(
|
|
478
560
|
device, AmazonSequenceType.TextCommand, text_command
|
|
479
561
|
)
|
|
480
562
|
|
|
@@ -484,7 +566,7 @@ class AmazonEchoApi:
|
|
|
484
566
|
skill_name: str,
|
|
485
567
|
) -> None:
|
|
486
568
|
"""Call Alexa.LaunchSkill to launch a skill."""
|
|
487
|
-
await self.
|
|
569
|
+
await self._call_alexa_command_per_cluster_member(
|
|
488
570
|
device, AmazonSequenceType.LaunchSkill, skill_name
|
|
489
571
|
)
|
|
490
572
|
|
|
@@ -494,7 +576,22 @@ class AmazonEchoApi:
|
|
|
494
576
|
info_skill_name: str,
|
|
495
577
|
) -> None:
|
|
496
578
|
"""Call Info skill. See ALEXA_INFO_SKILLS . const."""
|
|
497
|
-
|
|
579
|
+
info_skill = ALEXA_INFO_SKILLS.get(info_skill_name, info_skill_name)
|
|
580
|
+
await self._call_alexa_command_per_cluster_member(device, info_skill, "")
|
|
581
|
+
|
|
582
|
+
async def _call_alexa_command_per_cluster_member(
|
|
583
|
+
self,
|
|
584
|
+
device: AmazonDevice,
|
|
585
|
+
message_type: str,
|
|
586
|
+
message_body: str,
|
|
587
|
+
) -> None:
|
|
588
|
+
"""Call Alexa command per cluster member."""
|
|
589
|
+
for cluster_member in device.device_cluster_members:
|
|
590
|
+
await self._sequence_handler.send_message(
|
|
591
|
+
self._final_devices[cluster_member],
|
|
592
|
+
message_type,
|
|
593
|
+
message_body,
|
|
594
|
+
)
|
|
498
595
|
|
|
499
596
|
async def _format_human_error(self, sensors_state: dict) -> bool:
|
|
500
597
|
"""Format human readable error from malformed data."""
|
|
@@ -4,6 +4,7 @@ from .http import AMAZON_DEVICE_TYPE
|
|
|
4
4
|
|
|
5
5
|
SPEAKER_GROUP_FAMILY = "WHA"
|
|
6
6
|
SPEAKER_GROUP_MODEL = "Speaker Group"
|
|
7
|
+
AQM_DEVICE_TYPE = "AEZME1X38KDRA"
|
|
7
8
|
|
|
8
9
|
DEVICE_TO_IGNORE: list[str] = [
|
|
9
10
|
AMAZON_DEVICE_TYPE, # Alexa App for iOS
|
|
@@ -28,10 +29,15 @@ DEVICE_TO_IGNORE: list[str] = [
|
|
|
28
29
|
"A3BW5ZVFHRCQPO", # BMW Mini Car System - issue #479
|
|
29
30
|
"A133UZ2CB0IB8", # Sony Soundbar Sony HT-A5000 - issue #486
|
|
30
31
|
"A2M9HB23M9MSSM", # Smartwatch Amazfit Bip U Pro - issue #507
|
|
32
|
+
"A2QDHDQIWC2LTG", # Echo Buds (Left) - issue #515
|
|
33
|
+
"A31PMVIWCRNTX2", # Echo Buds (Right) - issue #515
|
|
34
|
+
"A3HVREY4JWAZ6K", # Echo Buds (Charger) - issue #515
|
|
31
35
|
"A1P7E7V3FCZKU6", # Toshiba Corporation TV 32LF221U19 - issue #531
|
|
36
|
+
"APHEAY6LX7T13", # Samsung Refrigerator RS22T5561SR/AA - issue #577
|
|
32
37
|
"A1NPP2J03FTS0I", # Eero Pro 6 - issue #602
|
|
33
38
|
"A14AIWB3T3AS1Z", # Samsung Soundbar HW-Q950A - issue #603
|
|
34
|
-
"
|
|
39
|
+
"A1X5IB2CRN3E8G", # Fitbit Versa 3 - issue #651
|
|
40
|
+
"A1NQ0LXWBGVQS9", # Samsung 2012 QLED TV - Issue #660
|
|
35
41
|
]
|
|
36
42
|
|
|
37
43
|
DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
@@ -426,4 +432,23 @@ DEVICE_TYPE_TO_MODEL: dict[str, dict[str, str | None]] = {
|
|
|
426
432
|
"model": "Orbi Voice (RBS40V)",
|
|
427
433
|
"hw_version": None,
|
|
428
434
|
},
|
|
435
|
+
AQM_DEVICE_TYPE: {
|
|
436
|
+
"model": "Air Quality Monitor",
|
|
437
|
+
"hw_version": "Gen1",
|
|
438
|
+
},
|
|
439
|
+
"A1MR3F8QRZNAXI": {
|
|
440
|
+
"model": "Echo Dot Max",
|
|
441
|
+
"hw_version": "Gen1",
|
|
442
|
+
},
|
|
443
|
+
"A1XULUOD31VLF4": {
|
|
444
|
+
"manufacturer": "Broan-NuTone LLC",
|
|
445
|
+
"model": "Bathroom Fan with Alexa (VC110CCT)",
|
|
446
|
+
"hw_version": None,
|
|
447
|
+
},
|
|
448
|
+
"A15QWUTQ6FSMYX": {
|
|
449
|
+
# This appears to be a group for both speakers
|
|
450
|
+
# but four devices show this device type (see issue #515)
|
|
451
|
+
"model": "Echo Buds",
|
|
452
|
+
"hw_version": "Gen2",
|
|
453
|
+
},
|
|
429
454
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
"connectivity": {
|
|
25
|
+
"name": "reachability",
|
|
26
|
+
"key": "reachabilityStatusValue",
|
|
27
|
+
"subkey": None,
|
|
28
|
+
"scale": None,
|
|
29
|
+
},
|
|
30
|
+
"range": {
|
|
31
|
+
"name": "rangeValue",
|
|
32
|
+
"key": "rangeValue",
|
|
33
|
+
"subkey": "value",
|
|
34
|
+
"scale": None,
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
AQM_RANGE_SENSORS: dict[str, dict[str, str | None]] = {
|
|
39
|
+
"4": {
|
|
40
|
+
"name": "Humidity",
|
|
41
|
+
"scale": "%",
|
|
42
|
+
},
|
|
43
|
+
"5": {
|
|
44
|
+
"name": "VOC",
|
|
45
|
+
"scale": None,
|
|
46
|
+
},
|
|
47
|
+
"6": {
|
|
48
|
+
"name": "PM25",
|
|
49
|
+
"scale": "MicroGramsPerCubicMeter",
|
|
50
|
+
},
|
|
51
|
+
"7": {
|
|
52
|
+
"name": "PM10",
|
|
53
|
+
"scale": "MicroGramsPerCubicMeter",
|
|
54
|
+
},
|
|
55
|
+
"8": {
|
|
56
|
+
"name": "CO",
|
|
57
|
+
"scale": "ppm",
|
|
58
|
+
},
|
|
59
|
+
"9": {
|
|
60
|
+
"name": "Air Quality",
|
|
61
|
+
"scale": None,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
ALEXA_INFO_SKILLS = {
|
|
67
|
+
"alexa_calendar_today": "Alexa.Calendar.PlayToday",
|
|
68
|
+
"alexa_calendar_tomorrow": "Alexa.Calendar.PlayTomorrow",
|
|
69
|
+
"alexa_calendar_next": "Alexa.Calendar.PlayNext",
|
|
70
|
+
"alexa_date": "Alexa.Date.Play",
|
|
71
|
+
"alexa_time": "Alexa.Time.Play",
|
|
72
|
+
"alexa_nationalnews": "Alexa.News.NationalNews",
|
|
73
|
+
"alexa_flashbriefing": "Alexa.FlashBriefing.Play",
|
|
74
|
+
"alexa_traffic": "Alexa.Traffic.Play",
|
|
75
|
+
"alexa_weather": "Alexa.Weather.Play",
|
|
76
|
+
"alexa_cleanup": "Alexa.CleanUp.Play",
|
|
77
|
+
"alexa_goodmorning": "Alexa.GoodMorning.Play",
|
|
78
|
+
"alexa_singasong": "Alexa.SingASong.Play",
|
|
79
|
+
"alexa_funfact": "Alexa.FunFact.Play",
|
|
80
|
+
"alexa_joke": "Alexa.Joke.Play",
|
|
81
|
+
"alexa_tellstory": "Alexa.TellStory.Play",
|
|
82
|
+
"alexa_imhome": "Alexa.ImHome.Play",
|
|
83
|
+
"alexa_goodnight": "Alexa.GoodNight.Play",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
MAX_CUSTOMER_ACCOUNT_RETRIES = 3
|
|
@@ -2,40 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
QUERY_DEVICE_DATA = """
|
|
4
4
|
query getDevicesBaseData {
|
|
5
|
-
listEndpoints(
|
|
5
|
+
alexaVoiceDevices: listEndpoints(
|
|
6
6
|
listEndpointsInput: {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
displayCategory: "ALEXA_VOICE_ENABLED"
|
|
8
|
+
includeHouseholdDevices: true
|
|
9
9
|
}
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
softwareVersion { value { text } }
|
|
19
|
-
creationTime
|
|
20
|
-
enablement
|
|
21
|
-
displayCategories {
|
|
22
|
-
all { value }
|
|
23
|
-
primary { value }
|
|
24
|
-
}
|
|
25
|
-
alexaEnabledMetadata {
|
|
26
|
-
iconId
|
|
27
|
-
isVisible
|
|
28
|
-
category
|
|
29
|
-
capabilities
|
|
30
|
-
}
|
|
31
|
-
legacyIdentifiers {
|
|
32
|
-
dmsIdentifier {
|
|
33
|
-
deviceType { value { text } }
|
|
34
|
-
}
|
|
35
|
-
chrsIdentifier { entityId }
|
|
36
|
-
}
|
|
37
|
-
legacyAppliance { applianceId }
|
|
10
|
+
) {
|
|
11
|
+
...DeviceEndpoints
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
airQualityMonitors: listEndpoints(
|
|
15
|
+
listEndpointsInput: {
|
|
16
|
+
displayCategory: "AIR_QUALITY_MONITOR"
|
|
17
|
+
includeHouseholdDevices: true
|
|
38
18
|
}
|
|
19
|
+
) {
|
|
20
|
+
...DeviceEndpoints
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fragment DeviceEndpoints on ListEndpointsResponse {
|
|
25
|
+
endpoints {
|
|
26
|
+
endpointId: id
|
|
27
|
+
friendlyNameObject { value { text } }
|
|
28
|
+
manufacturer { value { text } }
|
|
29
|
+
model { value { text } }
|
|
30
|
+
serialNumber { value { text } }
|
|
31
|
+
softwareVersion { value { text } }
|
|
32
|
+
creationTime
|
|
33
|
+
enablement
|
|
34
|
+
displayCategories {
|
|
35
|
+
all { value }
|
|
36
|
+
primary { value }
|
|
37
|
+
}
|
|
38
|
+
alexaEnabledMetadata {
|
|
39
|
+
iconId
|
|
40
|
+
isVisible
|
|
41
|
+
category
|
|
42
|
+
capabilities
|
|
43
|
+
}
|
|
44
|
+
legacyIdentifiers {
|
|
45
|
+
dmsIdentifier { deviceType { value { text } } }
|
|
46
|
+
chrsIdentifier { entityId }
|
|
47
|
+
}
|
|
48
|
+
legacyAppliance { applianceId }
|
|
39
49
|
}
|
|
40
50
|
}
|
|
41
51
|
"""
|
|
@@ -46,6 +56,7 @@ fragment EndpointState on Endpoint {
|
|
|
46
56
|
friendlyNameObject { value { text } }
|
|
47
57
|
features {
|
|
48
58
|
name
|
|
59
|
+
instance
|
|
49
60
|
properties {
|
|
50
61
|
name
|
|
51
62
|
type
|
|
@@ -76,6 +87,11 @@ fragment EndpointState on Endpoint {
|
|
|
76
87
|
timeOfSample
|
|
77
88
|
timeOfLastChange
|
|
78
89
|
}
|
|
90
|
+
... on RangeValue {
|
|
91
|
+
rangeValue { value }
|
|
92
|
+
timeOfSample
|
|
93
|
+
timeOfLastChange
|
|
94
|
+
}
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
}
|
|
@@ -371,6 +371,7 @@ class AmazonHttpWrapper:
|
|
|
371
371
|
]:
|
|
372
372
|
raise CannotAuthenticate(await self.http_phrase_error(resp.status))
|
|
373
373
|
if not await self._ignore_ap_signin_error(resp):
|
|
374
|
+
_LOGGER.debug("Error response content: %s", await resp.text())
|
|
374
375
|
raise CannotRetrieveData(
|
|
375
376
|
f"Request failed: {await self.http_phrase_error(resp.status)}"
|
|
376
377
|
)
|
|
@@ -1,46 +0,0 @@
|
|
|
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
|
-
]
|
|
45
|
-
|
|
46
|
-
MAX_CUSTOMER_ACCOUNT_RETRIES = 3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/__init__.py
RENAMED
|
File without changes
|
{aioamazondevices-11.0.1 → aioamazondevices-11.1.2}/src/aioamazondevices/implementation/dnd.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|