aioamazondevices 6.0.0__py3-none-any.whl → 6.1.0__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.
- aioamazondevices/__init__.py +1 -1
- aioamazondevices/api.py +102 -186
- aioamazondevices/const.py +28 -33
- aioamazondevices/query.py +91 -0
- {aioamazondevices-6.0.0.dist-info → aioamazondevices-6.1.0.dist-info}/METADATA +1 -1
- aioamazondevices-6.1.0.dist-info/RECORD +12 -0
- aioamazondevices-6.0.0.dist-info/RECORD +0 -11
- {aioamazondevices-6.0.0.dist-info → aioamazondevices-6.1.0.dist-info}/LICENSE +0 -0
- {aioamazondevices-6.0.0.dist-info → aioamazondevices-6.1.0.dist-info}/WHEEL +0 -0
aioamazondevices/__init__.py
CHANGED
aioamazondevices/api.py
CHANGED
@@ -48,18 +48,12 @@ from .const import (
|
|
48
48
|
HTTP_ERROR_199,
|
49
49
|
HTTP_ERROR_299,
|
50
50
|
JSON_EXTENSION,
|
51
|
-
NODE_BLUETOOTH,
|
52
|
-
NODE_DEVICES,
|
53
|
-
NODE_DO_NOT_DISTURB,
|
54
|
-
NODE_IDENTIFIER,
|
55
|
-
NODE_PREFERENCES,
|
56
51
|
REFRESH_ACCESS_TOKEN,
|
57
52
|
REFRESH_AUTH_COOKIES,
|
58
53
|
SAVE_PATH,
|
59
54
|
SENSORS,
|
60
|
-
|
61
|
-
|
62
|
-
URI_SENSORS,
|
55
|
+
URI_DEVICES,
|
56
|
+
URI_NEXUS_GRAPHQL,
|
63
57
|
URI_SIGNIN,
|
64
58
|
)
|
65
59
|
from .exceptions import (
|
@@ -69,6 +63,7 @@ from .exceptions import (
|
|
69
63
|
CannotRetrieveData,
|
70
64
|
WrongMethod,
|
71
65
|
)
|
66
|
+
from .query import QUERY_DEVICE_STATE
|
72
67
|
from .utils import obfuscate_email, scrub_fields
|
73
68
|
|
74
69
|
|
@@ -94,11 +89,8 @@ class AmazonDevice:
|
|
94
89
|
online: bool
|
95
90
|
serial_number: str
|
96
91
|
software_version: str
|
97
|
-
|
98
|
-
|
99
|
-
bluetooth_state: bool
|
100
|
-
entity_id: str
|
101
|
-
appliance_id: str
|
92
|
+
entity_id: str | None
|
93
|
+
endpoint_id: str | None
|
102
94
|
sensors: dict[str, AmazonDeviceSensor]
|
103
95
|
|
104
96
|
|
@@ -326,14 +318,6 @@ class AmazonEchoApi:
|
|
326
318
|
)
|
327
319
|
return False
|
328
320
|
|
329
|
-
async def _ignore_phoenix_error(self, response: ClientResponse) -> bool:
|
330
|
-
"""Return true if error is due to phoenix endpoint."""
|
331
|
-
# Endpoint URI_IDS replies with error 199 or 299
|
332
|
-
# during maintenance
|
333
|
-
return response.status in [HTTP_ERROR_199, HTTP_ERROR_299] and (
|
334
|
-
URI_IDS in response.url.path
|
335
|
-
)
|
336
|
-
|
337
321
|
async def _http_phrase_error(self, error: int) -> str:
|
338
322
|
"""Convert numeric error in human phrase."""
|
339
323
|
if error == HTTP_ERROR_199:
|
@@ -444,9 +428,7 @@ class AmazonEchoApi:
|
|
444
428
|
HTTPStatus.UNAUTHORIZED,
|
445
429
|
]:
|
446
430
|
raise CannotAuthenticate(await self._http_phrase_error(resp.status))
|
447
|
-
if not await self._ignore_ap_signin_error(
|
448
|
-
resp
|
449
|
-
) and not await self._ignore_phoenix_error(resp):
|
431
|
+
if not await self._ignore_ap_signin_error(resp):
|
450
432
|
raise CannotRetrieveData(
|
451
433
|
f"Request failed: {await self._http_phrase_error(resp.status)}"
|
452
434
|
)
|
@@ -597,127 +579,80 @@ class AmazonEchoApi:
|
|
597
579
|
_LOGGER.info("Register device: %s", scrub_fields(login_data))
|
598
580
|
return login_data
|
599
581
|
|
600
|
-
async def
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
"Sensors data not available [%s error '%s'], skipping",
|
612
|
-
URI_IDS,
|
613
|
-
await self._http_phrase_error(raw_resp.status),
|
614
|
-
)
|
615
|
-
self._sensors_available = False
|
616
|
-
return []
|
617
|
-
|
618
|
-
json_data = await raw_resp.json()
|
619
|
-
|
620
|
-
network_detail = orjson.loads(json_data["networkDetail"])
|
621
|
-
# Navigate through the nested structure step by step
|
622
|
-
location_details = network_detail["locationDetails"]["locationDetails"]
|
623
|
-
default_location = location_details["Default_Location"]
|
624
|
-
amazon_bridge = default_location["amazonBridgeDetails"]["amazonBridgeDetails"]
|
625
|
-
|
626
|
-
# New devices are based on LambdaBridge_AAA structure
|
627
|
-
lambda_bridge_aaa = amazon_bridge.get("LambdaBridge_AAA/SonarCloudService")
|
628
|
-
appliance_details_aaa = (
|
629
|
-
lambda_bridge_aaa["applianceDetails"]["applianceDetails"]
|
630
|
-
if lambda_bridge_aaa
|
631
|
-
else {}
|
632
|
-
)
|
582
|
+
async def _get_devices_state(
|
583
|
+
self,
|
584
|
+
) -> dict[str, Any]:
|
585
|
+
"""Get Device State."""
|
586
|
+
payload = {
|
587
|
+
"operationName": "getDevicesState",
|
588
|
+
"variables": {
|
589
|
+
"latencyTolerance": "LOW",
|
590
|
+
},
|
591
|
+
"query": QUERY_DEVICE_STATE,
|
592
|
+
}
|
633
593
|
|
634
|
-
|
635
|
-
|
594
|
+
_, raw_resp = await self._session_request(
|
595
|
+
method=HTTPMethod.POST,
|
596
|
+
url=f"https://alexa.amazon.{self._domain}{URI_NEXUS_GRAPHQL}",
|
597
|
+
input_data=payload,
|
598
|
+
json_data=True,
|
636
599
|
)
|
637
600
|
|
638
|
-
|
639
|
-
for bridge_key, bridge_value in amazon_bridge.items():
|
640
|
-
if "LambdaBridge_AlexaBridge/" in bridge_key:
|
641
|
-
# Value key: "LambdaBridge_AlexaBridge/XXXXXXXXXXXXXX@XXXXXXXXXXXXXX"
|
642
|
-
# Value subkey: "AlexaBridge_XXXXXXXXXXXXXX@XXXXXXXXXXXXXX_XXXXXXXXXXXX"
|
643
|
-
subkey = bridge_key.split("_")[1].replace("/", "_")
|
644
|
-
|
645
|
-
appliance_details_alexa = bridge_value["applianceDetails"][
|
646
|
-
"applianceDetails"
|
647
|
-
]
|
648
|
-
entity_ids_list.extend(
|
649
|
-
await self._get_entities_ids(appliance_details_alexa, subkey)
|
650
|
-
)
|
651
|
-
|
652
|
-
return entity_ids_list
|
653
|
-
|
654
|
-
async def _get_entities_ids(
|
655
|
-
self, appliance_details: dict[str, Any], searchkey: str
|
656
|
-
) -> list[dict[str, str]]:
|
657
|
-
"""Extract entityId and applianceId."""
|
658
|
-
entity_ids_list: list[dict[str, str]] = []
|
659
|
-
# Process each appliance that starts with "searchkey"
|
660
|
-
for appliance_key, appliance_data in appliance_details.items():
|
661
|
-
if not appliance_key.startswith(searchkey):
|
662
|
-
continue
|
663
|
-
|
664
|
-
entity_id = appliance_data["entityId"]
|
665
|
-
appliance_id = appliance_data["applianceId"]
|
666
|
-
|
667
|
-
# Create identifier object for this appliance
|
668
|
-
identifier = {
|
669
|
-
"entityId": entity_id,
|
670
|
-
"applianceId": appliance_id,
|
671
|
-
}
|
672
|
-
|
673
|
-
# Update device information for each device in the identifier list
|
674
|
-
for device_identifier in appliance_data["alexaDeviceIdentifierList"]:
|
675
|
-
serial_number = device_identifier["dmsDeviceSerialNumber"]
|
676
|
-
|
677
|
-
# Add identifier information to the device
|
678
|
-
# but only if the device was previously found
|
679
|
-
if serial_number in self._devices:
|
680
|
-
self._devices[serial_number] |= {NODE_IDENTIFIER: identifier}
|
681
|
-
|
682
|
-
# Add to entity IDs list for sensor retrieval
|
683
|
-
entity_ids_list.append({"entityId": entity_id, "entityType": "ENTITY"})
|
684
|
-
|
685
|
-
return entity_ids_list
|
601
|
+
return cast("dict", await raw_resp.json())
|
686
602
|
|
687
603
|
async def _get_sensors_states(
|
688
|
-
self,
|
689
|
-
) -> dict[str, dict[str, AmazonDeviceSensor]]:
|
604
|
+
self,
|
605
|
+
) -> tuple[dict[str, dict[str, Any]], dict[str, dict[str, AmazonDeviceSensor]]]:
|
690
606
|
"""Retrieve devices sensors states."""
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
607
|
+
devices_state = await self._get_devices_state()
|
608
|
+
devices_sensors: dict[str, dict[str, AmazonDeviceSensor]] = {}
|
609
|
+
devices_endpoints: dict[str, dict[str, Any]] = {}
|
610
|
+
|
611
|
+
endpoints = devices_state["data"]["listEndpoints"]
|
612
|
+
for endpoint in endpoints.get("endpoints"):
|
613
|
+
serial_number = (
|
614
|
+
endpoint["serialNumber"]["value"]["text"]
|
615
|
+
if endpoint["serialNumber"]
|
616
|
+
else None
|
617
|
+
)
|
618
|
+
if serial_number in self._devices:
|
619
|
+
devices_sensors[serial_number] = self._get_device_sensor_state(endpoint)
|
620
|
+
devices_endpoints[serial_number] = endpoint
|
621
|
+
|
622
|
+
return devices_endpoints, devices_sensors
|
623
|
+
|
624
|
+
def _get_device_sensor_state(
|
625
|
+
self, endpoint: dict[str, Any]
|
626
|
+
) -> dict[str, AmazonDeviceSensor]:
|
627
|
+
device_sensors: dict[str, AmazonDeviceSensor] = {}
|
628
|
+
if (
|
629
|
+
endpoint_dnd := endpoint.get("settings", {}).get("doNotDisturb")
|
630
|
+
) and not endpoint_dnd["error"]:
|
631
|
+
device_sensors["dnd"] = AmazonDeviceSensor(
|
632
|
+
"dnd", endpoint_dnd.get("toggleValue"), None
|
633
|
+
)
|
634
|
+
for feature in endpoint.get("features", {}):
|
635
|
+
first_property = (feature.get("properties") or [None])[0] or {}
|
636
|
+
if (
|
637
|
+
first_property.get("type") != "RETRIEVABLE"
|
638
|
+
or (sensor := SENSORS.get(feature["name"])) is None
|
639
|
+
):
|
640
|
+
continue
|
699
641
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
value=(_value["value"] if _value_dict else _value),
|
715
|
-
scale=_value.get("scale") if _value_dict else None,
|
716
|
-
)
|
717
|
-
}
|
718
|
-
)
|
719
|
-
final_sensors.update({_id: dict_sensors})
|
720
|
-
return final_sensors
|
642
|
+
if not (name := sensor["name"]):
|
643
|
+
raise TypeError("Unable to read sensor template")
|
644
|
+
|
645
|
+
value = first_property[sensor["key"]]
|
646
|
+
scale = value["scale"] if sensor["scale"] else None
|
647
|
+
if subkey := sensor["subkey"]:
|
648
|
+
value = value[subkey]
|
649
|
+
device_sensors[name] = AmazonDeviceSensor(
|
650
|
+
name,
|
651
|
+
value,
|
652
|
+
scale,
|
653
|
+
)
|
654
|
+
|
655
|
+
return device_sensors
|
721
656
|
|
722
657
|
async def login_mode_interactive(self, otp_code: str) -> dict[str, Any]:
|
723
658
|
"""Login to Amazon interactively via OTP."""
|
@@ -857,68 +792,49 @@ class AmazonEchoApi:
|
|
857
792
|
) -> dict[str, AmazonDevice]:
|
858
793
|
"""Get Amazon devices data."""
|
859
794
|
self._devices = {}
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
)
|
865
|
-
|
866
|
-
response_data = await raw_resp.text()
|
867
|
-
json_data = {} if len(response_data) == 0 else await raw_resp.json()
|
795
|
+
_, raw_resp = await self._session_request(
|
796
|
+
method=HTTPMethod.GET,
|
797
|
+
url=f"https://alexa.amazon.{self._domain}{URI_DEVICES}",
|
798
|
+
)
|
868
799
|
|
869
|
-
|
800
|
+
response_data = await raw_resp.text()
|
801
|
+
json_data = {} if len(response_data) == 0 else await raw_resp.json()
|
870
802
|
|
871
|
-
|
872
|
-
dev_serial = data.get("serialNumber") or data.get("deviceSerialNumber")
|
873
|
-
if previous_data := self._devices.get(dev_serial):
|
874
|
-
self._devices[dev_serial] = previous_data | {key: data}
|
875
|
-
else:
|
876
|
-
self._devices[dev_serial] = {key: data}
|
803
|
+
_LOGGER.debug("JSON devices data: %s", scrub_fields(json_data))
|
877
804
|
|
878
|
-
|
805
|
+
for data in json_data["devices"]:
|
806
|
+
dev_serial = data.get("serialNumber")
|
807
|
+
self._devices[dev_serial] = data
|
879
808
|
|
880
|
-
|
881
|
-
entity_ids_list := await self._get_devices_ids()
|
882
|
-
):
|
883
|
-
devices_sensors = await self._get_sensors_states(entity_ids_list)
|
809
|
+
devices_endpoints, devices_sensors = await self._get_sensors_states()
|
884
810
|
|
885
811
|
final_devices_list: dict[str, AmazonDevice] = {}
|
886
812
|
for device in self._devices.values():
|
887
813
|
# Remove stale, orphaned and virtual devices
|
888
|
-
|
889
|
-
if not devices_node or (devices_node.get("deviceType") in DEVICE_TO_IGNORE):
|
814
|
+
if not device or (device.get("deviceType") in DEVICE_TO_IGNORE):
|
890
815
|
continue
|
891
816
|
|
892
|
-
|
893
|
-
do_not_disturb_node = device[NODE_DO_NOT_DISTURB]
|
894
|
-
bluetooth_node = device[NODE_BLUETOOTH]
|
895
|
-
identifier_node = device.get(NODE_IDENTIFIER, {})
|
896
|
-
|
817
|
+
serial_number: str = device["serialNumber"]
|
897
818
|
# Add sensors
|
898
|
-
sensors = {}
|
899
|
-
|
900
|
-
for _device_id, _device_sensors in devices_sensors.items():
|
901
|
-
if _device_id == identifier_node["entityId"]:
|
902
|
-
sensors = _device_sensors
|
819
|
+
sensors = devices_sensors.get(serial_number, {})
|
820
|
+
device_endpoint = devices_endpoints.get(serial_number, {})
|
903
821
|
|
904
|
-
serial_number: str = devices_node["serialNumber"]
|
905
822
|
final_devices_list[serial_number] = AmazonDevice(
|
906
|
-
account_name=
|
907
|
-
capabilities=
|
908
|
-
device_family=
|
909
|
-
device_type=
|
910
|
-
device_owner_customer_id=
|
911
|
-
device_cluster_members=(
|
912
|
-
|
913
|
-
),
|
914
|
-
online=devices_node["online"],
|
823
|
+
account_name=device["accountName"],
|
824
|
+
capabilities=device["capabilities"],
|
825
|
+
device_family=device["deviceFamily"],
|
826
|
+
device_type=device["deviceType"],
|
827
|
+
device_owner_customer_id=device["deviceOwnerCustomerId"],
|
828
|
+
device_cluster_members=(device["clusterMembers"] or [serial_number]),
|
829
|
+
online=device["online"],
|
915
830
|
serial_number=serial_number,
|
916
|
-
software_version=
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
831
|
+
software_version=device["softwareVersion"],
|
832
|
+
entity_id=device_endpoint["legacyIdentifiers"]["chrsIdentifier"][
|
833
|
+
"entityId"
|
834
|
+
]
|
835
|
+
if device_endpoint
|
836
|
+
else None,
|
837
|
+
endpoint_id=device_endpoint["endpointId"] if device_endpoint else None,
|
922
838
|
sensors=sensors,
|
923
839
|
)
|
924
840
|
|
aioamazondevices/const.py
CHANGED
@@ -54,41 +54,10 @@ CSRF_COOKIE = "csrf"
|
|
54
54
|
REFRESH_ACCESS_TOKEN = "access_token" # noqa: S105
|
55
55
|
REFRESH_AUTH_COOKIES = "auth_cookies"
|
56
56
|
|
57
|
-
|
58
|
-
NODE_DO_NOT_DISTURB = "doNotDisturbDeviceStatusList"
|
59
|
-
NODE_PREFERENCES = "devicePreferences"
|
60
|
-
NODE_BLUETOOTH = "bluetoothStates"
|
61
|
-
NODE_IDENTIFIER = "identifier"
|
62
|
-
NODE_SENSORS = "sensors"
|
63
|
-
|
64
|
-
URI_QUERIES = {
|
65
|
-
NODE_DEVICES: "/api/devices-v2/device",
|
66
|
-
NODE_DO_NOT_DISTURB: "/api/dnd/device-status-list",
|
67
|
-
NODE_PREFERENCES: "/api/device-preferences",
|
68
|
-
NODE_BLUETOOTH: "/api/bluetooth",
|
69
|
-
# "/api/ping"
|
70
|
-
# "/api/np/command"
|
71
|
-
# "/api/np/player"
|
72
|
-
# "/api/device-wifi-details"
|
73
|
-
# "/api/activities"
|
74
|
-
# "/api/behaviors/v2/automations"
|
75
|
-
# "/api/notifications"
|
76
|
-
}
|
77
|
-
|
57
|
+
URI_DEVICES = "/api/devices-v2/device"
|
78
58
|
URI_SIGNIN = "/ap/signin"
|
79
|
-
|
80
|
-
URI_SENSORS = "/api/phoenix/state"
|
59
|
+
URI_NEXUS_GRAPHQL = "/nexus/v1/graphql"
|
81
60
|
|
82
|
-
SENSORS = [
|
83
|
-
"babyCryDetectionState",
|
84
|
-
"beepingApplianceDetectionState",
|
85
|
-
"coughDetectionState",
|
86
|
-
"dogBarkDetectionState",
|
87
|
-
"humanPresenceDetectionState",
|
88
|
-
"illuminance",
|
89
|
-
"temperature",
|
90
|
-
"waterSoundsDetectionState",
|
91
|
-
]
|
92
61
|
SENSOR_STATE_OFF = "NOT_DETECTED"
|
93
62
|
|
94
63
|
# File extensions
|
@@ -100,6 +69,32 @@ BIN_EXTENSION = ".bin"
|
|
100
69
|
SPEAKER_GROUP_FAMILY = "WHA"
|
101
70
|
SPEAKER_GROUP_MODEL = "Speaker Group"
|
102
71
|
|
72
|
+
SENSORS: dict[str, dict[str, str | None]] = {
|
73
|
+
"temperatureSensor": {
|
74
|
+
"name": "temperature",
|
75
|
+
"key": "value",
|
76
|
+
"subkey": "value",
|
77
|
+
"scale": "scale",
|
78
|
+
},
|
79
|
+
"motionSensor": {
|
80
|
+
"name": "motion",
|
81
|
+
"key": "detectionStateValue",
|
82
|
+
"subkey": None,
|
83
|
+
"scale": None,
|
84
|
+
},
|
85
|
+
"lightSensor": {
|
86
|
+
"name": "illuminance",
|
87
|
+
"key": "illuminanceValue",
|
88
|
+
"subkey": "value",
|
89
|
+
"scale": None,
|
90
|
+
},
|
91
|
+
"speaker": {
|
92
|
+
"name": "volume",
|
93
|
+
"key": "value",
|
94
|
+
"subkey": "volValue",
|
95
|
+
"scale": None,
|
96
|
+
},
|
97
|
+
}
|
103
98
|
DEVICE_TO_IGNORE: list[str] = [
|
104
99
|
AMAZON_DEVICE_TYPE, # Alexa App for iOS
|
105
100
|
"A2TF17PFR55MTB", # Alexa App for Android
|
@@ -0,0 +1,91 @@
|
|
1
|
+
"""GraphQL Queries."""
|
2
|
+
|
3
|
+
QUERY_DEVICE_STATE = """
|
4
|
+
query getDevicesState ($latencyTolerance: LatencyToleranceValue) {
|
5
|
+
listEndpoints(listEndpointsInput: {}) {
|
6
|
+
endpoints {
|
7
|
+
endpointId: id
|
8
|
+
friendlyNameObject { value { text } }
|
9
|
+
manufacturer { value { text } }
|
10
|
+
model { value { text} }
|
11
|
+
serialNumber { value { text } }
|
12
|
+
softwareVersion { value { text } }
|
13
|
+
creationTime
|
14
|
+
enablement
|
15
|
+
settings {
|
16
|
+
doNotDisturb {
|
17
|
+
id
|
18
|
+
endpointId
|
19
|
+
name
|
20
|
+
toggleValue
|
21
|
+
error {
|
22
|
+
type
|
23
|
+
message
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
displayCategories {
|
28
|
+
all { value }
|
29
|
+
primary { value }
|
30
|
+
}
|
31
|
+
alexaEnabledMetadata {
|
32
|
+
iconId
|
33
|
+
isVisible
|
34
|
+
category
|
35
|
+
capabilities
|
36
|
+
}
|
37
|
+
legacyIdentifiers {
|
38
|
+
dmsIdentifier {
|
39
|
+
deviceType { value { text } }
|
40
|
+
}
|
41
|
+
chrsIdentifier { entityId }
|
42
|
+
}
|
43
|
+
legacyAppliance { applianceId }
|
44
|
+
associatedUnits { id }
|
45
|
+
connections {
|
46
|
+
type
|
47
|
+
macAddress
|
48
|
+
bleMeshDeviceUuid
|
49
|
+
}
|
50
|
+
features(latencyToleranceValue: $latencyTolerance) {
|
51
|
+
name
|
52
|
+
instance
|
53
|
+
properties {
|
54
|
+
name
|
55
|
+
type
|
56
|
+
accuracy
|
57
|
+
error { message }
|
58
|
+
__typename
|
59
|
+
... on Illuminance {
|
60
|
+
illuminanceValue { value }
|
61
|
+
timeOfSample
|
62
|
+
timeOfLastChange
|
63
|
+
}
|
64
|
+
... on Reachability {
|
65
|
+
reachabilityStatusValue
|
66
|
+
timeOfSample
|
67
|
+
timeOfLastChange
|
68
|
+
}
|
69
|
+
... on DetectionState {
|
70
|
+
detectionStateValue
|
71
|
+
timeOfSample
|
72
|
+
timeOfLastChange
|
73
|
+
}
|
74
|
+
... on Volume {
|
75
|
+
value { volValue: value }
|
76
|
+
}
|
77
|
+
... on TemperatureSensor {
|
78
|
+
name
|
79
|
+
value {
|
80
|
+
value
|
81
|
+
scale
|
82
|
+
}
|
83
|
+
timeOfSample
|
84
|
+
timeOfLastChange
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
"""
|
@@ -0,0 +1,12 @@
|
|
1
|
+
aioamazondevices/__init__.py,sha256=DwM24CsEnErtxa0qE6fKSesGDpmcjKoMg3pl8-BRZoo,276
|
2
|
+
aioamazondevices/api.py,sha256=-GQPzbRH8-2hfFoS4CF4hrDTStmmwc5lotiFBKFuH40,40656
|
3
|
+
aioamazondevices/const.py,sha256=bqJmaStichdm0zB1RQYXa4OPz2gU2JnmUFQHeItlnZE,10808
|
4
|
+
aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
|
5
|
+
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
aioamazondevices/query.py,sha256=AGHHzefzfYzB7RLWPtlFxYc_rpUZdoeApsU2jYz3urQ,2053
|
7
|
+
aioamazondevices/sounds.py,sha256=CXMDk-KoKVFxBdVAw3MeOClqgpzcVDxvQhFOJp7qX-Y,1896
|
8
|
+
aioamazondevices/utils.py,sha256=RzuKRhnq_8ymCoJMoQJ2vBYyuew06RSWpqQWmqdNczE,2019
|
9
|
+
aioamazondevices-6.1.0.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
10
|
+
aioamazondevices-6.1.0.dist-info/METADATA,sha256=3ZCsm8H5iusSSQdjGtJQl2_Ipk6KXhg7K5gv8eILlA8,7623
|
11
|
+
aioamazondevices-6.1.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
12
|
+
aioamazondevices-6.1.0.dist-info/RECORD,,
|
@@ -1,11 +0,0 @@
|
|
1
|
-
aioamazondevices/__init__.py,sha256=GhICpBBVmQJhJULmStwil0XH8o4lS1ggwhsvwjoYWbI,276
|
2
|
-
aioamazondevices/api.py,sha256=YkkMTI8nP1Xop6LtujHXipqEmubnhZ7SBquaU0c2NHs,44709
|
3
|
-
aioamazondevices/const.py,sha256=XI_PvlmyAFtRWko36gaNEzg6JVHJO_i8dIjLzkA6Yo0,11033
|
4
|
-
aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
|
5
|
-
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
aioamazondevices/sounds.py,sha256=CXMDk-KoKVFxBdVAw3MeOClqgpzcVDxvQhFOJp7qX-Y,1896
|
7
|
-
aioamazondevices/utils.py,sha256=RzuKRhnq_8ymCoJMoQJ2vBYyuew06RSWpqQWmqdNczE,2019
|
8
|
-
aioamazondevices-6.0.0.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
9
|
-
aioamazondevices-6.0.0.dist-info/METADATA,sha256=i_ZkJRhmvIg3z8KBT4DzS6LwkWQlXOLVTUkGWQG0wAc,7623
|
10
|
-
aioamazondevices-6.0.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
11
|
-
aioamazondevices-6.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|