diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ef0873f..6b002704 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,89 @@
# Changelog
-## [0.8.1](https://github.com/python-kasa/python-kasa/tree/0.8.1) (2024-12-06)
+## [0.9.0](https://github.com/python-kasa/python-kasa/tree/0.9.0) (2024-12-21)
-This patch release fixes some issues with newly supported smartcam devices.
+[Full Changelog](https://github.com/python-kasa/python-kasa/compare/0.8.1...0.9.0)
+
+**Release highlights:**
+
+- Improvements to Tapo camera support:
+ - C100, C225, C325WB, C520WS and TC70 now supported.
+ - Support for motion, person, tamper, and baby cry detection.
+- Initial support for Tapo robovacs.
+- API extended with `FeatureAttributes` for consumers to test for [supported features](https://python-kasa.readthedocs.io/en/stable/topics.html#modules-and-features).
+- Experimental support for Kasa cameras[^1]
+
+[^1]: Currently limited to devices not yet provisioned via the Tapo app - Many thanks to @puxtril!
+
+**Breaking changes:**
+
+- Use DeviceInfo consistently across devices [\#1338](https://github.com/python-kasa/python-kasa/pull/1338) (@sdb9696)
+
+**Implemented enhancements:**
+
+- Add rssi and signal\_level to smartcam [\#1392](https://github.com/python-kasa/python-kasa/pull/1392) (@sdb9696)
+- Add smartcam detection modules [\#1389](https://github.com/python-kasa/python-kasa/pull/1389) (@sdb9696)
+- Add bare-bones matter modules to smart and smartcam devices [\#1371](https://github.com/python-kasa/python-kasa/pull/1371) (@sdb9696)
+- Add bare bones homekit modules smart and smartcam devices [\#1370](https://github.com/python-kasa/python-kasa/pull/1370) (@sdb9696)
+- Return raw discovery result in cli discover raw [\#1342](https://github.com/python-kasa/python-kasa/pull/1342) (@sdb9696)
+- cli: print model, https, and lv for discover list [\#1339](https://github.com/python-kasa/python-kasa/pull/1339) (@rytilahti)
+- Improve overheat reporting [\#1335](https://github.com/python-kasa/python-kasa/pull/1335) (@rytilahti)
+- Provide alternative camera urls [\#1316](https://github.com/python-kasa/python-kasa/pull/1316) (@sdb9696)
+- Add LinkieTransportV2 and basic IOT.IPCAMERA support [\#1270](https://github.com/python-kasa/python-kasa/pull/1270) (@Puxtril)
+- Add ssltransport for robovacs [\#943](https://github.com/python-kasa/python-kasa/pull/943) (@rytilahti)
+
+**Fixed bugs:**
+
+- Tapo H200 Hub does not work with python-kasa [\#1149](https://github.com/python-kasa/python-kasa/issues/1149)
+- Treat smartcam 500 errors after handshake as retryable [\#1395](https://github.com/python-kasa/python-kasa/pull/1395) (@sdb9696)
+- Fix lens mask required component and state [\#1386](https://github.com/python-kasa/python-kasa/pull/1386) (@sdb9696)
+- Add LensMask module to smartcam [\#1385](https://github.com/python-kasa/python-kasa/pull/1385) (@sdb9696)
+- Do not error when accessing smart device\_type before update [\#1319](https://github.com/python-kasa/python-kasa/pull/1319) (@sdb9696)
+- Fallback to other module data on get\_energy\_usage errors [\#1245](https://github.com/python-kasa/python-kasa/pull/1245) (@rytilahti)
+
+**Added support for devices:**
+
+- Add P210M\(US\) 1.0 1.0.3 fixture [\#1399](https://github.com/python-kasa/python-kasa/pull/1399) (@sdb9696)
+- Add C225\(US\) 2.0 1.0.11 fixture [\#1398](https://github.com/python-kasa/python-kasa/pull/1398) (@sdb9696)
+- Add P306\(US\) 1.0 1.1.2 fixture [\#1396](https://github.com/python-kasa/python-kasa/pull/1396) (@nakanaela)
+- Add TC70 3.0 1.3.11 fixture [\#1390](https://github.com/python-kasa/python-kasa/pull/1390) (@sdb9696)
+- Add C325WB\(EU\) 1.0 1.1.17 Fixture [\#1379](https://github.com/python-kasa/python-kasa/pull/1379) (@sdb9696)
+- Add C100 4.0 1.3.14 Fixture [\#1378](https://github.com/python-kasa/python-kasa/pull/1378) (@sdb9696)
+- Add KS200 \(US\) IOT Fixture and P115 \(US\) Smart Fixture [\#1355](https://github.com/python-kasa/python-kasa/pull/1355) (@ZeliardM)
+- Add C520WS camera fixture [\#1352](https://github.com/python-kasa/python-kasa/pull/1352) (@Happy-Cadaver)
+
+**Documentation updates:**
+
+- Update docs for Tapo Lab Third-Party compatibility [\#1380](https://github.com/python-kasa/python-kasa/pull/1380) (@sdb9696)
+- Add homebridge-kasa-python link to README [\#1367](https://github.com/python-kasa/python-kasa/pull/1367) (@rytilahti)
+- Update docs for new FeatureAttribute behaviour [\#1365](https://github.com/python-kasa/python-kasa/pull/1365) (@sdb9696)
+- Add link to related homeassistant-tapo-control [\#1333](https://github.com/python-kasa/python-kasa/pull/1333) (@rytilahti)
+
+**Project maintenance:**
+
+- Add P135 1.0 1.2.0 fixture [\#1397](https://github.com/python-kasa/python-kasa/pull/1397) (@sdb9696)
+- Handle smartcam device blocked response [\#1393](https://github.com/python-kasa/python-kasa/pull/1393) (@sdb9696)
+- Handle KeyboardInterrupts in the cli better [\#1391](https://github.com/python-kasa/python-kasa/pull/1391) (@sdb9696)
+- Update C520WS fixture with new methods [\#1384](https://github.com/python-kasa/python-kasa/pull/1384) (@sdb9696)
+- Miscellaneous minor fixes to dump\_devinfo [\#1382](https://github.com/python-kasa/python-kasa/pull/1382) (@sdb9696)
+- Add timeout parameter to dump\_devinfo [\#1381](https://github.com/python-kasa/python-kasa/pull/1381) (@sdb9696)
+- Simplify get\_protocol to prevent clashes with smartcam and robovac [\#1377](https://github.com/python-kasa/python-kasa/pull/1377) (@sdb9696)
+- Add smartcam modules to package inits [\#1376](https://github.com/python-kasa/python-kasa/pull/1376) (@sdb9696)
+- Enable saving of fixture files without git clone [\#1375](https://github.com/python-kasa/python-kasa/pull/1375) (@sdb9696)
+- Force single for some smartcam requests [\#1374](https://github.com/python-kasa/python-kasa/pull/1374) (@sdb9696)
+- Add new methods to dump\_devinfo [\#1373](https://github.com/python-kasa/python-kasa/pull/1373) (@sdb9696)
+- Update cli, light modules, and docs to use FeatureAttributes [\#1364](https://github.com/python-kasa/python-kasa/pull/1364) (@sdb9696)
+- Pass raw components to SmartChildDevice init [\#1363](https://github.com/python-kasa/python-kasa/pull/1363) (@sdb9696)
+- Fix line endings in device\_fixtures.py [\#1361](https://github.com/python-kasa/python-kasa/pull/1361) (@sdb9696)
+- Update dump\_devinfo for raw discovery json and common redactors [\#1358](https://github.com/python-kasa/python-kasa/pull/1358) (@sdb9696)
+- Tweak RELEASING.md instructions for patch releases [\#1347](https://github.com/python-kasa/python-kasa/pull/1347) (@sdb9696)
+- Scrub more vacuum keys [\#1328](https://github.com/python-kasa/python-kasa/pull/1328) (@rytilahti)
+- Remove unnecessary check for python \<3.10 [\#1326](https://github.com/python-kasa/python-kasa/pull/1326) (@rytilahti)
+- Add vacuum component queries to dump\_devinfo [\#1320](https://github.com/python-kasa/python-kasa/pull/1320) (@rytilahti)
+- Handle missing mgt\_encryption\_schm in discovery [\#1318](https://github.com/python-kasa/python-kasa/pull/1318) (@sdb9696)
+- Follow main package structure for tests [\#1317](https://github.com/python-kasa/python-kasa/pull/1317) (@rytilahti)
+
+## [0.8.1](https://github.com/python-kasa/python-kasa/tree/0.8.1) (2024-12-06)
[Full Changelog](https://github.com/python-kasa/python-kasa/compare/0.8.0...0.8.1)
@@ -46,28 +127,28 @@ Special thanks to @ryenitcher and @Puxtril for their new contributions to the im
- Update cli feature command for actions not to require a value [\#1264](https://github.com/python-kasa/python-kasa/pull/1264) (@sdb9696)
- Add pan tilt camera module [\#1261](https://github.com/python-kasa/python-kasa/pull/1261) (@sdb9696)
- Add alarm module for smartcamera hubs [\#1258](https://github.com/python-kasa/python-kasa/pull/1258) (@sdb9696)
-- Move TAPO smartcamera out of experimental package [\#1255](https://github.com/python-kasa/python-kasa/pull/1255) (@sdb9696)
- Add SmartCamera Led Module [\#1249](https://github.com/python-kasa/python-kasa/pull/1249) (@sdb9696)
-- Use component queries to select smartcamera modules [\#1248](https://github.com/python-kasa/python-kasa/pull/1248) (@sdb9696)
- Print formatting for IotLightPreset [\#1216](https://github.com/python-kasa/python-kasa/pull/1216) (@Puxtril)
- Allow getting Annotated features from modules [\#1018](https://github.com/python-kasa/python-kasa/pull/1018) (@sdb9696)
+- Move TAPO smartcamera out of experimental package [\#1255](https://github.com/python-kasa/python-kasa/pull/1255) (@sdb9696)
+- Use component queries to select smartcamera modules [\#1248](https://github.com/python-kasa/python-kasa/pull/1248) (@sdb9696)
- Add common Thermostat module [\#977](https://github.com/python-kasa/python-kasa/pull/977) (@sdb9696)
**Fixed bugs:**
- TP-Link Tapo S505D cannot disable gradual on/off [\#1309](https://github.com/python-kasa/python-kasa/issues/1309)
-- Inconsistent emeter information between features and emeter cli [\#1308](https://github.com/python-kasa/python-kasa/issues/1308)
- How to dump power usage after latest updates? [\#1306](https://github.com/python-kasa/python-kasa/issues/1306)
- kasa.discover: Got unsupported connection type: 'device\_family': 'SMART.IPCAMERA' [\#1267](https://github.com/python-kasa/python-kasa/issues/1267)
- device \_\_repr\_\_ fails if no sys\_info [\#1262](https://github.com/python-kasa/python-kasa/issues/1262)
- Tapo P110M: Error processing Energy for device, module will be unavailable: get\_energy\_usage for Energy [\#1243](https://github.com/python-kasa/python-kasa/issues/1243)
- Listing light presets throws error [\#1201](https://github.com/python-kasa/python-kasa/issues/1201)
-- Include duration when disabling smooth transition on/off [\#1313](https://github.com/python-kasa/python-kasa/pull/1313) (@rytilahti)
-- Expose energy command to cli [\#1307](https://github.com/python-kasa/python-kasa/pull/1307) (@rytilahti)
+- Inconsistent emeter information between features and emeter cli [\#1308](https://github.com/python-kasa/python-kasa/issues/1308)
- Make discovery on unsupported devices less noisy [\#1291](https://github.com/python-kasa/python-kasa/pull/1291) (@rytilahti)
- Fix repr for device created with no sysinfo or discovery info" [\#1266](https://github.com/python-kasa/python-kasa/pull/1266) (@sdb9696)
- Fix discovery by alias for smart devices [\#1260](https://github.com/python-kasa/python-kasa/pull/1260) (@sdb9696)
- Make \_\_repr\_\_ work on discovery info [\#1233](https://github.com/python-kasa/python-kasa/pull/1233) (@rytilahti)
+- Include duration when disabling smooth transition on/off [\#1313](https://github.com/python-kasa/python-kasa/pull/1313) (@rytilahti)
+- Expose energy command to cli [\#1307](https://github.com/python-kasa/python-kasa/pull/1307) (@rytilahti)
**Added support for devices:**
@@ -81,13 +162,11 @@ Special thanks to @ryenitcher and @Puxtril for their new contributions to the im
**Documentation updates:**
- Use markdown footnotes in supported.md [\#1310](https://github.com/python-kasa/python-kasa/pull/1310) (@sdb9696)
-- Update docs for the new module attributes has/get feature [\#1301](https://github.com/python-kasa/python-kasa/pull/1301) (@sdb9696)
- Fixup contributing.md for running test against a real device [\#1236](https://github.com/python-kasa/python-kasa/pull/1236) (@sdb9696)
+- Update docs for the new module attributes has/get feature [\#1301](https://github.com/python-kasa/python-kasa/pull/1301) (@sdb9696)
**Project maintenance:**
-- Rename tests/smartcamera to tests/smartcam [\#1315](https://github.com/python-kasa/python-kasa/pull/1315) (@sdb9696)
-- Do not error on smartcam hub attached smartcam child devices [\#1314](https://github.com/python-kasa/python-kasa/pull/1314) (@sdb9696)
- Add P110M\(EU\) fixture [\#1305](https://github.com/python-kasa/python-kasa/pull/1305) (@sdb9696)
- Run tests with caplog in a single worker [\#1304](https://github.com/python-kasa/python-kasa/pull/1304) (@sdb9696)
- Rename smartcamera to smartcam [\#1300](https://github.com/python-kasa/python-kasa/pull/1300) (@sdb9696)
@@ -117,15 +196,17 @@ Special thanks to @ryenitcher and @Puxtril for their new contributions to the im
- Add linkcheck to readthedocs CI [\#1253](https://github.com/python-kasa/python-kasa/pull/1253) (@rytilahti)
- Update cli energy command to use energy module [\#1252](https://github.com/python-kasa/python-kasa/pull/1252) (@sdb9696)
- Consolidate warnings for fixtures missing child devices [\#1251](https://github.com/python-kasa/python-kasa/pull/1251) (@sdb9696)
-- Update smartcamera fixtures with components [\#1250](https://github.com/python-kasa/python-kasa/pull/1250) (@sdb9696)
- Move transports into their own package [\#1247](https://github.com/python-kasa/python-kasa/pull/1247) (@rytilahti)
-- Fix warnings in our test suite [\#1246](https://github.com/python-kasa/python-kasa/pull/1246) (@rytilahti)
- Move tests folder to top level of project [\#1242](https://github.com/python-kasa/python-kasa/pull/1242) (@sdb9696)
-- Fix test framework running against real devices [\#1235](https://github.com/python-kasa/python-kasa/pull/1235) (@sdb9696)
- Add Additional Firmware Test Fixures [\#1234](https://github.com/python-kasa/python-kasa/pull/1234) (@ryenitcher)
-- Update DiscoveryResult to use Mashumaro instead of pydantic [\#1231](https://github.com/python-kasa/python-kasa/pull/1231) (@sdb9696)
- Update fixture for ES20M 1.0.11 [\#1215](https://github.com/python-kasa/python-kasa/pull/1215) (@rytilahti)
- Enable ruff check for ANN [\#1139](https://github.com/python-kasa/python-kasa/pull/1139) (@rytilahti)
+- Rename tests/smartcamera to tests/smartcam [\#1315](https://github.com/python-kasa/python-kasa/pull/1315) (@sdb9696)
+- Do not error on smartcam hub attached smartcam child devices [\#1314](https://github.com/python-kasa/python-kasa/pull/1314) (@sdb9696)
+- Update smartcamera fixtures with components [\#1250](https://github.com/python-kasa/python-kasa/pull/1250) (@sdb9696)
+- Fix warnings in our test suite [\#1246](https://github.com/python-kasa/python-kasa/pull/1246) (@rytilahti)
+- Fix test framework running against real devices [\#1235](https://github.com/python-kasa/python-kasa/pull/1235) (@sdb9696)
+- Update DiscoveryResult to use Mashumaro instead of pydantic [\#1231](https://github.com/python-kasa/python-kasa/pull/1231) (@sdb9696)
**Closed issues:**
diff --git a/README.md b/README.md
index 90c9ac0f..cac04796 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,10 @@ The following devices have been tested and confirmed as working. If your device
> [!NOTE]
> The hub attached Tapo buttons S200B and S200D do not currently support alerting when the button is pressed.
+> [!NOTE]
+> Some firmware versions of Tapo Cameras will not authenticate unless you enable "Tapo Lab" > "Third-Party Compatibility" in the native Tapo app.
+> Alternatively, you can factory reset and then prevent the device from accessing the internet.
+
### Supported Kasa devices
@@ -193,11 +197,11 @@ The following devices have been tested and confirmed as working. If your device
### Supported Tapo[^1] devices
- **Plugs**: P100, P110, P110M, P115, P125M, P135, TP15
-- **Power Strips**: P300, P304M, TP25
+- **Power Strips**: P210M, P300, P304M, P306, TP25
- **Wall Switches**: S500D, S505, S505D
- **Bulbs**: L510B, L510E, L530E, L630
- **Light Strips**: L900-10, L900-5, L920-5, L930-5
-- **Cameras**: C210, C520WS, TC65
+- **Cameras**: C100, C210, C225, C325WB, C520WS, TC65, TC70
- **Hubs**: H100, H200
- **Hub-Connected Devices[^3]**: S200B, S200D, T100, T110, T300, T310, T315
@@ -223,6 +227,7 @@ See [supported devices in our documentation](SUPPORTED.md) for more detailed inf
* [Home Assistant](https://www.home-assistant.io/integrations/tplink/)
* [MQTT access to TP-Link devices, using python-kasa](https://github.com/flavio-fernandes/mqtt2kasa)
+* [Homebridge Kasa Python Plug-In](https://github.com/ZeliardM/homebridge-kasa-python)
### Other related projects
diff --git a/SUPPORTED.md b/SUPPORTED.md
index ba7726cc..795d1346 100644
--- a/SUPPORTED.md
+++ b/SUPPORTED.md
@@ -5,6 +5,9 @@ The following devices have been tested and confirmed as working. If your device
> [!NOTE]
> The hub attached Tapo buttons S200B and S200D do not currently support alerting when the button is pressed.
+> [!NOTE]
+> Some firmware versions of Tapo Cameras will not authenticate unless you enable "Tapo Lab" > "Third-Party Compatibility" in the native Tapo app.
+> Alternatively, you can factory reset and then prevent the device from accessing the internet.
@@ -199,17 +202,22 @@ All Tapo devices require authentication.
Hub-Connected Devices may work acros
- Hardware: 1.0 (US) / Firmware: 1.1.0
- **P135**
- Hardware: 1.0 (US) / Firmware: 1.0.5
+ - Hardware: 1.0 (US) / Firmware: 1.2.0
- **TP15**
- Hardware: 1.0 (US) / Firmware: 1.0.3
### Power Strips
+- **P210M**
+ - Hardware: 1.0 (US) / Firmware: 1.0.3
- **P300**
- Hardware: 1.0 (EU) / Firmware: 1.0.13
- Hardware: 1.0 (EU) / Firmware: 1.0.15
- Hardware: 1.0 (EU) / Firmware: 1.0.7
- **P304M**
- Hardware: 1.0 (UK) / Firmware: 1.0.3
+- **P306**
+ - Hardware: 1.0 (US) / Firmware: 1.1.2
- **TP25**
- Hardware: 1.0 (US) / Firmware: 1.0.2
@@ -255,13 +263,21 @@ All Tapo devices require authentication.
Hub-Connected Devices may work acros
### Cameras
+- **C100**
+ - Hardware: 4.0 / Firmware: 1.3.14
- **C210**
- Hardware: 2.0 (EU) / Firmware: 1.4.2
- Hardware: 2.0 (EU) / Firmware: 1.4.3
+- **C225**
+ - Hardware: 2.0 (US) / Firmware: 1.0.11
+- **C325WB**
+ - Hardware: 1.0 (EU) / Firmware: 1.1.17
- **C520WS**
- Hardware: 1.0 (US) / Firmware: 1.2.8
- **TC65**
- Hardware: 1.0 / Firmware: 1.3.9
+- **TC70**
+ - Hardware: 3.0 / Firmware: 1.3.11
### Hubs
diff --git a/devtools/dump_devinfo.py b/devtools/dump_devinfo.py
index 7760b6cb..e985ab40 100644
--- a/devtools/dump_devinfo.py
+++ b/devtools/dump_devinfo.py
@@ -10,8 +10,6 @@ and finally execute a query to query all of them at once.
from __future__ import annotations
-import base64
-import collections.abc
import dataclasses
import json
import logging
@@ -19,6 +17,7 @@ import re
import sys
import traceback
from collections import defaultdict, namedtuple
+from collections.abc import Callable
from pathlib import Path
from pprint import pprint
from typing import Any
@@ -39,30 +38,80 @@ from kasa import (
)
from kasa.device_factory import get_protocol
from kasa.deviceconfig import DeviceEncryptionType, DeviceFamily
-from kasa.discover import DiscoveryResult
+from kasa.discover import (
+ NEW_DISCOVERY_REDACTORS,
+ DiscoveredRaw,
+ DiscoveryResult,
+)
from kasa.exceptions import SmartErrorCode
from kasa.protocols import IotProtocol
+from kasa.protocols.iotprotocol import REDACTORS as IOT_REDACTORS
+from kasa.protocols.protocol import redact_data
from kasa.protocols.smartcamprotocol import (
SmartCamProtocol,
_ChildCameraProtocolWrapper,
)
+from kasa.protocols.smartprotocol import REDACTORS as SMART_REDACTORS
from kasa.protocols.smartprotocol import SmartProtocol, _ChildProtocolWrapper
from kasa.smart import SmartChildDevice, SmartDevice
from kasa.smartcam import SmartCamDevice
Call = namedtuple("Call", "module method")
-FixtureResult = namedtuple("FixtureResult", "filename, folder, data")
+FixtureResult = namedtuple("FixtureResult", "filename, folder, data, protocol_suffix")
SMART_FOLDER = "tests/fixtures/smart/"
SMARTCAM_FOLDER = "tests/fixtures/smartcam/"
SMART_CHILD_FOLDER = "tests/fixtures/smart/child/"
IOT_FOLDER = "tests/fixtures/iot/"
+SMART_PROTOCOL_SUFFIX = "SMART"
+SMARTCAM_SUFFIX = "SMARTCAM"
+SMART_CHILD_SUFFIX = "SMART.CHILD"
+IOT_SUFFIX = "IOT"
+
+NO_GIT_FIXTURE_FOLDER = "kasa-fixtures"
+
ENCRYPT_TYPES = [encrypt_type.value for encrypt_type in DeviceEncryptionType]
_LOGGER = logging.getLogger(__name__)
+def _wrap_redactors(redactors: dict[str, Callable[[Any], Any] | None]):
+ """Wrap the redactors for dump_devinfo.
+
+ Will replace all partial REDACT_ values with zeros.
+ If the data item is already scrubbed by dump_devinfo will leave as-is.
+ """
+
+ def _wrap(key: str) -> Any:
+ def _wrapped(redactor: Callable[[Any], Any] | None) -> Any | None:
+ if redactor is None:
+ return lambda x: "**SCRUBBED**"
+
+ def _redact_to_zeros(x: Any) -> Any:
+ if isinstance(x, str) and "REDACT" in x:
+ return re.sub(r"\w", "0", x)
+ if isinstance(x, dict):
+ for k, v in x.items():
+ x[k] = _redact_to_zeros(v)
+ return x
+
+ def _scrub(x: Any) -> Any:
+ if key in {"ip", "local_ip"}:
+ return "127.0.0.123"
+ # Already scrubbed by dump_devinfo
+ if isinstance(x, str) and "SCRUBBED" in x:
+ return x
+ default = redactor(x)
+ return _redact_to_zeros(default)
+
+ return _scrub
+
+ return _wrapped(redactors[key])
+
+ return {key: _wrap(key) for key in redactors}
+
+
@dataclasses.dataclass
class SmartCall:
"""Class for smart and smartcam calls."""
@@ -74,115 +123,6 @@ class SmartCall:
supports_multiple: bool = True
-def scrub(res):
- """Remove identifiers from the given dict."""
- keys_to_scrub = [
- "deviceId",
- "fwId",
- "hwId",
- "oemId",
- "mac",
- "mic_mac",
- "latitude_i",
- "longitude_i",
- "latitude",
- "longitude",
- "la", # lat on ks240
- "lo", # lon on ks240
- "owner",
- "device_id",
- "ip",
- "ssid",
- "hw_id",
- "fw_id",
- "oem_id",
- "nickname",
- "alias",
- "bssid",
- "channel",
- "original_device_id", # for child devices on strips
- "parent_device_id", # for hub children
- "setup_code", # matter
- "setup_payload", # matter
- "mfi_setup_code", # mfi_ for homekit
- "mfi_setup_id",
- "mfi_token_token",
- "mfi_token_uuid",
- "dev_id",
- "device_name",
- "device_alias",
- "connect_ssid",
- "encrypt_info",
- "local_ip",
- "username",
- # vacuum
- "board_sn",
- "custom_sn",
- "location",
- ]
-
- for k, v in res.items():
- if isinstance(v, collections.abc.Mapping):
- if k == "encrypt_info":
- if "data" in v:
- v["data"] = ""
- if "key" in v:
- v["key"] = ""
- else:
- res[k] = scrub(res.get(k))
- elif (
- isinstance(v, list)
- and len(v) > 0
- and isinstance(v[0], collections.abc.Mapping)
- ):
- res[k] = [scrub(vi) for vi in v]
- else:
- if k in keys_to_scrub:
- if k in ["mac", "mic_mac"]:
- # Some macs have : or - as a separator and others do not
- if len(v) == 12:
- v = f"{v[:6]}000000"
- else:
- delim = ":" if ":" in v else "-"
- rest = delim.join(
- format(s, "02x") for s in bytes.fromhex("000000")
- )
- v = f"{v[:8]}{delim}{rest}"
- elif k in ["latitude", "latitude_i", "longitude", "longitude_i"]:
- v = 0
- elif k in ["ip", "local_ip"]:
- v = "127.0.0.123"
- elif k in ["ssid"]:
- # Need a valid base64 value here
- v = base64.b64encode(b"#MASKED_SSID#").decode()
- elif k in ["nickname"]:
- v = base64.b64encode(b"#MASKED_NAME#").decode()
- elif k in [
- "alias",
- "device_alias",
- "device_name",
- "username",
- "location",
- ]:
- v = "#MASKED_NAME#"
- elif isinstance(res[k], int):
- v = 0
- elif k in ["map_data"]: #
- v = "#SCRUBBED_MAPDATA#"
- elif k in ["device_id", "dev_id"] and "SCRUBBED" in v:
- pass # already scrubbed
- elif k == ["device_id", "dev_id"] and len(v) > 40:
- # retain the last two chars when scrubbing child ids
- end = v[-2:]
- v = re.sub(r"\w", "0", v)
- v = v[:40] + end
- else:
- v = re.sub(r"\w", "0", v)
-
- res[k] = v
- return res
-
-
def default_to_regular(d):
"""Convert nested defaultdicts to regular ones.
@@ -207,9 +147,19 @@ async def handle_device(
]
for fixture_result in fixture_results:
- save_filename = Path(basedir) / fixture_result.folder / fixture_result.filename
+ save_folder = Path(basedir) / fixture_result.folder
+ if save_folder.exists():
+ save_filename = save_folder / f"{fixture_result.filename}.json"
+ else:
+ # If being run without git clone
+ save_folder = Path(basedir) / NO_GIT_FIXTURE_FOLDER
+ save_folder.mkdir(exist_ok=True)
+ save_filename = (
+ save_folder
+ / f"{fixture_result.filename}-{fixture_result.protocol_suffix}.json"
+ )
- pprint(scrub(fixture_result.data))
+ pprint(fixture_result.data)
if autosave:
save = "y"
else:
@@ -300,6 +250,12 @@ async def handle_device(
type=bool,
help="Set flag if the device encryption uses https.",
)
+@click.option(
+ "--timeout",
+ required=False,
+ default=15,
+ help="Timeout for queries.",
+)
@click.option("--port", help="Port override", type=int)
async def cli(
host,
@@ -317,6 +273,7 @@ async def cli(
device_family,
login_version,
port,
+ timeout,
):
"""Generate devinfo files for devices.
@@ -325,6 +282,11 @@ async def cli(
if debug:
logging.basicConfig(level=logging.DEBUG)
+ raw_discovery = {}
+
+ def capture_raw(discovered: DiscoveredRaw):
+ raw_discovery[discovered["meta"]["ip"]] = discovered["discovery_response"]
+
credentials = Credentials(username=username, password=password)
if host is not None:
if discovery_info:
@@ -342,6 +304,7 @@ async def cli(
connection_type=connection_type,
port_override=port,
credentials=credentials,
+ timeout=timeout,
)
device = await Device.connect(config=dc)
await handle_device(
@@ -363,6 +326,7 @@ async def cli(
port_override=port,
credentials=credentials,
connection_type=ctype,
+ timeout=timeout,
)
if protocol := get_protocol(config):
await handle_device(basedir, autosave, protocol, batch_size=batch_size)
@@ -377,12 +341,17 @@ async def cli(
credentials=credentials,
port=port,
discovery_timeout=discovery_timeout,
+ timeout=timeout,
+ on_discovered_raw=capture_raw,
)
+ discovery_info = raw_discovery[device.host]
+ if decrypted_data := device._discovery_info.get("decrypted_data"):
+ discovery_info["result"]["decrypted_data"] = decrypted_data
await handle_device(
basedir,
autosave,
device.protocol,
- discovery_info=device._discovery_info,
+ discovery_info=discovery_info,
batch_size=batch_size,
)
else:
@@ -391,21 +360,29 @@ async def cli(
f" {target}. Use --target to override."
)
devices = await Discover.discover(
- target=target, credentials=credentials, discovery_timeout=discovery_timeout
+ target=target,
+ credentials=credentials,
+ discovery_timeout=discovery_timeout,
+ timeout=timeout,
+ on_discovered_raw=capture_raw,
)
click.echo(f"Detected {len(devices)} devices")
for dev in devices.values():
+ discovery_info = raw_discovery[dev.host]
+ if decrypted_data := dev._discovery_info.get("decrypted_data"):
+ discovery_info["result"]["decrypted_data"] = decrypted_data
+
await handle_device(
basedir,
autosave,
dev.protocol,
- discovery_info=dev._discovery_info,
+ discovery_info=discovery_info,
batch_size=batch_size,
)
async def get_legacy_fixture(
- protocol: IotProtocol, *, discovery_info: dict[str, Any] | None
+ protocol: IotProtocol, *, discovery_info: dict[str, dict[str, Any]] | None
) -> FixtureResult:
"""Get fixture for legacy IOT style protocol."""
items = [
@@ -475,11 +452,21 @@ async def get_legacy_fixture(
_echo_error(f"Unable to query all successes at once: {ex}")
finally:
await protocol.close()
+
+ final = redact_data(final, _wrap_redactors(IOT_REDACTORS))
+
+ # Scrub the child device ids
+ if children := final.get("system", {}).get("get_sysinfo", {}).get("children"):
+ for index, child in enumerate(children):
+ if "id" not in child:
+ _LOGGER.error("Could not find a device for the child device: %s", child)
+ else:
+ child["id"] = f"SCRUBBED_CHILD_DEVICE_ID_{index + 1}"
+
if discovery_info and not discovery_info.get("system"):
- # Need to recreate a DiscoverResult here because we don't want the aliases
- # in the fixture, we want the actual field names as returned by the device.
- dr = DiscoveryResult.from_dict(discovery_info)
- final["discovery_result"] = dr.to_dict()
+ final["discovery_result"] = redact_data(
+ discovery_info, _wrap_redactors(NEW_DISCOVERY_REDACTORS)
+ )
click.echo(f"Got {len(successes)} successes")
click.echo(click.style("## device info file ##", bold=True))
@@ -489,9 +476,14 @@ async def get_legacy_fixture(
hw_version = sysinfo["hw_ver"]
sw_version = sysinfo["sw_ver"]
sw_version = sw_version.split(" ", maxsplit=1)[0]
- save_filename = f"{model}_{hw_version}_{sw_version}.json"
+ save_filename = f"{model}_{hw_version}_{sw_version}"
copy_folder = IOT_FOLDER
- return FixtureResult(filename=save_filename, folder=copy_folder, data=final)
+ return FixtureResult(
+ filename=save_filename,
+ folder=copy_folder,
+ data=final,
+ protocol_suffix=IOT_SUFFIX,
+ )
def _echo_error(msg: str):
@@ -860,14 +852,20 @@ def get_smart_child_fixture(response):
model = model_info.long_name
if model_info.region is not None:
model = f"{model}({model_info.region})"
- save_filename = f"{model}_{hw_version}_{fw_version}.json"
+ save_filename = f"{model}_{hw_version}_{fw_version}"
return FixtureResult(
- filename=save_filename, folder=SMART_CHILD_FOLDER, data=response
+ filename=save_filename,
+ folder=SMART_CHILD_FOLDER,
+ data=response,
+ protocol_suffix=SMART_CHILD_SUFFIX,
)
async def get_smart_fixtures(
- protocol: SmartProtocol, *, discovery_info: dict[str, Any] | None, batch_size: int
+ protocol: SmartProtocol,
+ *,
+ discovery_info: dict[str, dict[str, Any]] | None,
+ batch_size: int,
) -> list[FixtureResult]:
"""Get fixture for new TAPO style protocol."""
if isinstance(protocol, SmartCamProtocol):
@@ -963,6 +961,7 @@ async def get_smart_fixtures(
and (child_model := response["get_device_info"].get("model"))
and child_model != parent_model
):
+ response = redact_data(response, _wrap_redactors(SMART_REDACTORS))
fixture_results.append(get_smart_child_fixture(response))
else:
cd = final.setdefault("child_devices", {})
@@ -978,43 +977,56 @@ async def get_smart_fixtures(
child["device_id"] = scrubbed_device_ids[device_id]
# Scrub the device ids in the parent for the smart camera protocol
- if gc := final.get("getChildDeviceList"):
- for child in gc["child_device_list"]:
+ if gc := final.get("getChildDeviceComponentList"):
+ for child in gc["child_component_list"]:
+ device_id = child["device_id"]
+ child["device_id"] = scrubbed_device_ids[device_id]
+ for child in final["getChildDeviceList"]["child_device_list"]:
if device_id := child.get("device_id"):
child["device_id"] = scrubbed_device_ids[device_id]
continue
- if device_id := child.get("dev_id"):
- child["dev_id"] = scrubbed_device_ids[device_id]
+ elif dev_id := child.get("dev_id"):
+ child["dev_id"] = scrubbed_device_ids[dev_id]
continue
_LOGGER.error("Could not find a device for the child device: %s", child)
- # Need to recreate a DiscoverResult here because we don't want the aliases
- # in the fixture, we want the actual field names as returned by the device.
+ final = redact_data(final, _wrap_redactors(SMART_REDACTORS))
+ discovery_result = None
if discovery_info:
- dr = DiscoveryResult.from_dict(discovery_info) # type: ignore
- final["discovery_result"] = dr.to_dict()
+ final["discovery_result"] = redact_data(
+ discovery_info, _wrap_redactors(NEW_DISCOVERY_REDACTORS)
+ )
+ discovery_result = discovery_info["result"]
click.echo(f"Got {len(successes)} successes")
click.echo(click.style("## device info file ##", bold=True))
if "get_device_info" in final:
# smart protocol
- model_info = SmartDevice._get_device_info(final, discovery_info)
+ model_info = SmartDevice._get_device_info(final, discovery_result)
copy_folder = SMART_FOLDER
+ protocol_suffix = SMART_PROTOCOL_SUFFIX
else:
# smart camera protocol
- model_info = SmartCamDevice._get_device_info(final, discovery_info)
+ model_info = SmartCamDevice._get_device_info(final, discovery_result)
copy_folder = SMARTCAM_FOLDER
+ protocol_suffix = SMARTCAM_SUFFIX
hw_version = model_info.hardware_version
sw_version = model_info.firmware_version
model = model_info.long_name
if model_info.region is not None:
model = f"{model}({model_info.region})"
- save_filename = f"{model}_{hw_version}_{sw_version}.json"
+ save_filename = f"{model}_{hw_version}_{sw_version}"
fixture_results.insert(
- 0, FixtureResult(filename=save_filename, folder=copy_folder, data=final)
+ 0,
+ FixtureResult(
+ filename=save_filename,
+ folder=copy_folder,
+ data=final,
+ protocol_suffix=protocol_suffix,
+ ),
)
return fixture_results
diff --git a/devtools/generate_supported.py b/devtools/generate_supported.py
index 532c7e6a..7b4e9787 100755
--- a/devtools/generate_supported.py
+++ b/devtools/generate_supported.py
@@ -205,7 +205,7 @@ def _get_supported_devices(
fixture_data = json.load(f)
model_info = device_cls._get_device_info(
- fixture_data, fixture_data.get("discovery_result")
+ fixture_data, fixture_data.get("discovery_result", {}).get("result")
)
supported_type = DEVICE_TYPE_TO_PRODUCT_GROUP[model_info.device_type]
diff --git a/devtools/helpers/smartcamrequests.py b/devtools/helpers/smartcamrequests.py
index 074b5774..5759a44b 100644
--- a/devtools/helpers/smartcamrequests.py
+++ b/devtools/helpers/smartcamrequests.py
@@ -60,4 +60,7 @@ SMARTCAM_REQUESTS: list[dict] = [
{"get": {"motor": {"name": ["capability"]}}},
{"get": {"audio_capability": {"name": ["device_speaker", "device_microphone"]}}},
{"get": {"audio_config": {"name": ["speaker", "microphone"]}}},
+ {"getMatterSetupInfo": {"matter": {}}},
+ {"getConnectStatus": {"onboarding": {"get_connect_status": {}}}},
+ {"scanApList": {"onboarding": {"scan": {}}}},
]
diff --git a/devtools/update_fixtures.py b/devtools/update_fixtures.py
new file mode 100644
index 00000000..13b9996e
--- /dev/null
+++ b/devtools/update_fixtures.py
@@ -0,0 +1,128 @@
+"""Module to mass update fixture files."""
+
+import json
+import logging
+from collections.abc import Callable
+from pathlib import Path
+
+import asyncclick as click
+
+from devtools.dump_devinfo import _wrap_redactors
+from kasa.discover import NEW_DISCOVERY_REDACTORS, redact_data
+from kasa.protocols.iotprotocol import REDACTORS as IOT_REDACTORS
+from kasa.protocols.smartprotocol import REDACTORS as SMART_REDACTORS
+
+FIXTURE_FOLDER = "tests/fixtures/"
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def update_fixtures(update_func: Callable[[dict], bool], *, dry_run: bool) -> None:
+ """Run the update function against the fixtures."""
+ for file in Path(FIXTURE_FOLDER).glob("**/*.json"):
+ with file.open("r") as f:
+ fixture_data = json.load(f)
+
+ if file.parent.name == "serialization":
+ continue
+ changed = update_func(fixture_data)
+ if changed:
+ click.echo(f"Will update {file.name}\n")
+ if changed and not dry_run:
+ with file.open("w") as f:
+ json.dump(fixture_data, f, sort_keys=True, indent=4)
+ f.write("\n")
+
+
+def _discovery_result_update(info) -> bool:
+ """Update discovery_result to be the raw result and error_code."""
+ if (disco_result := info.get("discovery_result")) and "result" not in disco_result:
+ info["discovery_result"] = {
+ "result": disco_result,
+ "error_code": 0,
+ }
+ return True
+ return False
+
+
+def _child_device_id_update(info) -> bool:
+ """Update child device ids to be the scrubbed ids from dump_devinfo."""
+ changed = False
+ if get_child_device_list := info.get("get_child_device_list"):
+ child_device_list = get_child_device_list["child_device_list"]
+ child_component_list = info["get_child_device_component_list"][
+ "child_component_list"
+ ]
+ for index, child_device in enumerate(child_device_list):
+ child_component = child_component_list[index]
+ if "SCRUBBED" not in child_device["device_id"]:
+ dev_id = f"SCRUBBED_CHILD_DEVICE_ID_{index + 1}"
+ click.echo(
+ f"child_device_id{index}: {child_device['device_id']} -> {dev_id}"
+ )
+ child_device["device_id"] = dev_id
+ child_component["device_id"] = dev_id
+ changed = True
+
+ if children := info.get("system", {}).get("get_sysinfo", {}).get("children"):
+ for index, child_device in enumerate(children):
+ if "SCRUBBED" not in child_device["id"]:
+ dev_id = f"SCRUBBED_CHILD_DEVICE_ID_{index + 1}"
+ click.echo(f"child_device_id{index}: {child_device['id']} -> {dev_id}")
+ child_device["id"] = dev_id
+ changed = True
+
+ return changed
+
+
+def _diff_data(fullkey, data1, data2, diffs):
+ if isinstance(data1, dict):
+ for k, v in data1.items():
+ _diff_data(fullkey + "/" + k, v, data2[k], diffs)
+ elif isinstance(data1, list):
+ for index, item in enumerate(data1):
+ _diff_data(fullkey + "/" + str(index), item, data2[index], diffs)
+ elif data1 != data2:
+ diffs[fullkey] = (data1, data2)
+
+
+def _redactor_result_update(info) -> bool:
+ """Update fixtures with the output using the common redactors."""
+ changed = False
+
+ redactors = IOT_REDACTORS if "system" in info else SMART_REDACTORS
+
+ for key, val in info.items():
+ if not isinstance(val, dict):
+ continue
+ if key == "discovery_result":
+ info[key] = redact_data(val, _wrap_redactors(NEW_DISCOVERY_REDACTORS))
+ else:
+ info[key] = redact_data(val, _wrap_redactors(redactors))
+ diffs: dict[str, tuple[str, str]] = {}
+ _diff_data(key, val, info[key], diffs)
+ if diffs:
+ for k, v in diffs.items():
+ click.echo(f"{k}: {v[0]} -> {v[1]}")
+ changed = True
+
+ return changed
+
+
+@click.option(
+ "--dry-run/--no-dry-run",
+ default=False,
+ is_flag=True,
+ type=bool,
+ help="Perform a dry run without saving.",
+)
+@click.command()
+async def cli(dry_run: bool) -> None:
+ """Cli method fo rupdating fixtures."""
+ update_fixtures(_discovery_result_update, dry_run=dry_run)
+ update_fixtures(_child_device_id_update, dry_run=dry_run)
+ update_fixtures(_redactor_result_update, dry_run=dry_run)
+
+
+if __name__ == "__main__":
+ cli()
diff --git a/docs/source/featureattributes.md b/docs/source/featureattributes.md
new file mode 100644
index 00000000..69285ad4
--- /dev/null
+++ b/docs/source/featureattributes.md
@@ -0,0 +1,13 @@
+Some modules have attributes that may not be supported by the device.
+These attributes will be annotated with a `FeatureAttribute` return type.
+For example:
+
+```py
+ @property
+ def hsv(self) -> Annotated[HSV, FeatureAttribute()]:
+ """Return the current HSV state of the bulb."""
+```
+
+You can test whether a `FeatureAttribute` is supported by the device with {meth}`kasa.Module.has_feature`
+or {meth}`kasa.Module.get_feature` which will return `None` if not supported.
+Calling these methods on attributes not annotated with a `FeatureAttribute` return type will return an error.
diff --git a/docs/source/reference.md b/docs/source/reference.md
index f4771ac5..90493c9c 100644
--- a/docs/source/reference.md
+++ b/docs/source/reference.md
@@ -13,11 +13,13 @@
## Device
+% N.B. Credentials clashes with autodoc
```{eval-rst}
.. autoclass:: Device
:members:
:undoc-members:
+ :exclude-members: Credentials
```
@@ -28,7 +30,6 @@
.. autoclass:: Credentials
:members:
:undoc-members:
- :noindex:
```
@@ -61,15 +62,11 @@
```{eval-rst}
.. autoclass:: Module
- :noindex:
:members:
- :inherited-members:
- :undoc-members:
```
```{eval-rst}
.. autoclass:: Feature
- :noindex:
:members:
:inherited-members:
:undoc-members:
@@ -77,7 +74,6 @@
```{eval-rst}
.. automodule:: kasa.interfaces
- :noindex:
:members:
:inherited-members:
:undoc-members:
@@ -85,64 +81,29 @@
## Protocols and transports
+
```{eval-rst}
-.. autoclass:: kasa.protocols.BaseProtocol
+.. automodule:: kasa.protocols
:members:
- :inherited-members:
+ :imported-members:
:undoc-members:
+ :exclude-members: SmartErrorCode
+ :no-index:
```
```{eval-rst}
-.. autoclass:: kasa.protocols.IotProtocol
+.. automodule:: kasa.transports
:members:
- :inherited-members:
+ :imported-members:
:undoc-members:
+ :no-index:
```
-```{eval-rst}
-.. autoclass:: kasa.protocols.SmartProtocol
- :members:
- :inherited-members:
- :undoc-members:
-```
-
-```{eval-rst}
-.. autoclass:: kasa.transports.BaseTransport
- :members:
- :inherited-members:
- :undoc-members:
-```
-
-```{eval-rst}
-.. autoclass:: kasa.transports.XorTransport
- :members:
- :inherited-members:
- :undoc-members:
-```
-
-```{eval-rst}
-.. autoclass:: kasa.transports.KlapTransport
- :members:
- :inherited-members:
- :undoc-members:
-```
-
-```{eval-rst}
-.. autoclass:: kasa.transports.KlapTransportV2
- :members:
- :inherited-members:
- :undoc-members:
-```
-
-```{eval-rst}
-.. autoclass:: kasa.transports.AesTransport
- :members:
- :inherited-members:
- :undoc-members:
-```
## Errors and exceptions
+
+
```{eval-rst}
.. autoclass:: kasa.exceptions.KasaException
:members:
@@ -171,3 +132,4 @@
.. autoclass:: kasa.exceptions.TimeoutError
:members:
:undoc-members:
+```
diff --git a/docs/source/topics.md b/docs/source/topics.md
index 0dcc60d1..f7d0cdd5 100644
--- a/docs/source/topics.md
+++ b/docs/source/topics.md
@@ -80,14 +80,17 @@ This can be done using the {attr}`~kasa.Device.internal_state` property.
## Modules and Features
The functionality provided by all {class}`~kasa.Device` instances is (mostly) done inside separate modules.
-While the individual device-type specific classes provide an easy access for the most import features,
-you can also access individual modules through {attr}`kasa.Device.modules`.
-You can get the list of supported modules for a given device instance using {attr}`~kasa.Device.supported_modules`.
+While the device class provides easy access for most device related attributes,
+for components like `light` and `camera` you can access the module through {attr}`kasa.Device.modules`.
+The module names are handily available as constants on {class}`~kasa.Module` and will return type aware values from the collection.
-```{note}
-If you only need some module-specific information,
-you can call the wanted method on the module to avoid using {meth}`~kasa.Device.update`.
-```
+Features represent individual pieces of functionality within a module like brightness, hsv and temperature within a light module.
+They allow for instrospection and can be accessed through {attr}`kasa.Device.features`.
+Attributes can be accessed via a `Feature` or a module attribute depending on the use case.
+Modules tend to provide richer functionality but using the features does not require an understanding of the module api.
+
+:::{include} featureattributes.md
+:::
(topics-protocols-and-transports)=
## Protocols and Transports
@@ -137,96 +140,3 @@ The base exception for all library errors is {class}`KasaException `.
- If the device fails to respond within a timeout the library raises a {class}`TimeoutError `.
- All other failures will raise the base {class}`KasaException ` class.
-
-
diff --git a/docs/tutorial.py b/docs/tutorial.py
index 903489a7..76094abb 100644
--- a/docs/tutorial.py
+++ b/docs/tutorial.py
@@ -40,7 +40,7 @@ Different groups of functionality are supported by modules which you can access
key from :class:`~kasa.Module`.
Modules will only be available on the device if they are supported but some individual features of a module may not be available for your device.
-You can check the availability using ``is_``-prefixed properties like `is_color`.
+You can check the availability using ``has_feature()`` method.
>>> from kasa import Module
>>> Module.Light in dev.modules
diff --git a/kasa/__init__.py b/kasa/__init__.py
index ee52eb3a..b8871f99 100755
--- a/kasa/__init__.py
+++ b/kasa/__init__.py
@@ -38,7 +38,7 @@ from kasa.feature import Feature
from kasa.interfaces.light import HSV, ColorTempRange, Light, LightState
from kasa.interfaces.thermostat import Thermostat, ThermostatState
from kasa.module import Module
-from kasa.protocols import BaseProtocol, IotProtocol, SmartProtocol
+from kasa.protocols import BaseProtocol, IotProtocol, SmartCamProtocol, SmartProtocol
from kasa.protocols.iotprotocol import _deprecated_TPLinkSmartHomeProtocol # noqa: F401
from kasa.smartcam.modules.camera import StreamResolution
from kasa.transports import BaseTransport
@@ -52,6 +52,7 @@ __all__ = [
"BaseTransport",
"IotProtocol",
"SmartProtocol",
+ "SmartCamProtocol",
"LightState",
"TurnOnBehaviors",
"TurnOnBehavior",
diff --git a/kasa/cli/common.py b/kasa/cli/common.py
index 649df065..5114f7af 100644
--- a/kasa/cli/common.py
+++ b/kasa/cli/common.py
@@ -2,12 +2,14 @@
from __future__ import annotations
+import asyncio
import json
import re
import sys
from collections.abc import Callable
from contextlib import contextmanager
from functools import singledispatch, update_wrapper, wraps
+from gettext import gettext
from typing import TYPE_CHECKING, Any, Final
import asyncclick as click
@@ -238,4 +240,19 @@ def CatchAllExceptions(cls):
except Exception as exc:
_handle_exception(self._debug, exc)
+ def __call__(self, *args, **kwargs):
+ """Run the coroutine in the event loop and print any exceptions.
+
+ python click catches KeyboardInterrupt in main, raises Abort()
+ and does sys.exit. asyncclick doesn't properly handle a coroutine
+ receiving CancelledError on a KeyboardInterrupt, so we catch the
+ KeyboardInterrupt here once asyncio.run has re-raised it. This
+ avoids large stacktraces when a user presses Ctrl-C.
+ """
+ try:
+ asyncio.run(self.main(*args, **kwargs))
+ except KeyboardInterrupt:
+ click.echo(gettext("\nAborted!"), file=sys.stderr)
+ sys.exit(1)
+
return _CommandCls
diff --git a/kasa/cli/device.py b/kasa/cli/device.py
index 2e621368..0ef8a76f 100644
--- a/kasa/cli/device.py
+++ b/kasa/cli/device.py
@@ -41,8 +41,14 @@ async def state(ctx, dev: Device):
echo(f"Device state: {dev.is_on}")
echo(f"Time: {dev.time} (tz: {dev.timezone})")
- echo(f"Hardware: {dev.hw_info['hw_ver']}")
- echo(f"Software: {dev.hw_info['sw_ver']}")
+ echo(
+ f"Hardware: {dev.device_info.hardware_version}"
+ f"{' (' + dev.region + ')' if dev.region else ''}"
+ )
+ echo(
+ f"Firmware: {dev.device_info.firmware_version}"
+ f" {dev.device_info.firmware_build}"
+ )
echo(f"MAC (rssi): {dev.mac} ({dev.rssi})")
if verbose:
echo(f"Location: {dev.location}")
diff --git a/kasa/cli/discover.py b/kasa/cli/discover.py
index 5e676a1d..2470434b 100644
--- a/kasa/cli/discover.py
+++ b/kasa/cli/discover.py
@@ -123,14 +123,19 @@ async def list(ctx):
async def print_discovered(dev: Device):
cparams = dev.config.connection_type
infostr = (
- f"{dev.host:<15} {cparams.device_family.value:<20} "
- f"{cparams.encryption_type.value:<7}"
+ f"{dev.host:<15} {dev.model:<9} {cparams.device_family.value:<20} "
+ f"{cparams.encryption_type.value:<7} {cparams.https:<5} "
+ f"{cparams.login_version or '-':<3}"
)
async with sem:
try:
await dev.update()
except AuthenticationError:
echo(f"{infostr} - Authentication failed")
+ except TimeoutError:
+ echo(f"{infostr} - Timed out")
+ except Exception as ex:
+ echo(f"{infostr} - Error: {ex}")
else:
echo(f"{infostr} {dev.alias}")
@@ -138,7 +143,10 @@ async def list(ctx):
if host := unsupported_exception.host:
echo(f"{host:<15} UNSUPPORTED DEVICE")
- echo(f"{'HOST':<15} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} {'ALIAS'}")
+ echo(
+ f"{'HOST':<15} {'MODEL':<9} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} "
+ f"{'HTTPS':<5} {'LV':<3} {'ALIAS'}"
+ )
return await _discover(
ctx,
print_discovered=print_discovered,
diff --git a/kasa/cli/light.py b/kasa/cli/light.py
index b2909c59..a7785563 100644
--- a/kasa/cli/light.py
+++ b/kasa/cli/light.py
@@ -25,7 +25,9 @@ def light(dev) -> None:
@pass_dev_or_child
async def brightness(dev: Device, brightness: int, transition: int):
"""Get or set brightness."""
- if not (light := dev.modules.get(Module.Light)) or not light.is_dimmable:
+ if not (light := dev.modules.get(Module.Light)) or not light.has_feature(
+ "brightness"
+ ):
error("This device does not support brightness.")
return
@@ -45,13 +47,15 @@ async def brightness(dev: Device, brightness: int, transition: int):
@pass_dev_or_child
async def temperature(dev: Device, temperature: int, transition: int):
"""Get or set color temperature."""
- if not (light := dev.modules.get(Module.Light)) or not light.is_variable_color_temp:
+ if not (light := dev.modules.get(Module.Light)) or not (
+ color_temp_feat := light.get_feature("color_temp")
+ ):
error("Device does not support color temperature")
return
if temperature is None:
echo(f"Color temperature: {light.color_temp}")
- valid_temperature_range = light.valid_temperature_range
+ valid_temperature_range = color_temp_feat.range
if valid_temperature_range != (0, 0):
echo("(min: {}, max: {})".format(*valid_temperature_range))
else:
@@ -59,7 +63,7 @@ async def temperature(dev: Device, temperature: int, transition: int):
"Temperature range unknown, please open a github issue"
f" or a pull request for model '{dev.model}'"
)
- return light.valid_temperature_range
+ return color_temp_feat.range
else:
echo(f"Setting color temperature to {temperature}")
return await light.set_color_temp(temperature, transition=transition)
@@ -99,7 +103,7 @@ async def effect(dev: Device, ctx, effect):
@pass_dev_or_child
async def hsv(dev: Device, ctx, h, s, v, transition):
"""Get or set color in HSV."""
- if not (light := dev.modules.get(Module.Light)) or not light.is_color:
+ if not (light := dev.modules.get(Module.Light)) or not light.has_feature("hsv"):
error("Device does not support colors")
return
diff --git a/kasa/device.py b/kasa/device.py
index 58fea7ff..71539355 100644
--- a/kasa/device.py
+++ b/kasa/device.py
@@ -29,7 +29,7 @@ All devices provide several informational properties:
>>> dev.alias
Bedroom Lamp Plug
>>> dev.model
-HS110(EU)
+HS110
>>> dev.rssi
-71
>>> dev.mac
@@ -151,7 +151,7 @@ _LOGGER = logging.getLogger(__name__)
@dataclass
-class _DeviceInfo:
+class DeviceInfo:
"""Device Model Information."""
short_name: str
@@ -208,7 +208,7 @@ class Device(ABC):
self.protocol: BaseProtocol = protocol or IotProtocol(
transport=XorTransport(config=config or DeviceConfig(host=host)),
)
- self._last_update: Any = None
+ self._last_update: dict[str, Any] = {}
_LOGGER.debug("Initializing %s of type %s", host, type(self))
self._device_type = DeviceType.Unknown
# TODO: typing Any is just as using dict | None would require separate
@@ -334,9 +334,21 @@ class Device(ABC):
"""Returns the device model."""
@property
+ def region(self) -> str | None:
+ """Returns the device region."""
+ return self.device_info.region
+
+ @property
+ def device_info(self) -> DeviceInfo:
+ """Return device info."""
+ return self._get_device_info(self._last_update, self._discovery_info)
+
+ @staticmethod
@abstractmethod
- def _model_region(self) -> str:
- """Return device full model name and region."""
+ def _get_device_info(
+ info: dict[str, Any], discovery_info: dict[str, Any] | None
+ ) -> DeviceInfo:
+ """Get device info."""
@property
@abstractmethod
diff --git a/kasa/device_factory.py b/kasa/device_factory.py
index a1015570..99654a0c 100644
--- a/kasa/device_factory.py
+++ b/kasa/device_factory.py
@@ -8,7 +8,7 @@ from typing import Any
from .device import Device
from .device_type import DeviceType
-from .deviceconfig import DeviceConfig
+from .deviceconfig import DeviceConfig, DeviceFamily
from .exceptions import KasaException, UnsupportedDeviceError
from .iot import (
IotBulb,
@@ -179,20 +179,29 @@ def get_device_class_from_family(
def get_protocol(
config: DeviceConfig,
) -> BaseProtocol | None:
- """Return the protocol from the connection name."""
- protocol_name = config.connection_type.device_family.value.split(".")[0]
+ """Return the protocol from the connection name.
+
+ For cameras and vacuums the device family is a simple mapping to
+ the protocol/transport. For other device types the transport varies
+ based on the discovery information.
+ """
ctype = config.connection_type
+ protocol_name = ctype.device_family.value.split(".")[0]
+
+ if ctype.device_family is DeviceFamily.SmartIpCamera:
+ return SmartCamProtocol(transport=SslAesTransport(config=config))
+
+ if ctype.device_family is DeviceFamily.IotIpCamera:
+ return IotProtocol(transport=LinkieTransportV2(config=config))
+
+ if ctype.device_family is DeviceFamily.SmartTapoRobovac:
+ return SmartProtocol(transport=SslTransport(config=config))
protocol_transport_key = (
protocol_name
+ "."
+ ctype.encryption_type.value
+ (".HTTPS" if ctype.https else "")
- + (
- f".{ctype.login_version}"
- if ctype.login_version and ctype.login_version > 1
- else ""
- )
)
_LOGGER.debug("Finding transport for %s", protocol_transport_key)
@@ -201,12 +210,11 @@ def get_protocol(
] = {
"IOT.XOR": (IotProtocol, XorTransport),
"IOT.KLAP": (IotProtocol, KlapTransport),
- "IOT.XOR.HTTPS.2": (IotProtocol, LinkieTransportV2),
"SMART.AES": (SmartProtocol, AesTransport),
- "SMART.AES.2": (SmartProtocol, AesTransport),
- "SMART.KLAP.2": (SmartProtocol, KlapTransportV2),
- "SMART.AES.HTTPS.2": (SmartCamProtocol, SslAesTransport),
- "SMART.AES.HTTPS": (SmartProtocol, SslTransport),
+ "SMART.KLAP": (SmartProtocol, KlapTransportV2),
+ # H200 is device family SMART.TAPOHUB and uses SmartCamProtocol so use
+ # https to distuingish from SmartProtocol devices
+ "SMART.AES.HTTPS": (SmartCamProtocol, SslAesTransport),
}
if not (prot_tran_cls := supported_device_protocols.get(protocol_transport_key)):
return None
diff --git a/kasa/discover.py b/kasa/discover.py
index d88fcc09..b696c370 100755
--- a/kasa/discover.py
+++ b/kasa/discover.py
@@ -22,7 +22,7 @@ Discovery returns a dict of {ip: discovered devices}:
>>>
>>> found_devices = await Discover.discover()
>>> [dev.model for dev in found_devices.values()]
-['KP303(UK)', 'HS110(EU)', 'L530E', 'KL430(US)', 'HS220(US)']
+['KP303', 'HS110', 'L530E', 'KL430', 'HS220']
You can pass username and password for devices requiring authentication
@@ -65,17 +65,17 @@ It is also possible to pass a coroutine to be executed for each found device:
>>> print(f"Discovered {dev.alias} (model: {dev.model})")
>>>
>>> devices = await Discover.discover(on_discovered=print_dev_info, credentials=creds)
-Discovered Bedroom Power Strip (model: KP303(UK))
-Discovered Bedroom Lamp Plug (model: HS110(EU))
+Discovered Bedroom Power Strip (model: KP303)
+Discovered Bedroom Lamp Plug (model: HS110)
Discovered Living Room Bulb (model: L530)
-Discovered Bedroom Lightstrip (model: KL430(US))
-Discovered Living Room Dimmer Switch (model: HS220(US))
+Discovered Bedroom Lightstrip (model: KL430)
+Discovered Living Room Dimmer Switch (model: HS220)
Discovering a single device returns a kasa.Device object.
>>> device = await Discover.discover_single("127.0.0.1", credentials=creds)
>>> device.model
-'KP303(UK)'
+'KP303'
"""
@@ -168,6 +168,12 @@ OnUnsupportedCallable = Callable[[UnsupportedDeviceError], Coroutine]
OnConnectAttemptCallable = Callable[[ConnectAttempt, bool], None]
DeviceDict = dict[str, Device]
+DECRYPTED_REDACTORS: dict[str, Callable[[Any], Any] | None] = {
+ "connect_ssid": lambda x: "#MASKED_SSID#" if x else "",
+ "device_id": lambda x: "REDACTED_" + x[9::],
+ "owner": lambda x: "REDACTED_" + x[9::],
+}
+
NEW_DISCOVERY_REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"device_id": lambda x: "REDACTED_" + x[9::],
"device_name": lambda x: "#MASKED_NAME#" if x else "",
@@ -177,6 +183,8 @@ NEW_DISCOVERY_REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"group_id": lambda x: "REDACTED_" + x[9::],
"group_name": lambda x: "I01BU0tFRF9TU0lEIw==",
"encrypt_info": lambda x: {**x, "key": "", "data": ""},
+ "ip": lambda x: x, # don't redact but keep listed here for dump_devinfo
+ "decrypted_data": lambda x: redact_data(x, DECRYPTED_REDACTORS),
}
@@ -490,7 +498,7 @@ class Discover:
try:
_LOGGER.debug("Waiting %s seconds for responses...", discovery_timeout)
await protocol.wait_for_discovery_to_complete()
- except KasaException as ex:
+ except (KasaException, asyncio.CancelledError) as ex:
for device in protocol.discovered_devices.values():
await device.protocol.close()
raise ex
@@ -742,6 +750,7 @@ class Discover:
@staticmethod
def _decrypt_discovery_data(discovery_result: DiscoveryResult) -> None:
+ debug_enabled = _LOGGER.isEnabledFor(logging.DEBUG)
if TYPE_CHECKING:
assert discovery_result.encrypt_info
assert _AesDiscoveryQuery.keypair
@@ -757,7 +766,19 @@ class Discover:
session = AesEncyptionSession(key, iv)
decrypted_data = session.decrypt(encrypted_data)
- discovery_result.decrypted_data = json_loads(decrypted_data)
+ result = json_loads(decrypted_data)
+ if debug_enabled:
+ data = (
+ redact_data(result, DECRYPTED_REDACTORS)
+ if Discover._redact_data
+ else result
+ )
+ _LOGGER.debug(
+ "Decrypted encrypt_info for %s: %s",
+ discovery_result.ip,
+ pf(data),
+ )
+ discovery_result.decrypted_data = result
@staticmethod
def _get_discovery_json(data: bytes, ip: str) -> dict:
@@ -826,12 +847,12 @@ class Discover:
):
encrypt_type = encrypt_info.sym_schm
- if (
- not (login_version := encrypt_schm.lv)
- and (et := discovery_result.encrypt_type)
- and et == ["3"]
+ if not (login_version := encrypt_schm.lv) and (
+ et := discovery_result.encrypt_type
):
- login_version = 2
+ # Known encrypt types are ["1","2"] and ["3"]
+ # Reuse the login_version attribute to pass the max to transport
+ login_version = max([int(i) for i in et])
if not encrypt_type:
raise UnsupportedDeviceError(
diff --git a/kasa/httpclient.py b/kasa/httpclient.py
index 87e3626a..31d8dfbb 100644
--- a/kasa/httpclient.py
+++ b/kasa/httpclient.py
@@ -113,10 +113,23 @@ class HttpClient:
ssl=ssl,
)
async with resp:
- if resp.status == 200:
- response_data = await resp.read()
- if return_json:
+ response_data = await resp.read()
+
+ if resp.status == 200:
+ if return_json:
+ response_data = json_loads(response_data.decode())
+ else:
+ _LOGGER.debug(
+ "Device %s received status code %s with response %s",
+ self._config.host,
+ resp.status,
+ str(response_data),
+ )
+ if response_data and return_json:
+ try:
response_data = json_loads(response_data.decode())
+ except Exception:
+ _LOGGER.debug("Device %s response could not be parsed as json")
except (aiohttp.ServerDisconnectedError, aiohttp.ClientOSError) as ex:
if not self._wait_between_requests:
diff --git a/kasa/interfaces/light.py b/kasa/interfaces/light.py
index 912ec2e2..6dd5b0f0 100644
--- a/kasa/interfaces/light.py
+++ b/kasa/interfaces/light.py
@@ -23,7 +23,7 @@ Get the light module to interact:
>>> light = dev.modules[Module.Light]
-You can use the ``is_``-prefixed properties to check for supported features:
+You can use the ``has_feature()`` method to check for supported features:
>>> light.has_feature("brightness")
True
diff --git a/kasa/iot/iotdevice.py b/kasa/iot/iotdevice.py
index 90f63c97..851f21cc 100755
--- a/kasa/iot/iotdevice.py
+++ b/kasa/iot/iotdevice.py
@@ -22,7 +22,7 @@ from datetime import datetime, timedelta, tzinfo
from typing import TYPE_CHECKING, Any, cast
from warnings import warn
-from ..device import Device, WifiNetwork, _DeviceInfo
+from ..device import Device, DeviceInfo, WifiNetwork
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..exceptions import KasaException
@@ -43,7 +43,7 @@ def requires_update(f: Callable) -> Any:
@functools.wraps(f)
async def wrapped(*args: Any, **kwargs: Any) -> Any:
self = args[0]
- if self._last_update is None and (
+ if not self._last_update and (
self._sys_info is None or f.__name__ not in self._sys_info
):
raise KasaException("You need to await update() to access the data")
@@ -54,7 +54,7 @@ def requires_update(f: Callable) -> Any:
@functools.wraps(f)
def wrapped(*args: Any, **kwargs: Any) -> Any:
self = args[0]
- if self._last_update is None and (
+ if not self._last_update and (
self._sys_info is None or f.__name__ not in self._sys_info
):
raise KasaException("You need to await update() to access the data")
@@ -112,7 +112,7 @@ class IotDevice(Device):
>>> dev.alias
Bedroom Lamp Plug
>>> dev.model
- HS110(EU)
+ HS110
>>> dev.rssi
-71
>>> dev.mac
@@ -310,7 +310,7 @@ class IotDevice(Device):
# If this is the initial update, check only for the sysinfo
# This is necessary as some devices crash on unexpected modules
# See #105, #120, #161
- if self._last_update is None:
+ if not self._last_update:
_LOGGER.debug("Performing the initial update to obtain sysinfo")
response = await self.protocol.query(req)
self._last_update = response
@@ -452,7 +452,9 @@ class IotDevice(Device):
# This allows setting of some info properties directly
# from partial discovery info that will then be found
# by the requires_update decorator
- self._set_sys_info(info)
+ discovery_model = info["device_model"]
+ no_region_model, _, _ = discovery_model.partition("(")
+ self._set_sys_info({**info, "model": no_region_model})
def _set_sys_info(self, sys_info: dict[str, Any]) -> None:
"""Set sys_info."""
@@ -471,18 +473,13 @@ class IotDevice(Device):
"""
return self._sys_info # type: ignore
- @property # type: ignore
- @requires_update
- def model(self) -> str:
- """Return device model."""
- sys_info = self._sys_info
- return str(sys_info["model"])
-
@property
@requires_update
- def _model_region(self) -> str:
- """Return device full model name and region."""
- return self.model
+ def model(self) -> str:
+ """Returns the device model."""
+ if self._last_update:
+ return self.device_info.short_name
+ return self._sys_info["model"]
@property # type: ignore
def alias(self) -> str | None:
@@ -748,7 +745,7 @@ class IotDevice(Device):
@staticmethod
def _get_device_info(
info: dict[str, Any], discovery_info: dict[str, Any] | None
- ) -> _DeviceInfo:
+ ) -> DeviceInfo:
"""Get model information for a device."""
sys_info = _extract_sys_info(info)
@@ -766,7 +763,7 @@ class IotDevice(Device):
firmware_version, firmware_build = fw_version_full.split(" ", maxsplit=1)
auth = bool(discovery_info and ("mgt_encrypt_schm" in discovery_info))
- return _DeviceInfo(
+ return DeviceInfo(
short_name=long_name,
long_name=long_name,
brand="kasa",
diff --git a/kasa/iot/modules/light.py b/kasa/iot/modules/light.py
index da55bcad..fa953590 100644
--- a/kasa/iot/modules/light.py
+++ b/kasa/iot/modules/light.py
@@ -207,17 +207,18 @@ class Light(IotModule, LightInterface):
return self._light_state
async def _post_update_hook(self) -> None:
- if self._device.is_on is False:
+ device = self._device
+ if device.is_on is False:
state = LightState(light_on=False)
else:
state = LightState(light_on=True)
- if self._device._is_dimmable:
+ if device._is_dimmable:
state.brightness = self.brightness
- if self._device._is_color:
+ if device._is_color:
hsv = self.hsv
state.hue = hsv.hue
state.saturation = hsv.saturation
- if self._device._is_variable_color_temp:
+ if device._is_variable_color_temp:
state.color_temp = self.color_temp
self._light_state = state
diff --git a/kasa/iot/modules/lightpreset.py b/kasa/iot/modules/lightpreset.py
index d97bfc4a..76d39860 100644
--- a/kasa/iot/modules/lightpreset.py
+++ b/kasa/iot/modules/lightpreset.py
@@ -85,17 +85,19 @@ class LightPreset(IotModule, LightPresetInterface):
def preset(self) -> str:
"""Return current preset name."""
light = self._device.modules[Module.Light]
+ is_color = light.has_feature("hsv")
+ is_variable_color_temp = light.has_feature("color_temp")
+
brightness = light.brightness
- color_temp = light.color_temp if light.is_variable_color_temp else None
- h, s = (light.hsv.hue, light.hsv.saturation) if light.is_color else (None, None)
+ color_temp = light.color_temp if is_variable_color_temp else None
+
+ h, s = (light.hsv.hue, light.hsv.saturation) if is_color else (None, None)
for preset_name, preset in self._presets.items():
if (
preset.brightness == brightness
- and (
- preset.color_temp == color_temp or not light.is_variable_color_temp
- )
- and (preset.hue == h or not light.is_color)
- and (preset.saturation == s or not light.is_color)
+ and (preset.color_temp == color_temp or not is_variable_color_temp)
+ and (preset.hue == h or not is_color)
+ and (preset.saturation == s or not is_color)
):
return preset_name
return self.PRESET_NOT_SET
@@ -107,7 +109,7 @@ class LightPreset(IotModule, LightPresetInterface):
"""Set a light preset for the device."""
light = self._device.modules[Module.Light]
if preset_name == self.PRESET_NOT_SET:
- if light.is_color:
+ if light.has_feature("hsv"):
preset = LightState(hue=0, saturation=0, brightness=100)
else:
preset = LightState(brightness=100)
diff --git a/kasa/module.py b/kasa/module.py
index 2b2e65f9..2870b661 100644
--- a/kasa/module.py
+++ b/kasa/module.py
@@ -21,6 +21,9 @@ check for the existence of the module:
>>> print(light.brightness)
100
+.. include:: ../featureattributes.md
+ :parser: myst_parser.sphinx_
+
To see whether a device supports specific functionality, you can check whether the
module has that feature:
@@ -151,8 +154,12 @@ class Module(ABC):
)
TriggerLogs: Final[ModuleName[smart.TriggerLogs]] = ModuleName("TriggerLogs")
+ HomeKit: Final[ModuleName[smart.HomeKit]] = ModuleName("HomeKit")
+ Matter: Final[ModuleName[smart.Matter]] = ModuleName("Matter")
+
# SMARTCAM only modules
Camera: Final[ModuleName[smartcam.Camera]] = ModuleName("Camera")
+ LensMask: Final[ModuleName[smartcam.LensMask]] = ModuleName("LensMask")
def __init__(self, device: Device, module: str) -> None:
self._device = device
diff --git a/kasa/protocols/__init__.py b/kasa/protocols/__init__.py
index 44130d7f..b994d732 100644
--- a/kasa/protocols/__init__.py
+++ b/kasa/protocols/__init__.py
@@ -2,6 +2,7 @@
from .iotprotocol import IotProtocol
from .protocol import BaseProtocol
+from .smartcamprotocol import SmartCamProtocol
from .smartprotocol import SmartErrorCode, SmartProtocol
__all__ = [
@@ -9,4 +10,5 @@ __all__ = [
"IotProtocol",
"SmartErrorCode",
"SmartProtocol",
+ "SmartCamProtocol",
]
diff --git a/kasa/protocols/iotprotocol.py b/kasa/protocols/iotprotocol.py
index 3bc6c454..b58e57ae 100755
--- a/kasa/protocols/iotprotocol.py
+++ b/kasa/protocols/iotprotocol.py
@@ -25,19 +25,35 @@ if TYPE_CHECKING:
_LOGGER = logging.getLogger(__name__)
+
+def _mask_children(children: list[dict[str, Any]]) -> list[dict[str, Any]]:
+ def mask_child(child: dict[str, Any], index: int) -> dict[str, Any]:
+ result = {
+ **child,
+ "id": f"SCRUBBED_CHILD_DEVICE_ID_{index+1}",
+ }
+ # Will leave empty aliases as blank
+ if child.get("alias"):
+ result["alias"] = f"#MASKED_NAME# {index + 1}"
+ return result
+
+ return [mask_child(child, index) for index, child in enumerate(children)]
+
+
REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"latitude": lambda x: 0,
"longitude": lambda x: 0,
"latitude_i": lambda x: 0,
"longitude_i": lambda x: 0,
"deviceId": lambda x: "REDACTED_" + x[9::],
- "id": lambda x: "REDACTED_" + x[9::],
+ "children": _mask_children,
"alias": lambda x: "#MASKED_NAME#" if x else "",
"mac": mask_mac,
"mic_mac": mask_mac,
"ssid": lambda x: "#MASKED_SSID#" if x else "",
"oemId": lambda x: "REDACTED_" + x[9::],
"username": lambda _: "user@example.com", # cnCloud
+ "hwId": lambda x: "REDACTED_" + x[9::],
}
diff --git a/kasa/protocols/protocol.py b/kasa/protocols/protocol.py
index 211a7b5a..fb09b882 100755
--- a/kasa/protocols/protocol.py
+++ b/kasa/protocols/protocol.py
@@ -66,6 +66,8 @@ def redact_data(data: _T, redactors: dict[str, Callable[[Any], Any] | None]) ->
def mask_mac(mac: str) -> str:
"""Return mac address with last two octects blanked."""
+ if len(mac) == 12:
+ return f"{mac[:6]}000000"
delim = ":" if ":" in mac else "-"
rest = delim.join(format(s, "02x") for s in bytes.fromhex("000000"))
return f"{mac[:8]}{delim}{rest}"
diff --git a/kasa/protocols/smartcamprotocol.py b/kasa/protocols/smartcamprotocol.py
index 12caa207..324f8056 100644
--- a/kasa/protocols/smartcamprotocol.py
+++ b/kasa/protocols/smartcamprotocol.py
@@ -19,7 +19,7 @@ from ..transports.sslaestransport import (
SMART_RETRYABLE_ERRORS,
SmartErrorCode,
)
-from . import SmartProtocol
+from .smartprotocol import SmartProtocol
_LOGGER = logging.getLogger(__name__)
diff --git a/kasa/protocols/smartprotocol.py b/kasa/protocols/smartprotocol.py
index 80e76ca6..7f02b45e 100644
--- a/kasa/protocols/smartprotocol.py
+++ b/kasa/protocols/smartprotocol.py
@@ -9,6 +9,7 @@ from __future__ import annotations
import asyncio
import base64
import logging
+import re
import time
import uuid
from collections.abc import Callable
@@ -45,15 +46,36 @@ REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"original_device_id": lambda x: "REDACTED_" + x[9::], # Strip children
"nickname": lambda x: "I01BU0tFRF9OQU1FIw==" if x else "",
"mac": mask_mac,
- "ssid": lambda x: "I01BU0tFRF9TU0lEIw=" if x else "",
+ "ssid": lambda x: "I01BU0tFRF9TU0lEIw==" if x else "",
"bssid": lambda _: "000000000000",
+ "channel": lambda _: 0,
"oem_id": lambda x: "REDACTED_" + x[9::],
- "setup_code": None, # matter
- "setup_payload": None, # matter
- "mfi_setup_code": None, # mfi_ for homekit
- "mfi_setup_id": None,
- "mfi_token_token": None,
- "mfi_token_uuid": None,
+ "hw_id": lambda x: "REDACTED_" + x[9::],
+ "fw_id": lambda x: "REDACTED_" + x[9::],
+ "setup_code": lambda x: re.sub(r"\w", "0", x), # matter
+ "setup_payload": lambda x: re.sub(r"\w", "0", x), # matter
+ "mfi_setup_code": lambda x: re.sub(r"\w", "0", x), # mfi_ for homekit
+ "mfi_setup_id": lambda x: re.sub(r"\w", "0", x),
+ "mfi_token_token": lambda x: re.sub(r"\w", "0", x),
+ "mfi_token_uuid": lambda x: re.sub(r"\w", "0", x),
+ "ip": lambda x: x, # don't redact but keep listed here for dump_devinfo
+ # smartcam
+ "dev_id": lambda x: "REDACTED_" + x[9::],
+ "device_name": lambda x: "#MASKED_NAME#" if x else "",
+ "device_alias": lambda x: "#MASKED_NAME#" if x else "",
+ "local_ip": lambda x: x, # don't redact but keep listed here for dump_devinfo
+ # robovac
+ "board_sn": lambda _: "000000000000",
+ "custom_sn": lambda _: "000000000000",
+ "location": lambda x: "#MASKED_NAME#" if x else "",
+ "map_data": lambda x: "#SCRUBBED_MAPDATA#" if x else "",
+}
+
+# Queries that are known not to work properly when sent as a
+# multiRequest. They will not return the `method` key.
+FORCE_SINGLE_REQUEST = {
+ "getConnectStatus",
+ "scanApList",
}
@@ -76,6 +98,7 @@ class SmartProtocol(BaseProtocol):
self._transport._config.batch_size or self.DEFAULT_MULTI_REQUEST_BATCH_SIZE
)
self._redact_data = True
+ self._method_missing_logged = False
def get_smart_request(self, method: str, params: dict | None = None) -> str:
"""Get a request message as a string."""
@@ -162,17 +185,18 @@ class SmartProtocol(BaseProtocol):
multi_result: dict[str, Any] = {}
smart_method = "multipleRequest"
- multi_requests = [
- {"method": method, "params": params} if params else {"method": method}
- for method, params in requests.items()
- ]
-
- end = len(multi_requests)
+ end = len(requests)
# The SmartCamProtocol sends requests with a length 1 as a
# multipleRequest. The SmartProtocol doesn't so will never
# raise_on_error
raise_on_error = end == 1
+ multi_requests = [
+ {"method": method, "params": params} if params else {"method": method}
+ for method, params in requests.items()
+ if method not in FORCE_SINGLE_REQUEST
+ ]
+
# Break the requests down as there can be a size limit
step = self._multi_request_batch_size
if step == 1:
@@ -233,7 +257,20 @@ class SmartProtocol(BaseProtocol):
responses = response_step["result"]["responses"]
for response in responses:
- method = response["method"]
+ # some smartcam devices calls do not populate the method key
+ # these should be defined in DO_NOT_SEND_AS_MULTI_REQUEST.
+ if not (method := response.get("method")):
+ if not self._method_missing_logged:
+ # Avoid spamming the logs
+ self._method_missing_logged = True
+ _LOGGER.error(
+ "No method key in response for %s, skipping: %s",
+ self._host,
+ response_step,
+ )
+ # These will end up being queried individually
+ continue
+
self._handle_response_error_code(
response, method, raise_on_error=raise_on_error
)
@@ -242,13 +279,17 @@ class SmartProtocol(BaseProtocol):
result, method, retry_count=retry_count
)
multi_result[method] = result
- # Multi requests don't continue after errors so requery any missing
+
+ # Multi requests don't continue after errors so requery any missing.
+ # Will also query individually any DO_NOT_SEND_AS_MULTI_REQUEST.
for method, params in requests.items():
if method not in multi_result:
resp = await self._transport.send(
self.get_smart_request(method, params)
)
- self._handle_response_error_code(resp, method, raise_on_error=False)
+ self._handle_response_error_code(
+ resp, method, raise_on_error=raise_on_error
+ )
multi_result[method] = resp.get("result")
return multi_result
diff --git a/kasa/smart/modules/__init__.py b/kasa/smart/modules/__init__.py
index 36754801..ae9fb68f 100644
--- a/kasa/smart/modules/__init__.py
+++ b/kasa/smart/modules/__init__.py
@@ -16,6 +16,7 @@ from .energy import Energy
from .fan import Fan
from .firmware import Firmware
from .frostprotection import FrostProtection
+from .homekit import HomeKit
from .humiditysensor import HumiditySensor
from .led import Led
from .light import Light
@@ -23,6 +24,7 @@ from .lighteffect import LightEffect
from .lightpreset import LightPreset
from .lightstripeffect import LightStripEffect
from .lighttransition import LightTransition
+from .matter import Matter
from .motionsensor import MotionSensor
from .overheatprotection import OverheatProtection
from .reportmode import ReportMode
@@ -66,4 +68,6 @@ __all__ = [
"Thermostat",
"SmartLightEffect",
"OverheatProtection",
+ "HomeKit",
+ "Matter",
]
diff --git a/kasa/smart/modules/energy.py b/kasa/smart/modules/energy.py
index 6b5bdb57..0cfdc92c 100644
--- a/kasa/smart/modules/energy.py
+++ b/kasa/smart/modules/energy.py
@@ -2,10 +2,10 @@
from __future__ import annotations
-from typing import NoReturn
+from typing import Any, NoReturn
from ...emeterstatus import EmeterStatus
-from ...exceptions import KasaException
+from ...exceptions import DeviceError, KasaException
from ...interfaces.energy import Energy as EnergyInterface
from ..smartmodule import SmartModule, raise_if_update_error
@@ -15,12 +15,39 @@ class Energy(SmartModule, EnergyInterface):
REQUIRED_COMPONENT = "energy_monitoring"
+ _energy: dict[str, Any]
+ _current_consumption: float | None
+
async def _post_update_hook(self) -> None:
- if "voltage_mv" in self.data.get("get_emeter_data", {}):
+ try:
+ data = self.data
+ except DeviceError as de:
+ self._energy = {}
+ self._current_consumption = None
+ raise de
+
+ # If version is 1 then data is get_energy_usage
+ self._energy = data.get("get_energy_usage", data)
+
+ if "voltage_mv" in data.get("get_emeter_data", {}):
self._supported = (
self._supported | EnergyInterface.ModuleFeature.VOLTAGE_CURRENT
)
+ if (power := self._energy.get("current_power")) is not None or (
+ power := data.get("get_emeter_data", {}).get("power_mw")
+ ) is not None:
+ self._current_consumption = power / 1_000
+ # Fallback if get_energy_usage does not provide current_power,
+ # which can happen on some newer devices (e.g. P304M).
+ # This may not be valid scenario as it pre-dates trying get_emeter_data
+ elif (
+ power := self.data.get("get_current_power", {}).get("current_power")
+ ) is not None:
+ self._current_consumption = power
+ else:
+ self._current_consumption = None
+
def query(self) -> dict:
"""Query to execute during the update cycle."""
req = {
@@ -33,28 +60,21 @@ class Energy(SmartModule, EnergyInterface):
return req
@property
- @raise_if_update_error
- def current_consumption(self) -> float | None:
- """Current power in watts."""
- if (power := self.energy.get("current_power")) is not None or (
- power := self.data.get("get_emeter_data", {}).get("power_mw")
- ) is not None:
- return power / 1_000
- # Fallback if get_energy_usage does not provide current_power,
- # which can happen on some newer devices (e.g. P304M).
- elif (
- power := self.data.get("get_current_power", {}).get("current_power")
- ) is not None:
- return power
- return None
+ def optional_response_keys(self) -> list[str]:
+ """Return optional response keys for the module."""
+ if self.supported_version > 1:
+ return ["get_energy_usage"]
+ return []
+
+ @property
+ def current_consumption(self) -> float | None:
+ """Current power in watts."""
+ return self._current_consumption
@property
- @raise_if_update_error
def energy(self) -> dict:
"""Return get_energy_usage results."""
- if en := self.data.get("get_energy_usage"):
- return en
- return self.data
+ return self._energy
def _get_status_from_energy(self, energy: dict) -> EmeterStatus:
return EmeterStatus(
@@ -83,16 +103,18 @@ class Energy(SmartModule, EnergyInterface):
return self._get_status_from_energy(res["get_energy_usage"])
@property
- @raise_if_update_error
def consumption_this_month(self) -> float | None:
"""Get the emeter value for this month in kWh."""
- return self.energy.get("month_energy", 0) / 1_000
+ if (month := self.energy.get("month_energy")) is not None:
+ return month / 1_000
+ return None
@property
- @raise_if_update_error
def consumption_today(self) -> float | None:
"""Get the emeter value for today in kWh."""
- return self.energy.get("today_energy", 0) / 1_000
+ if (today := self.energy.get("today_energy")) is not None:
+ return today / 1_000
+ return None
@property
@raise_if_update_error
diff --git a/kasa/smart/modules/homekit.py b/kasa/smart/modules/homekit.py
new file mode 100644
index 00000000..2df8db1f
--- /dev/null
+++ b/kasa/smart/modules/homekit.py
@@ -0,0 +1,32 @@
+"""Implementation of homekit module."""
+
+from __future__ import annotations
+
+from ...feature import Feature
+from ..smartmodule import SmartModule
+
+
+class HomeKit(SmartModule):
+ """Implementation of homekit module."""
+
+ QUERY_GETTER_NAME: str = "get_homekit_info"
+ REQUIRED_COMPONENT = "homekit"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="homekit_setup_code",
+ name="Homekit setup code",
+ container=self,
+ attribute_getter=lambda x: x.info["mfi_setup_code"],
+ type=Feature.Type.Sensor,
+ category=Feature.Category.Debug,
+ )
+ )
+
+ @property
+ def info(self) -> dict[str, str]:
+ """Homekit mfi setup info."""
+ return self.data
diff --git a/kasa/smart/modules/light.py b/kasa/smart/modules/light.py
index d10139d9..d548811f 100644
--- a/kasa/smart/modules/light.py
+++ b/kasa/smart/modules/light.py
@@ -136,16 +136,17 @@ class Light(SmartModule, LightInterface):
return self._light_state
async def _post_update_hook(self) -> None:
- if self._device.is_on is False:
+ device = self._device
+ if device.is_on is False:
state = LightState(light_on=False)
else:
state = LightState(light_on=True)
- if Module.Brightness in self._device.modules:
+ if Module.Brightness in device.modules:
state.brightness = self.brightness
- if Module.Color in self._device.modules:
+ if Module.Color in device.modules:
hsv = self.hsv
state.hue = hsv.hue
state.saturation = hsv.saturation
- if Module.ColorTemperature in self._device.modules:
+ if Module.ColorTemperature in device.modules:
state.color_temp = self.color_temp
self._light_state = state
diff --git a/kasa/smart/modules/matter.py b/kasa/smart/modules/matter.py
new file mode 100644
index 00000000..c6bfe2d8
--- /dev/null
+++ b/kasa/smart/modules/matter.py
@@ -0,0 +1,43 @@
+"""Implementation of matter module."""
+
+from __future__ import annotations
+
+from ...feature import Feature
+from ..smartmodule import SmartModule
+
+
+class Matter(SmartModule):
+ """Implementation of matter module."""
+
+ QUERY_GETTER_NAME: str = "get_matter_setup_info"
+ REQUIRED_COMPONENT = "matter"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="matter_setup_code",
+ name="Matter setup code",
+ container=self,
+ attribute_getter=lambda x: x.info["setup_code"],
+ type=Feature.Type.Sensor,
+ category=Feature.Category.Debug,
+ )
+ )
+ self._add_feature(
+ Feature(
+ self._device,
+ id="matter_setup_payload",
+ name="Matter setup payload",
+ container=self,
+ attribute_getter=lambda x: x.info["setup_payload"],
+ type=Feature.Type.Sensor,
+ category=Feature.Category.Debug,
+ )
+ )
+
+ @property
+ def info(self) -> dict[str, str]:
+ """Matter setup info."""
+ return self.data
diff --git a/kasa/smart/smartchilddevice.py b/kasa/smart/smartchilddevice.py
index db3319f3..2ef0454f 100644
--- a/kasa/smart/smartchilddevice.py
+++ b/kasa/smart/smartchilddevice.py
@@ -6,10 +6,11 @@ import logging
import time
from typing import Any
+from ..device import DeviceInfo
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..protocols.smartprotocol import SmartProtocol, _ChildProtocolWrapper
-from .smartdevice import SmartDevice
+from .smartdevice import ComponentsRaw, SmartDevice
from .smartmodule import SmartModule
_LOGGER = logging.getLogger(__name__)
@@ -37,7 +38,7 @@ class SmartChildDevice(SmartDevice):
self,
parent: SmartDevice,
info: dict,
- component_info: dict,
+ component_info_raw: ComponentsRaw,
*,
config: DeviceConfig | None = None,
protocol: SmartProtocol | None = None,
@@ -47,7 +48,24 @@ class SmartChildDevice(SmartDevice):
super().__init__(parent.host, config=parent.config, protocol=_protocol)
self._parent = parent
self._update_internal_state(info)
- self._components = component_info
+ self._components_raw = component_info_raw
+ self._components = self._parse_components(self._components_raw)
+
+ @property
+ def device_info(self) -> DeviceInfo:
+ """Return device info.
+
+ Child device does not have it info and components in _last_update so
+ this overrides the base implementation to call _get_device_info with
+ info and components combined as they would be in _last_update.
+ """
+ return self._get_device_info(
+ {
+ "get_device_info": self._info,
+ "component_nego": self._components_raw,
+ },
+ None,
+ )
async def update(self, update_children: bool = True) -> None:
"""Update child module info.
@@ -84,7 +102,7 @@ class SmartChildDevice(SmartDevice):
cls,
parent: SmartDevice,
child_info: dict,
- child_components: dict,
+ child_components_raw: ComponentsRaw,
protocol: SmartProtocol | None = None,
*,
last_update: dict | None = None,
@@ -97,7 +115,7 @@ class SmartChildDevice(SmartDevice):
derived from the parent.
"""
child: SmartChildDevice = cls(
- parent, child_info, child_components, protocol=protocol
+ parent, child_info, child_components_raw, protocol=protocol
)
if last_update:
child._last_update = last_update
diff --git a/kasa/smart/smartdevice.py b/kasa/smart/smartdevice.py
index ed5a4eec..5fd22115 100644
--- a/kasa/smart/smartdevice.py
+++ b/kasa/smart/smartdevice.py
@@ -7,9 +7,9 @@ import logging
import time
from collections.abc import Mapping, Sequence
from datetime import UTC, datetime, timedelta, tzinfo
-from typing import TYPE_CHECKING, Any, cast
+from typing import TYPE_CHECKING, Any, TypeAlias, cast
-from ..device import Device, WifiNetwork, _DeviceInfo
+from ..device import Device, DeviceInfo, WifiNetwork
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..exceptions import AuthenticationError, DeviceError, KasaException, SmartErrorCode
@@ -40,6 +40,8 @@ _LOGGER = logging.getLogger(__name__)
# same issue, homekit perhaps?
NON_HUB_PARENT_ONLY_MODULES = [DeviceModule, Time, Firmware, Cloud]
+ComponentsRaw: TypeAlias = dict[str, list[dict[str, int | str]]]
+
# Device must go last as the other interfaces also inherit Device
# and python needs a consistent method resolution order.
@@ -61,13 +63,12 @@ class SmartDevice(Device):
)
super().__init__(host=host, config=config, protocol=_protocol)
self.protocol: SmartProtocol
- self._components_raw: dict[str, Any] | None = None
+ self._components_raw: ComponentsRaw | None = None
self._components: dict[str, int] = {}
self._state_information: dict[str, Any] = {}
self._modules: dict[str | ModuleName[Module], SmartModule] = {}
self._parent: SmartDevice | None = None
self._children: Mapping[str, SmartDevice] = {}
- self._last_update = {}
self._last_update_time: float | None = None
self._on_since: datetime | None = None
self._info: dict[str, Any] = {}
@@ -82,10 +83,8 @@ class SmartDevice(Device):
self.internal_state.update(resp)
children = self.internal_state["get_child_device_list"]["child_device_list"]
- children_components = {
- child["device_id"]: {
- comp["id"]: int(comp["ver_code"]) for comp in child["component_list"]
- }
+ children_components_raw = {
+ child["device_id"]: child
for child in self.internal_state["get_child_device_component_list"][
"child_component_list"
]
@@ -96,7 +95,7 @@ class SmartDevice(Device):
child_info["device_id"]: await SmartChildDevice.create(
parent=self,
child_info=child_info,
- child_components=children_components[child_info["device_id"]],
+ child_components_raw=children_components_raw[child_info["device_id"]],
)
for child_info in children
}
@@ -131,6 +130,13 @@ class SmartDevice(Device):
f"{request} not found in {responses} for device {self.host}"
)
+ @staticmethod
+ def _parse_components(components_raw: ComponentsRaw) -> dict[str, int]:
+ return {
+ str(comp["id"]): int(comp["ver_code"])
+ for comp in components_raw["component_list"]
+ }
+
async def _negotiate(self) -> None:
"""Perform initialization.
@@ -151,12 +157,9 @@ class SmartDevice(Device):
self._info = self._try_get_response(resp, "get_device_info")
# Create our internal presentation of available components
- self._components_raw = cast(dict, resp["component_nego"])
+ self._components_raw = cast(ComponentsRaw, resp["component_nego"])
- self._components = {
- comp["id"]: int(comp["ver_code"])
- for comp in self._components_raw["component_list"]
- }
+ self._components = self._parse_components(self._components_raw)
if "child_device" in self._components and not self.children:
await self._initialize_children()
@@ -493,18 +496,13 @@ class SmartDevice(Device):
@property
def model(self) -> str:
"""Returns the device model."""
- return str(self._info.get("model"))
+ # If update hasn't been called self._device_info can't be used
+ if self._last_update:
+ return self.device_info.short_name
- @property
- def _model_region(self) -> str:
- """Return device full model name and region."""
- if (disco := self._discovery_info) and (
- disco_model := disco.get("device_model")
- ):
- return disco_model
- # Some devices have the region in the specs element.
- region = f"({specs})" if (specs := self._info.get("specs")) else ""
- return f"{self.model}{region}"
+ disco_model = str(self._info.get("device_model"))
+ long_name, _, _ = disco_model.partition("(")
+ return long_name
@property
def alias(self) -> str | None:
@@ -804,7 +802,7 @@ class SmartDevice(Device):
@staticmethod
def _get_device_info(
info: dict[str, Any], discovery_info: dict[str, Any] | None
- ) -> _DeviceInfo:
+ ) -> DeviceInfo:
"""Get model information for a device."""
di = info["get_device_info"]
components = [comp["id"] for comp in info["component_nego"]["component_list"]]
@@ -833,7 +831,7 @@ class SmartDevice(Device):
# Brand inferred from SMART.KASAPLUG/SMART.TAPOPLUG etc.
brand = devicetype[:4].lower()
- return _DeviceInfo(
+ return DeviceInfo(
short_name=short_name,
long_name=long_name,
brand=brand,
diff --git a/kasa/smart/smartmodule.py b/kasa/smart/smartmodule.py
index ab6ae667..a5666f63 100644
--- a/kasa/smart/smartmodule.py
+++ b/kasa/smart/smartmodule.py
@@ -57,7 +57,7 @@ class SmartModule(Module):
#: Module is initialized, if any of the given keys exists in the sysinfo
SYSINFO_LOOKUP_KEYS: list[str] = []
#: Query to execute during the main update cycle
- QUERY_GETTER_NAME: str
+ QUERY_GETTER_NAME: str = ""
REGISTERED_MODULES: dict[str, type[SmartModule]] = {}
@@ -72,6 +72,7 @@ class SmartModule(Module):
self._last_update_time: float | None = None
self._last_update_error: KasaException | None = None
self._error_count = 0
+ self._logged_remove_keys: list[str] = []
def __init_subclass__(cls, **kwargs) -> None:
# We only want to register submodules in a modules package so that
@@ -138,7 +139,9 @@ class SmartModule(Module):
Default implementation uses the raw query getter w/o parameters.
"""
- return {self.QUERY_GETTER_NAME: None}
+ if self.QUERY_GETTER_NAME:
+ return {self.QUERY_GETTER_NAME: None}
+ return {}
async def call(self, method: str, params: dict | None = None) -> dict:
"""Call a method.
@@ -147,6 +150,15 @@ class SmartModule(Module):
"""
return await self._device._query_helper(method, params)
+ @property
+ def optional_response_keys(self) -> list[str]:
+ """Return optional response keys for the module.
+
+ Defaults to no keys. Overriding this and providing keys will remove
+ instead of raise on error.
+ """
+ return []
+
@property
def data(self) -> dict[str, Any]:
"""Return response data for the module.
@@ -179,12 +191,31 @@ class SmartModule(Module):
filtered_data = {k: v for k, v in dev._last_update.items() if k in q_keys}
+ remove_keys: list[str] = []
for data_item in filtered_data:
if isinstance(filtered_data[data_item], SmartErrorCode):
- raise DeviceError(
- f"{data_item} for {self.name}", error_code=filtered_data[data_item]
+ if data_item in self.optional_response_keys:
+ remove_keys.append(data_item)
+ else:
+ raise DeviceError(
+ f"{data_item} for {self.name}",
+ error_code=filtered_data[data_item],
+ )
+
+ for key in remove_keys:
+ if key not in self._logged_remove_keys:
+ self._logged_remove_keys.append(key)
+ _LOGGER.debug(
+ "Removed key %s from response for device %s as it returned "
+ "error: %s. This message will only be logged once per key.",
+ key,
+ self._device.host,
+ filtered_data[key],
)
- if len(filtered_data) == 1:
+
+ filtered_data.pop(key)
+
+ if len(filtered_data) == 1 and not remove_keys:
return next(iter(filtered_data.values()))
return filtered_data
diff --git a/kasa/smartcam/modules/__init__.py b/kasa/smartcam/modules/__init__.py
index 16d59581..3ea4bb6a 100644
--- a/kasa/smartcam/modules/__init__.py
+++ b/kasa/smartcam/modules/__init__.py
@@ -1,19 +1,33 @@
"""Modules for SMARTCAM devices."""
from .alarm import Alarm
+from .babycrydetection import BabyCryDetection
from .camera import Camera
from .childdevice import ChildDevice
from .device import DeviceModule
+from .homekit import HomeKit
from .led import Led
+from .lensmask import LensMask
+from .matter import Matter
+from .motiondetection import MotionDetection
from .pantilt import PanTilt
+from .persondetection import PersonDetection
+from .tamperdetection import TamperDetection
from .time import Time
__all__ = [
"Alarm",
+ "BabyCryDetection",
"Camera",
"ChildDevice",
"DeviceModule",
"Led",
"PanTilt",
+ "PersonDetection",
"Time",
+ "HomeKit",
+ "Matter",
+ "MotionDetection",
+ "LensMask",
+ "TamperDetection",
]
diff --git a/kasa/smartcam/modules/babycrydetection.py b/kasa/smartcam/modules/babycrydetection.py
new file mode 100644
index 00000000..e9e32371
--- /dev/null
+++ b/kasa/smartcam/modules/babycrydetection.py
@@ -0,0 +1,47 @@
+"""Implementation of baby cry detection module."""
+
+from __future__ import annotations
+
+import logging
+
+from ...feature import Feature
+from ..smartcammodule import SmartCamModule
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class BabyCryDetection(SmartCamModule):
+ """Implementation of baby cry detection module."""
+
+ REQUIRED_COMPONENT = "babyCryDetection"
+
+ QUERY_GETTER_NAME = "getBCDConfig"
+ QUERY_MODULE_NAME = "sound_detection"
+ QUERY_SECTION_NAMES = "bcd"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="baby_cry_detection",
+ name="Baby cry detection",
+ container=self,
+ attribute_getter="enabled",
+ attribute_setter="set_enabled",
+ type=Feature.Type.Switch,
+ category=Feature.Category.Primary,
+ )
+ )
+
+ @property
+ def enabled(self) -> bool:
+ """Return the baby cry detection enabled state."""
+ return self.data["bcd"]["enabled"] == "on"
+
+ async def set_enabled(self, enable: bool) -> dict:
+ """Set the baby cry detection enabled state."""
+ params = {"enabled": "on" if enable else "off"}
+ return await self._device._query_setter_helper(
+ "setBCDConfig", self.QUERY_MODULE_NAME, "bcd", params
+ )
diff --git a/kasa/smartcam/modules/camera.py b/kasa/smartcam/modules/camera.py
index e96794c2..f1eda0f9 100644
--- a/kasa/smartcam/modules/camera.py
+++ b/kasa/smartcam/modules/camera.py
@@ -1,16 +1,18 @@
-"""Implementation of device module."""
+"""Implementation of camera module."""
from __future__ import annotations
import base64
import logging
from enum import StrEnum
+from typing import Annotated
from urllib.parse import quote_plus
from ...credentials import Credentials
from ...device_type import DeviceType
from ...feature import Feature
from ...json import loads as json_loads
+from ...module import FeatureAttribute, Module
from ..smartcammodule import SmartCamModule
_LOGGER = logging.getLogger(__name__)
@@ -29,28 +31,38 @@ class StreamResolution(StrEnum):
class Camera(SmartCamModule):
"""Implementation of device module."""
- QUERY_GETTER_NAME = "getLensMaskConfig"
- QUERY_MODULE_NAME = "lens_mask"
- QUERY_SECTION_NAMES = "lens_mask_info"
-
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
- self._add_feature(
- Feature(
- self._device,
- id="state",
- name="State",
- attribute_getter="is_on",
- attribute_setter="set_state",
- type=Feature.Type.Switch,
- category=Feature.Category.Primary,
+ if Module.LensMask in self._device.modules:
+ self._add_feature(
+ Feature(
+ self._device,
+ id="state",
+ name="State",
+ container=self,
+ attribute_getter="is_on",
+ attribute_setter="set_state",
+ type=Feature.Type.Switch,
+ category=Feature.Category.Primary,
+ )
)
- )
@property
def is_on(self) -> bool:
- """Return the device id."""
- return self.data["lens_mask_info"]["enabled"] == "off"
+ """Return the device on state."""
+ if lens_mask := self._device.modules.get(Module.LensMask):
+ return not lens_mask.enabled
+ return True
+
+ async def set_state(self, on: bool) -> Annotated[dict, FeatureAttribute()]:
+ """Set the device on state.
+
+ If the device does not support setting state will do nothing.
+ """
+ if lens_mask := self._device.modules.get(Module.LensMask):
+ # Turning off enables the privacy mask which is why value is reversed.
+ return await lens_mask.set_enabled(not on)
+ return {}
def _get_credentials(self) -> Credentials | None:
"""Get credentials from ."""
@@ -109,14 +121,6 @@ class Camera(SmartCamModule):
"""Return the onvif url."""
return f"http://{self._device.host}:{ONVIF_PORT}/onvif/device_service"
- async def set_state(self, on: bool) -> dict:
- """Set the device state."""
- # Turning off enables the privacy mask which is why value is reversed.
- params = {"enabled": "off" if on else "on"}
- return await self._device._query_setter_helper(
- "setLensMaskConfig", self.QUERY_MODULE_NAME, "lens_mask_info", params
- )
-
async def _check_supported(self) -> bool:
"""Additional check to see if the module is supported by the device."""
return self._device.device_type is DeviceType.Camera
diff --git a/kasa/smartcam/modules/device.py b/kasa/smartcam/modules/device.py
index 0541d75c..655a92da 100644
--- a/kasa/smartcam/modules/device.py
+++ b/kasa/smartcam/modules/device.py
@@ -14,6 +14,13 @@ class DeviceModule(SmartCamModule):
QUERY_MODULE_NAME = "device_info"
QUERY_SECTION_NAMES = ["basic_info", "info"]
+ def query(self) -> dict:
+ """Query to execute during the update cycle."""
+ q = super().query()
+ q["getConnectionType"] = {"network": {"get_connection_type": []}}
+
+ return q
+
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
self._add_feature(
@@ -26,6 +33,32 @@ class DeviceModule(SmartCamModule):
type=Feature.Type.Sensor,
)
)
+ if self.rssi is not None:
+ self._add_feature(
+ Feature(
+ self._device,
+ container=self,
+ id="rssi",
+ name="RSSI",
+ attribute_getter="rssi",
+ icon="mdi:signal",
+ unit_getter=lambda: "dBm",
+ category=Feature.Category.Debug,
+ type=Feature.Type.Sensor,
+ )
+ )
+ self._add_feature(
+ Feature(
+ self._device,
+ container=self,
+ id="signal_level",
+ name="Signal Level",
+ attribute_getter="signal_level",
+ icon="mdi:signal",
+ category=Feature.Category.Info,
+ type=Feature.Type.Sensor,
+ )
+ )
async def _post_update_hook(self) -> None:
"""Overriden to prevent module disabling.
@@ -37,4 +70,14 @@ class DeviceModule(SmartCamModule):
@property
def device_id(self) -> str:
"""Return the device id."""
- return self.data["basic_info"]["dev_id"]
+ return self.data[self.QUERY_GETTER_NAME]["basic_info"]["dev_id"]
+
+ @property
+ def rssi(self) -> int | None:
+ """Return the device id."""
+ return self.data["getConnectionType"].get("rssiValue")
+
+ @property
+ def signal_level(self) -> int | None:
+ """Return the device id."""
+ return self.data["getConnectionType"].get("rssi")
diff --git a/kasa/smartcam/modules/homekit.py b/kasa/smartcam/modules/homekit.py
new file mode 100644
index 00000000..a35de4f9
--- /dev/null
+++ b/kasa/smartcam/modules/homekit.py
@@ -0,0 +1,16 @@
+"""Implementation of homekit module."""
+
+from __future__ import annotations
+
+from ..smartcammodule import SmartCamModule
+
+
+class HomeKit(SmartCamModule):
+ """Implementation of homekit module."""
+
+ REQUIRED_COMPONENT = "homekit"
+
+ @property
+ def info(self) -> dict[str, str]:
+ """Not supported, return empty dict."""
+ return {}
diff --git a/kasa/smartcam/modules/lensmask.py b/kasa/smartcam/modules/lensmask.py
new file mode 100644
index 00000000..9257b306
--- /dev/null
+++ b/kasa/smartcam/modules/lensmask.py
@@ -0,0 +1,31 @@
+"""Implementation of lens mask privacy module."""
+
+from __future__ import annotations
+
+import logging
+
+from ..smartcammodule import SmartCamModule
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class LensMask(SmartCamModule):
+ """Implementation of lens mask module."""
+
+ REQUIRED_COMPONENT = "lensMask"
+
+ QUERY_GETTER_NAME = "getLensMaskConfig"
+ QUERY_MODULE_NAME = "lens_mask"
+ QUERY_SECTION_NAMES = "lens_mask_info"
+
+ @property
+ def enabled(self) -> bool:
+ """Return the lens mask state."""
+ return self.data["lens_mask_info"]["enabled"] == "on"
+
+ async def set_enabled(self, enable: bool) -> dict:
+ """Set the lens mask state."""
+ params = {"enabled": "on" if enable else "off"}
+ return await self._device._query_setter_helper(
+ "setLensMaskConfig", self.QUERY_MODULE_NAME, "lens_mask_info", params
+ )
diff --git a/kasa/smartcam/modules/matter.py b/kasa/smartcam/modules/matter.py
new file mode 100644
index 00000000..8ea0e4cf
--- /dev/null
+++ b/kasa/smartcam/modules/matter.py
@@ -0,0 +1,44 @@
+"""Implementation of matter module."""
+
+from __future__ import annotations
+
+from ...feature import Feature
+from ..smartcammodule import SmartCamModule
+
+
+class Matter(SmartCamModule):
+ """Implementation of matter module."""
+
+ QUERY_GETTER_NAME = "getMatterSetupInfo"
+ QUERY_MODULE_NAME = "matter"
+ REQUIRED_COMPONENT = "matter"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="matter_setup_code",
+ name="Matter setup code",
+ container=self,
+ attribute_getter=lambda x: x.info["setup_code"],
+ type=Feature.Type.Sensor,
+ category=Feature.Category.Debug,
+ )
+ )
+ self._add_feature(
+ Feature(
+ self._device,
+ id="matter_setup_payload",
+ name="Matter setup payload",
+ container=self,
+ attribute_getter=lambda x: x.info["setup_payload"],
+ type=Feature.Type.Sensor,
+ category=Feature.Category.Debug,
+ )
+ )
+
+ @property
+ def info(self) -> dict[str, str]:
+ """Matter setup info."""
+ return self.data
diff --git a/kasa/smartcam/modules/motiondetection.py b/kasa/smartcam/modules/motiondetection.py
new file mode 100644
index 00000000..33067bdf
--- /dev/null
+++ b/kasa/smartcam/modules/motiondetection.py
@@ -0,0 +1,47 @@
+"""Implementation of motion detection module."""
+
+from __future__ import annotations
+
+import logging
+
+from ...feature import Feature
+from ..smartcammodule import SmartCamModule
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class MotionDetection(SmartCamModule):
+ """Implementation of motion detection module."""
+
+ REQUIRED_COMPONENT = "detection"
+
+ QUERY_GETTER_NAME = "getDetectionConfig"
+ QUERY_MODULE_NAME = "motion_detection"
+ QUERY_SECTION_NAMES = "motion_det"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="motion_detection",
+ name="Motion detection",
+ container=self,
+ attribute_getter="enabled",
+ attribute_setter="set_enabled",
+ type=Feature.Type.Switch,
+ category=Feature.Category.Primary,
+ )
+ )
+
+ @property
+ def enabled(self) -> bool:
+ """Return the motion detection enabled state."""
+ return self.data["motion_det"]["enabled"] == "on"
+
+ async def set_enabled(self, enable: bool) -> dict:
+ """Set the motion detection enabled state."""
+ params = {"enabled": "on" if enable else "off"}
+ return await self._device._query_setter_helper(
+ "setDetectionConfig", self.QUERY_MODULE_NAME, "motion_det", params
+ )
diff --git a/kasa/smartcam/modules/persondetection.py b/kasa/smartcam/modules/persondetection.py
new file mode 100644
index 00000000..641609d5
--- /dev/null
+++ b/kasa/smartcam/modules/persondetection.py
@@ -0,0 +1,47 @@
+"""Implementation of person detection module."""
+
+from __future__ import annotations
+
+import logging
+
+from ...feature import Feature
+from ..smartcammodule import SmartCamModule
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class PersonDetection(SmartCamModule):
+ """Implementation of person detection module."""
+
+ REQUIRED_COMPONENT = "personDetection"
+
+ QUERY_GETTER_NAME = "getPersonDetectionConfig"
+ QUERY_MODULE_NAME = "people_detection"
+ QUERY_SECTION_NAMES = "detection"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="person_detection",
+ name="Person detection",
+ container=self,
+ attribute_getter="enabled",
+ attribute_setter="set_enabled",
+ type=Feature.Type.Switch,
+ category=Feature.Category.Primary,
+ )
+ )
+
+ @property
+ def enabled(self) -> bool:
+ """Return the person detection enabled state."""
+ return self.data["detection"]["enabled"] == "on"
+
+ async def set_enabled(self, enable: bool) -> dict:
+ """Set the person detection enabled state."""
+ params = {"enabled": "on" if enable else "off"}
+ return await self._device._query_setter_helper(
+ "setPersonDetectionConfig", self.QUERY_MODULE_NAME, "detection", params
+ )
diff --git a/kasa/smartcam/modules/tamperdetection.py b/kasa/smartcam/modules/tamperdetection.py
new file mode 100644
index 00000000..32b352f7
--- /dev/null
+++ b/kasa/smartcam/modules/tamperdetection.py
@@ -0,0 +1,47 @@
+"""Implementation of tamper detection module."""
+
+from __future__ import annotations
+
+import logging
+
+from ...feature import Feature
+from ..smartcammodule import SmartCamModule
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class TamperDetection(SmartCamModule):
+ """Implementation of tamper detection module."""
+
+ REQUIRED_COMPONENT = "tamperDetection"
+
+ QUERY_GETTER_NAME = "getTamperDetectionConfig"
+ QUERY_MODULE_NAME = "tamper_detection"
+ QUERY_SECTION_NAMES = "tamper_det"
+
+ def _initialize_features(self) -> None:
+ """Initialize features after the initial update."""
+ self._add_feature(
+ Feature(
+ self._device,
+ id="tamper_detection",
+ name="Tamper detection",
+ container=self,
+ attribute_getter="enabled",
+ attribute_setter="set_enabled",
+ type=Feature.Type.Switch,
+ category=Feature.Category.Primary,
+ )
+ )
+
+ @property
+ def enabled(self) -> bool:
+ """Return the tamper detection enabled state."""
+ return self.data["tamper_det"]["enabled"] == "on"
+
+ async def set_enabled(self, enable: bool) -> dict:
+ """Set the tamper detection enabled state."""
+ params = {"enabled": "on" if enable else "off"}
+ return await self._device._query_setter_helper(
+ "setTamperDetectionConfig", self.QUERY_MODULE_NAME, "tamper_det", params
+ )
diff --git a/kasa/smartcam/smartcamdevice.py b/kasa/smartcam/smartcamdevice.py
index 0090117e..fdae3140 100644
--- a/kasa/smartcam/smartcamdevice.py
+++ b/kasa/smartcam/smartcamdevice.py
@@ -3,13 +3,14 @@
from __future__ import annotations
import logging
-from typing import Any
+from typing import Any, cast
-from ..device import _DeviceInfo
+from ..device import DeviceInfo
from ..device_type import DeviceType
from ..module import Module
from ..protocols.smartcamprotocol import _ChildCameraProtocolWrapper
from ..smart import SmartChildDevice, SmartDevice
+from ..smart.smartdevice import ComponentsRaw
from .modules import ChildDevice, DeviceModule
from .smartcammodule import SmartCamModule
@@ -36,7 +37,7 @@ class SmartCamDevice(SmartDevice):
@staticmethod
def _get_device_info(
info: dict[str, Any], discovery_info: dict[str, Any] | None
- ) -> _DeviceInfo:
+ ) -> DeviceInfo:
"""Get model information for a device."""
basic_info = info["getDeviceInfo"]["device_info"]["basic_info"]
short_name = basic_info["device_model"]
@@ -44,7 +45,7 @@ class SmartCamDevice(SmartDevice):
device_type = SmartCamDevice._get_device_type_from_sysinfo(basic_info)
fw_version_full = basic_info["sw_version"]
firmware_version, firmware_build = fw_version_full.split(" ", maxsplit=1)
- return _DeviceInfo(
+ return DeviceInfo(
short_name=basic_info["device_model"],
long_name=long_name,
brand="tapo",
@@ -78,7 +79,7 @@ class SmartCamDevice(SmartDevice):
self._children[child_id]._update_internal_state(info)
async def _initialize_smart_child(
- self, info: dict, child_components: dict
+ self, info: dict, child_components_raw: ComponentsRaw
) -> SmartDevice:
"""Initialize a smart child device attached to a smartcam device."""
child_id = info["device_id"]
@@ -93,7 +94,7 @@ class SmartCamDevice(SmartDevice):
return await SmartChildDevice.create(
parent=self,
child_info=info,
- child_components=child_components,
+ child_components_raw=child_components_raw,
protocol=child_protocol,
last_update=initial_response,
)
@@ -108,17 +109,8 @@ class SmartCamDevice(SmartDevice):
self.internal_state.update(resp)
smart_children_components = {
- child["device_id"]: {
- comp["id"]: int(comp["ver_code"]) for comp in component_list
- }
+ child["device_id"]: child
for child in resp["getChildDeviceComponentList"]["child_component_list"]
- if (component_list := child.get("component_list"))
- # Child camera devices will have a different component schema so only
- # extract smart values.
- and (first_comp := next(iter(component_list), None))
- and isinstance(first_comp, dict)
- and "id" in first_comp
- and "ver_code" in first_comp
}
children = {}
for info in resp["getChildDeviceList"]["child_device_list"]:
@@ -142,6 +134,11 @@ class SmartCamDevice(SmartDevice):
if (
mod.REQUIRED_COMPONENT
and mod.REQUIRED_COMPONENT not in self._components
+ # Always add Camera module to cameras
+ and (
+ mod._module_name() != Module.Camera
+ or self._device_type is not DeviceType.Camera
+ )
):
continue
module = mod(self, mod._module_name())
@@ -172,6 +169,13 @@ class SmartCamDevice(SmartDevice):
return res
+ @staticmethod
+ def _parse_components(components_raw: ComponentsRaw) -> dict[str, int]:
+ return {
+ str(comp["name"]): int(comp["version"])
+ for comp in components_raw["app_component_list"]
+ }
+
async def _negotiate(self) -> None:
"""Perform initialization.
@@ -181,17 +185,16 @@ class SmartCamDevice(SmartDevice):
initial_query = {
"getDeviceInfo": {"device_info": {"name": ["basic_info", "info"]}},
"getAppComponentList": {"app_component": {"name": "app_component_list"}},
+ "getConnectionType": {"network": {"get_connection_type": {}}},
}
resp = await self.protocol.query(initial_query)
self._last_update.update(resp)
self._update_internal_info(resp)
- self._components = {
- comp["name"]: int(comp["version"])
- for comp in resp["getAppComponentList"]["app_component"][
- "app_component_list"
- ]
- }
+ self._components_raw = cast(
+ ComponentsRaw, resp["getAppComponentList"]["app_component"]
+ )
+ self._components = self._parse_components(self._components_raw)
if "childControl" in self._components and not self.children:
await self._initialize_children()
@@ -251,11 +254,16 @@ class SmartCamDevice(SmartDevice):
def hw_info(self) -> dict:
"""Return hardware info for the device."""
return {
- "sw_ver": self._info.get("hw_ver"),
- "hw_ver": self._info.get("fw_ver"),
+ "sw_ver": self._info.get("fw_ver"),
+ "hw_ver": self._info.get("hw_ver"),
"mac": self._info.get("mac"),
"type": self._info.get("type"),
"hwId": self._info.get("hwId"),
"dev_name": self.alias,
"oemId": self._info.get("oem_id"),
}
+
+ @property
+ def rssi(self) -> int | None:
+ """Return the device id."""
+ return self.modules[SmartCamModule.SmartCamDeviceModule].rssi
diff --git a/kasa/smartcam/smartcammodule.py b/kasa/smartcam/smartcammodule.py
index ca1a3b82..85addd65 100644
--- a/kasa/smartcam/smartcammodule.py
+++ b/kasa/smartcam/smartcammodule.py
@@ -20,9 +20,23 @@ class SmartCamModule(SmartModule):
"""Base class for SMARTCAM modules."""
SmartCamAlarm: Final[ModuleName[modules.Alarm]] = ModuleName("SmartCamAlarm")
+ SmartCamMotionDetection: Final[ModuleName[modules.MotionDetection]] = ModuleName(
+ "MotionDetection"
+ )
+ SmartCamPersonDetection: Final[ModuleName[modules.PersonDetection]] = ModuleName(
+ "PersonDetection"
+ )
+ SmartCamTamperDetection: Final[ModuleName[modules.TamperDetection]] = ModuleName(
+ "TamperDetection"
+ )
+ SmartCamBabyCryDetection: Final[ModuleName[modules.BabyCryDetection]] = ModuleName(
+ "BabyCryDetection"
+ )
+
+ SmartCamDeviceModule: Final[ModuleName[modules.DeviceModule]] = ModuleName(
+ "devicemodule"
+ )
- #: Query to execute during the main update cycle
- QUERY_GETTER_NAME: str
#: Module name to be queried
QUERY_MODULE_NAME: str
#: Section name or names to be queried
@@ -37,6 +51,8 @@ class SmartCamModule(SmartModule):
Default implementation uses the raw query getter w/o parameters.
"""
+ if not self.QUERY_GETTER_NAME:
+ return {}
section_names = (
{"name": self.QUERY_SECTION_NAMES} if self.QUERY_SECTION_NAMES else {}
)
@@ -86,7 +102,8 @@ class SmartCamModule(SmartModule):
f" for '{self._module}'"
)
- return query_resp.get(self.QUERY_MODULE_NAME)
+ # Some calls return the data under the module, others not
+ return query_resp.get(self.QUERY_MODULE_NAME, query_resp)
else:
found = {key: val for key, val in dev._last_update.items() if key in q}
for key in q:
diff --git a/kasa/transports/__init__.py b/kasa/transports/__init__.py
index 602d0cca..192b4156 100644
--- a/kasa/transports/__init__.py
+++ b/kasa/transports/__init__.py
@@ -4,6 +4,7 @@ from .aestransport import AesEncyptionSession, AesTransport
from .basetransport import BaseTransport
from .klaptransport import KlapTransport, KlapTransportV2
from .linkietransport import LinkieTransportV2
+from .sslaestransport import SslAesTransport
from .ssltransport import SslTransport
from .xortransport import XorEncryption, XorTransport
@@ -11,6 +12,7 @@ __all__ = [
"AesTransport",
"AesEncyptionSession",
"SslTransport",
+ "SslAesTransport",
"BaseTransport",
"KlapTransport",
"KlapTransportV2",
diff --git a/kasa/transports/sslaestransport.py b/kasa/transports/sslaestransport.py
index 2061d293..500d9422 100644
--- a/kasa/transports/sslaestransport.py
+++ b/kasa/transports/sslaestransport.py
@@ -8,6 +8,7 @@ import hashlib
import logging
import secrets
import ssl
+from contextlib import suppress
from enum import Enum, auto
from typing import TYPE_CHECKING, Any, cast
@@ -160,6 +161,19 @@ class SslAesTransport(BaseTransport):
error_code = SmartErrorCode.INTERNAL_UNKNOWN_ERROR
return error_code
+ def _get_response_inner_error(self, resp_dict: Any) -> SmartErrorCode | None:
+ error_code_raw = resp_dict.get("data", {}).get("code")
+ if error_code_raw is None:
+ return None
+ try:
+ error_code = SmartErrorCode.from_int(error_code_raw)
+ except ValueError:
+ _LOGGER.warning(
+ "Device %s received unknown error code: %s", self._host, error_code_raw
+ )
+ error_code = SmartErrorCode.INTERNAL_UNKNOWN_ERROR
+ return error_code
+
def _handle_response_error_code(self, resp_dict: Any, msg: str) -> None:
error_code = self._get_response_error(resp_dict)
if error_code is SmartErrorCode.SUCCESS:
@@ -216,6 +230,31 @@ class SslAesTransport(BaseTransport):
ssl=await self._get_ssl_context(),
)
+ if TYPE_CHECKING:
+ assert self._encryption_session is not None
+
+ # Devices can respond with 500 if another session is created from
+ # the same host. Decryption may not succeed after that
+ if status_code == 500:
+ msg = (
+ f"Device {self._host} replied with status 500 after handshake, "
+ f"response: "
+ )
+ decrypted = None
+ if isinstance(resp_dict, dict) and (
+ response := resp_dict.get("result", {}).get("response")
+ ):
+ with suppress(Exception):
+ decrypted = self._encryption_session.decrypt(response.encode())
+
+ if decrypted:
+ msg += decrypted
+ else:
+ msg += str(resp_dict)
+
+ _LOGGER.debug(msg)
+ raise _RetryableError(msg)
+
if status_code != 200:
raise KasaException(
f"{self._host} responded with an unexpected "
@@ -228,7 +267,6 @@ class SslAesTransport(BaseTransport):
if TYPE_CHECKING:
resp_dict = cast(dict[str, Any], resp_dict)
- assert self._encryption_session is not None
if "result" in resp_dict and "response" in resp_dict["result"]:
raw_response: str = resp_dict["result"]["response"]
@@ -383,13 +421,29 @@ class SslAesTransport(BaseTransport):
error_code = default_error_code
resp_dict = default_resp_dict
+ # If the default login worked it's ok not to provide credentials but if
+ # it didn't raise auth error here.
if not self._username:
raise AuthenticationError(
f"Credentials must be supplied to connect to {self._host}"
)
+
+ # Device responds with INVALID_NONCE and a "nonce" to indicate ready
+ # for secure login. Otherwise error.
if error_code is not SmartErrorCode.INVALID_NONCE or (
- resp_dict and "nonce" not in resp_dict["result"].get("data", {})
+ resp_dict and "nonce" not in resp_dict.get("result", {}).get("data", {})
):
+ if (
+ resp_dict
+ and self._get_response_inner_error(resp_dict)
+ is SmartErrorCode.DEVICE_BLOCKED
+ ):
+ sec_left = resp_dict.get("data", {}).get("sec_left")
+ msg = "Device blocked" + (
+ f" for {sec_left} seconds" if sec_left else ""
+ )
+ raise DeviceError(msg, error_code=SmartErrorCode.DEVICE_BLOCKED)
+
raise AuthenticationError(f"Error trying handshake1: {resp_dict}")
if TYPE_CHECKING:
diff --git a/pyproject.toml b/pyproject.toml
index 9dc265c8..2ad192e4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "python-kasa"
-version = "0.8.1"
+version = "0.9.0"
description = "Python API for TP-Link Kasa and Tapo devices"
license = {text = "GPL-3.0-or-later"}
authors = [ { name = "python-kasa developers" }]
diff --git a/tests/device_fixtures.py b/tests/device_fixtures.py
index b1756572..e2041ca9 100644
--- a/tests/device_fixtures.py
+++ b/tests/device_fixtures.py
@@ -79,8 +79,6 @@ PLUGS_IOT = {
"KP125",
"KP401",
}
-# P135 supports dimming, but its not currently support
-# by the library
PLUGS_SMART = {
"P100",
"P110",
@@ -112,7 +110,7 @@ SWITCHES_SMART = {
}
SWITCHES = {*SWITCHES_IOT, *SWITCHES_SMART}
STRIPS_IOT = {"HS107", "HS300", "KP303", "KP200", "KP400", "EP40"}
-STRIPS_SMART = {"P300", "P304M", "TP25", "EP40M"}
+STRIPS_SMART = {"P300", "P304M", "TP25", "EP40M", "P210M", "P306"}
STRIPS = {*STRIPS_IOT, *STRIPS_SMART}
DIMMERS_IOT = {"ES20M", "HS220", "KS220", "KS220M", "KS230", "KP405"}
@@ -435,7 +433,7 @@ async def get_device_for_fixture(
discovery_data = None
if "discovery_result" in fixture_data.data:
- discovery_data = fixture_data.data["discovery_result"]
+ discovery_data = fixture_data.data["discovery_result"]["result"]
elif "system" in fixture_data.data:
discovery_data = {
"system": {"get_sysinfo": fixture_data.data["system"]["get_sysinfo"]}
@@ -473,8 +471,12 @@ def get_nearest_fixture_to_ip(dev):
assert protocol_fixtures, "Unknown device type"
# This will get the best fixture with a match on model region
- if model_region_fixtures := filter_fixtures(
- "", model_filter={dev._model_region}, fixture_list=protocol_fixtures
+ if (di := dev.device_info) and (
+ model_region_fixtures := filter_fixtures(
+ "",
+ model_filter={di.long_name + (f"({di.region})" if di.region else "")},
+ fixture_list=protocol_fixtures,
+ )
):
return next(iter(model_region_fixtures))
diff --git a/tests/discovery_fixtures.py b/tests/discovery_fixtures.py
index 93921536..eb843f1a 100644
--- a/tests/discovery_fixtures.py
+++ b/tests/discovery_fixtures.py
@@ -139,7 +139,8 @@ smart_discovery = parametrize_discovery("smart discovery", protocol_filter={"SMA
)
async def discovery_mock(request, mocker):
"""Mock discovery and patch protocol queries to use Fake protocols."""
- fixture_info: FixtureInfo = request.param
+ fi: FixtureInfo = request.param
+ fixture_info = FixtureInfo(fi.name, fi.protocol, copy.deepcopy(fi.data))
return patch_discovery({DISCOVERY_MOCK_IP: fixture_info}, mocker)
@@ -159,6 +160,17 @@ def create_discovery_mock(ip: str, fixture_data: dict):
login_version: int | None = None
port_override: int | None = None
+ @property
+ def model(self) -> str:
+ dd = self.discovery_data
+ model_region = (
+ dd["result"]["device_model"]
+ if self.discovery_port == 20002
+ else dd["system"]["get_sysinfo"]["model"]
+ )
+ model, _, _ = model_region.partition("(")
+ return model
+
@property
def _datagram(self) -> bytes:
if self.default_port == 9999:
@@ -170,14 +182,17 @@ def create_discovery_mock(ip: str, fixture_data: dict):
)
if "discovery_result" in fixture_data:
- discovery_data = {"result": fixture_data["discovery_result"].copy()}
- discovery_result = fixture_data["discovery_result"]
+ discovery_data = fixture_data["discovery_result"].copy()
+ discovery_result = fixture_data["discovery_result"]["result"]
device_type = discovery_result["device_type"]
encrypt_type = discovery_result["mgt_encrypt_schm"].get(
"encrypt_type", discovery_result.get("encrypt_info", {}).get("sym_schm")
)
- login_version = discovery_result["mgt_encrypt_schm"].get("lv")
+ if not (login_version := discovery_result["mgt_encrypt_schm"].get("lv")) and (
+ et := discovery_result.get("encrypt_type")
+ ):
+ login_version = max([int(i) for i in et])
https = discovery_result["mgt_encrypt_schm"]["is_support_https"]
dm = _DiscoveryMock(
ip,
@@ -305,7 +320,7 @@ def discovery_data(request, mocker):
mocker.patch("kasa.IotProtocol.query", return_value=fixture_data)
mocker.patch("kasa.SmartProtocol.query", return_value=fixture_data)
if "discovery_result" in fixture_data:
- return {"result": fixture_data["discovery_result"]}
+ return fixture_data["discovery_result"].copy()
else:
return {"system": {"get_sysinfo": fixture_data["system"]["get_sysinfo"]}}
diff --git a/tests/fakeprotocol_smart.py b/tests/fakeprotocol_smart.py
index 448729ca..c0222b99 100644
--- a/tests/fakeprotocol_smart.py
+++ b/tests/fakeprotocol_smart.py
@@ -114,6 +114,15 @@ class FakeSmartTransport(BaseTransport):
"type": 0,
},
),
+ "get_homekit_info": (
+ "homekit",
+ {
+ "mfi_setup_code": "000-00-000",
+ "mfi_setup_id": "0000",
+ "mfi_token_token": "000000000000000000000000000000000",
+ "mfi_token_uuid": "00000000-0000-0000-0000-000000000000",
+ },
+ ),
"get_auto_update_info": (
"firmware",
{"enable": True, "random_range": 120, "time": 180},
@@ -151,6 +160,13 @@ class FakeSmartTransport(BaseTransport):
"energy_monitoring",
{"igain": 10861, "vgain": 118657},
),
+ "get_matter_setup_info": (
+ "matter",
+ {
+ "setup_code": "00000000000",
+ "setup_payload": "00:0000000-0000.00.000",
+ },
+ ),
}
async def send(self, request: str):
diff --git a/tests/fakeprotocol_smartcam.py b/tests/fakeprotocol_smartcam.py
index d110e784..381a0a89 100644
--- a/tests/fakeprotocol_smartcam.py
+++ b/tests/fakeprotocol_smartcam.py
@@ -34,6 +34,7 @@ class FakeSmartCamTransport(BaseTransport):
list_return_size=10,
is_child=False,
verbatim=False,
+ components_not_included=False,
):
super().__init__(
config=DeviceConfig(
@@ -44,6 +45,7 @@ class FakeSmartCamTransport(BaseTransport):
),
),
)
+
self.fixture_name = fixture_name
# When True verbatim will bypass any extra processing of missing
# methods and is used to test the fixture creation itself.
@@ -58,6 +60,17 @@ class FakeSmartCamTransport(BaseTransport):
# self.child_protocols = self._get_child_protocols()
self.list_return_size = list_return_size
+ # Setting this flag allows tests to create dummy transports without
+ # full fixture info for testing specific cases like list handling etc
+ self.components_not_included = (components_not_included,)
+ if not components_not_included:
+ self.components = {
+ comp["name"]: comp["version"]
+ for comp in self.info["getAppComponentList"]["app_component"][
+ "app_component_list"
+ ]
+ }
+
@property
def default_port(self):
"""Default port for the transport."""
@@ -112,6 +125,15 @@ class FakeSmartCamTransport(BaseTransport):
info = info[key]
info[set_keys[-1]] = value
+ FIXTURE_MISSING_MAP = {
+ "getMatterSetupInfo": (
+ "matter",
+ {
+ "setup_code": "00000000000",
+ "setup_payload": "00:0000000-0000.00.000",
+ },
+ )
+ }
# Setters for when there's not a simple mapping of setters to getters
SETTERS = {
("system", "sys", "dev_alias"): [
@@ -199,26 +221,38 @@ class FakeSmartCamTransport(BaseTransport):
return {**result, "error_code": 0}
else:
return {"error_code": -1}
- elif method[:3] == "get":
- params = request_dict.get("params")
- if method in info:
- result = copy.deepcopy(info[method])
- if "start_index" in result and "sum" in result:
- list_key = next(
- iter([key for key in result if isinstance(result[key], list)])
- )
- start_index = (
- start_index
- if (params and (start_index := params.get("start_index")))
- else 0
- )
- result[list_key] = result[list_key][
- start_index : start_index + self.list_return_size
- ]
- return {"result": result, "error_code": 0}
- else:
- return {"error_code": -1}
+ if method in info:
+ params = request_dict.get("params")
+ result = copy.deepcopy(info[method])
+ if "start_index" in result and "sum" in result:
+ list_key = next(
+ iter([key for key in result if isinstance(result[key], list)])
+ )
+ start_index = (
+ start_index
+ if (params and (start_index := params.get("start_index")))
+ else 0
+ )
+
+ result[list_key] = result[list_key][
+ start_index : start_index + self.list_return_size
+ ]
+ return {"result": result, "error_code": 0}
+
+ if self.verbatim:
+ return {"error_code": -1}
+
+ if (
+ # FIXTURE_MISSING is for service calls not in place when
+ # SMART fixtures started to be generated
+ missing_result := self.FIXTURE_MISSING_MAP.get(method)
+ ) and missing_result[0] in self.components:
+ # Copy to info so it will work with update methods
+ info[method] = copy.deepcopy(missing_result[1])
+ result = copy.deepcopy(info[method])
+ return {"result": result, "error_code": 0}
+
return {"error_code": -1}
async def close(self) -> None:
diff --git a/tests/fixtureinfo.py b/tests/fixtureinfo.py
index fc1dd1fb..62b71228 100644
--- a/tests/fixtureinfo.py
+++ b/tests/fixtureinfo.py
@@ -145,12 +145,21 @@ def filter_fixtures(
def _component_match(
fixture_data: FixtureInfo, component_filter: str | ComponentFilter
):
- if (component_nego := fixture_data.data.get("component_nego")) is None:
+ components = {}
+ if component_nego := fixture_data.data.get("component_nego"):
+ components = {
+ component["id"]: component["ver_code"]
+ for component in component_nego["component_list"]
+ }
+ if get_app_component_list := fixture_data.data.get("getAppComponentList"):
+ components = {
+ component["name"]: component["version"]
+ for component in get_app_component_list["app_component"][
+ "app_component_list"
+ ]
+ }
+ if not components:
return False
- components = {
- component["id"]: component["ver_code"]
- for component in component_nego["component_list"]
- }
if isinstance(component_filter, str):
return component_filter in components
else:
diff --git a/tests/fixtures/iot/EP10(US)_1.0_1.0.2.json b/tests/fixtures/iot/EP10(US)_1.0_1.0.2.json
index e40543d6..11cafb87 100644
--- a/tests/fixtures/iot/EP10(US)_1.0_1.0.2.json
+++ b/tests/fixtures/iot/EP10(US)_1.0_1.0.2.json
@@ -2,7 +2,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "167 lamp",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Mini",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/EP40(US)_1.0_1.0.2.json b/tests/fixtures/iot/EP40(US)_1.0_1.0.2.json
index 238265a2..5be97e87 100644
--- a/tests/fixtures/iot/EP40(US)_1.0_1.0.2.json
+++ b/tests/fixtures/iot/EP40(US)_1.0_1.0.2.json
@@ -1,12 +1,12 @@
{
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Smart Plug_004F",
+ "alias": "#MASKED_NAME#",
"child_num": 2,
"children": [
{
- "alias": "Zombie",
- "id": "8006231E1499BAC4D4BC7EFCD4B075181E6393F200",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 0
},
{
- "alias": "Magic",
- "id": "8006231E1499BAC4D4BC7EFCD4B075181E6393F201",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/ES20M(US)_1.0_1.0.11.json b/tests/fixtures/iot/ES20M(US)_1.0_1.0.11.json
index 99ecdaa5..6d15034f 100644
--- a/tests/fixtures/iot/ES20M(US)_1.0_1.0.11.json
+++ b/tests/fixtures/iot/ES20M(US)_1.0_1.0.11.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/ES20M(US)_1.0_1.0.8.json b/tests/fixtures/iot/ES20M(US)_1.0_1.0.8.json
index bb316b83..e28301d5 100644
--- a/tests/fixtures/iot/ES20M(US)_1.0_1.0.8.json
+++ b/tests/fixtures/iot/ES20M(US)_1.0_1.0.8.json
@@ -78,7 +78,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test ES20M",
+ "alias": "#MASKED_NAME#",
"brightness": 35,
"dev_name": "Wi-Fi Smart Dimmer with sensor",
"deviceId": "0000000000000000000000000000000000000000",
diff --git a/tests/fixtures/iot/HS100(UK)_4.1_1.1.0.json b/tests/fixtures/iot/HS100(UK)_4.1_1.1.0.json
index 6e33fd7d..324e193a 100644
--- a/tests/fixtures/iot/HS100(UK)_4.1_1.1.0.json
+++ b/tests/fixtures/iot/HS100(UK)_4.1_1.1.0.json
@@ -1,18 +1,21 @@
{
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "HS100(UK)",
- "device_type": "IOT.SMARTPLUGSWITCH",
- "factory_default": true,
- "hw_ver": "4.1",
- "ip": "127.0.0.123",
- "mac": "CC-32-E5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false
- },
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "HS100(UK)",
+ "device_type": "IOT.SMARTPLUGSWITCH",
+ "factory_default": true,
+ "hw_ver": "4.1",
+ "ip": "127.0.0.123",
+ "mac": "CC-32-E5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false
+ },
+ "owner": "00000000000000000000000000000000"
+ }
},
"system": {
"get_sysinfo": {
diff --git a/tests/fixtures/iot/HS100(US)_1.0_1.2.5.json b/tests/fixtures/iot/HS100(US)_1.0_1.2.5.json
index 1bbe29d4..1f2cad62 100644
--- a/tests/fixtures/iot/HS100(US)_1.0_1.2.5.json
+++ b/tests/fixtures/iot/HS100(US)_1.0_1.2.5.json
@@ -18,7 +18,7 @@
"system": {
"get_sysinfo": {
"active_mode": "schedule",
- "alias": "Unused 3",
+ "alias": "#MASKED_NAME#",
"dev_name": "Wi-Fi Smart Plug",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS100(US)_2.0_1.5.6.json b/tests/fixtures/iot/HS100(US)_2.0_1.5.6.json
index 03dd42d5..f73d6233 100644
--- a/tests/fixtures/iot/HS100(US)_2.0_1.5.6.json
+++ b/tests/fixtures/iot/HS100(US)_2.0_1.5.6.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "3D Printer",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS103(US)_1.0_1.5.7.json b/tests/fixtures/iot/HS103(US)_1.0_1.5.7.json
index e5928c3d..ec388dd3 100644
--- a/tests/fixtures/iot/HS103(US)_1.0_1.5.7.json
+++ b/tests/fixtures/iot/HS103(US)_1.0_1.5.7.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "schedule",
- "alias": "Night lite",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Lite",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS103(US)_2.1_1.1.2.json b/tests/fixtures/iot/HS103(US)_2.1_1.1.2.json
index 664845f6..a9064ac7 100644
--- a/tests/fixtures/iot/HS103(US)_2.1_1.1.2.json
+++ b/tests/fixtures/iot/HS103(US)_2.1_1.1.2.json
@@ -18,7 +18,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Corner",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Lite",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS103(US)_2.1_1.1.4.json b/tests/fixtures/iot/HS103(US)_2.1_1.1.4.json
index 819c5bdd..cf7cb935 100644
--- a/tests/fixtures/iot/HS103(US)_2.1_1.1.4.json
+++ b/tests/fixtures/iot/HS103(US)_2.1_1.1.4.json
@@ -2,7 +2,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Plug",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Lite",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS105(US)_1.0_1.5.6.json b/tests/fixtures/iot/HS105(US)_1.0_1.5.6.json
index 79691004..a84c0f49 100644
--- a/tests/fixtures/iot/HS105(US)_1.0_1.5.6.json
+++ b/tests/fixtures/iot/HS105(US)_1.0_1.5.6.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Unused 1",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Mini",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS107(US)_1.0_1.0.8.json b/tests/fixtures/iot/HS107(US)_1.0_1.0.8.json
index 046a89e9..ddc61ef8 100644
--- a/tests/fixtures/iot/HS107(US)_1.0_1.0.8.json
+++ b/tests/fixtures/iot/HS107(US)_1.0_1.0.8.json
@@ -17,12 +17,12 @@
},
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Smart Plug_D310",
+ "alias": "#MASKED_NAME#",
"child_num": 2,
"children": [
{
- "alias": "Garage Charger 1",
- "id": "00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -30,8 +30,8 @@
"state": 0
},
{
- "alias": "Garage Charger 2",
- "id": "01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -46,7 +46,7 @@
"hw_ver": "1.0",
"latitude_i": 0,
"led_off": 0,
- "longitude_i": -0,
+ "longitude_i": 0,
"mac": "00:00:00:00:00:00",
"mic_type": "IOT.SMARTPLUGSWITCH",
"model": "HS107(US)",
diff --git a/tests/fixtures/iot/HS110(EU)_1.0_1.2.5.json b/tests/fixtures/iot/HS110(EU)_1.0_1.2.5.json
index 99cba288..e75b18bc 100644
--- a/tests/fixtures/iot/HS110(EU)_1.0_1.2.5.json
+++ b/tests/fixtures/iot/HS110(EU)_1.0_1.2.5.json
@@ -11,7 +11,7 @@
"system": {
"get_sysinfo": {
"active_mode": "schedule",
- "alias": "Bedroom Lamp Plug",
+ "alias": "#MASKED_NAME#",
"dev_name": "Wi-Fi Smart Plug With Energy Monitoring",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS110(US)_1.0_1.2.6.json b/tests/fixtures/iot/HS110(US)_1.0_1.2.6.json
index 5e285e72..cf5ac065 100644
--- a/tests/fixtures/iot/HS110(US)_1.0_1.2.6.json
+++ b/tests/fixtures/iot/HS110(US)_1.0_1.2.6.json
@@ -11,7 +11,7 @@
"system": {
"get_sysinfo": {
"active_mode": "schedule",
- "alias": "Home Google WiFi HS110",
+ "alias": "#MASKED_NAME#",
"dev_name": "Wi-Fi Smart Plug With Energy Monitoring",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS200(US)_2.0_1.5.7.json b/tests/fixtures/iot/HS200(US)_2.0_1.5.7.json
index 2fbcc65c..31e4a5f9 100644
--- a/tests/fixtures/iot/HS200(US)_2.0_1.5.7.json
+++ b/tests/fixtures/iot/HS200(US)_2.0_1.5.7.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Master Bedroom Fan",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Light Switch",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS200(US)_5.0_1.0.2.json b/tests/fixtures/iot/HS200(US)_5.0_1.0.2.json
index fc09e6f5..44370f2e 100644
--- a/tests/fixtures/iot/HS200(US)_5.0_1.0.2.json
+++ b/tests/fixtures/iot/HS200(US)_5.0_1.0.2.json
@@ -2,7 +2,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "House Fan",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Light Switch",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS210(US)_1.0_1.5.8.json b/tests/fixtures/iot/HS210(US)_1.0_1.5.8.json
index ced3e891..b286c53f 100644
--- a/tests/fixtures/iot/HS210(US)_1.0_1.5.8.json
+++ b/tests/fixtures/iot/HS210(US)_1.0_1.5.8.json
@@ -21,7 +21,7 @@
"get_sysinfo": {
"abnormal_detect": 1,
"active_mode": "none",
- "alias": "Garage Light",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi 3-Way Light Switch",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/HS220(US)_1.0_1.5.7.json b/tests/fixtures/iot/HS220(US)_1.0_1.5.7.json
index eef806fb..3826d198 100644
--- a/tests/fixtures/iot/HS220(US)_1.0_1.5.7.json
+++ b/tests/fixtures/iot/HS220(US)_1.0_1.5.7.json
@@ -28,7 +28,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Living Room Dimmer Switch",
+ "alias": "#MASKED_NAME#",
"brightness": 25,
"dev_name": "Smart Wi-Fi Dimmer",
"deviceId": "000000000000000000000000000000000000000",
@@ -38,9 +38,9 @@
"hwId": "00000000000000000000000000000000",
"hw_ver": "1.0",
"icon_hash": "",
- "latitude_i": 11.6210,
+ "latitude_i": 0,
"led_off": 0,
- "longitude_i": 42.2074,
+ "longitude_i": 0,
"mac": "00:00:00:00:00:00",
"mic_type": "IOT.SMARTPLUGSWITCH",
"model": "HS220(US)",
diff --git a/tests/fixtures/iot/HS220(US)_2.0_1.0.3.json b/tests/fixtures/iot/HS220(US)_2.0_1.0.3.json
index 61e3d84e..d7d0a5a2 100644
--- a/tests/fixtures/iot/HS220(US)_2.0_1.0.3.json
+++ b/tests/fixtures/iot/HS220(US)_2.0_1.0.3.json
@@ -17,7 +17,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Living Room Dimmer Switch",
+ "alias": "#MASKED_NAME#",
"brightness": 100,
"dev_name": "Wi-Fi Smart Dimmer",
"deviceId": "0000000000000000000000000000000000000000",
diff --git a/tests/fixtures/iot/HS300(US)_1.0_1.0.10.json b/tests/fixtures/iot/HS300(US)_1.0_1.0.10.json
index a6d34957..0fc22a39 100644
--- a/tests/fixtures/iot/HS300(US)_1.0_1.0.10.json
+++ b/tests/fixtures/iot/HS300(US)_1.0_1.0.10.json
@@ -22,12 +22,12 @@
},
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Power Strip_DAE1",
+ "alias": "#MASKED_NAME#",
"child_num": 6,
"children": [
{
- "alias": "Office Monitor 1",
- "id": "00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -35,8 +35,8 @@
"state": 0
},
{
- "alias": "Office Monitor 2",
- "id": "01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -44,8 +44,8 @@
"state": 0
},
{
- "alias": "Office Monitor 3",
- "id": "02",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
@@ -53,8 +53,8 @@
"state": 0
},
{
- "alias": "Office Laptop Dock",
- "id": "03",
+ "alias": "#MASKED_NAME# 4",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_4",
"next_action": {
"type": -1
},
@@ -62,8 +62,8 @@
"state": 0
},
{
- "alias": "Office Desk Light",
- "id": "04",
+ "alias": "#MASKED_NAME# 5",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_5",
"next_action": {
"type": -1
},
@@ -71,8 +71,8 @@
"state": 0
},
{
- "alias": "Laptop",
- "id": "05",
+ "alias": "#MASKED_NAME# 6",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_6",
"next_action": {
"type": -1
},
@@ -87,7 +87,7 @@
"hw_ver": "1.0",
"latitude_i": 0,
"led_off": 0,
- "longitude_i": -0,
+ "longitude_i": 0,
"mac": "00:00:00:00:00:00",
"mic_type": "IOT.SMARTPLUGSWITCH",
"model": "HS300(US)",
diff --git a/tests/fixtures/iot/HS300(US)_1.0_1.0.21.json b/tests/fixtures/iot/HS300(US)_1.0_1.0.21.json
index 388fadf3..a174027c 100644
--- a/tests/fixtures/iot/HS300(US)_1.0_1.0.21.json
+++ b/tests/fixtures/iot/HS300(US)_1.0_1.0.21.json
@@ -10,12 +10,12 @@
},
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Power Strip_2CA9",
+ "alias": "#MASKED_NAME#",
"child_num": 6,
"children": [
{
- "alias": "Home CameraPC",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -23,8 +23,8 @@
"state": 1
},
{
- "alias": "Home Firewalla",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -32,8 +32,8 @@
"state": 1
},
{
- "alias": "Home Cox modem",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED02",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
@@ -41,8 +41,8 @@
"state": 1
},
{
- "alias": "Home rpi3-2",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED03",
+ "alias": "#MASKED_NAME# 4",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_4",
"next_action": {
"type": -1
},
@@ -50,8 +50,8 @@
"state": 1
},
{
- "alias": "Home Camera Switch",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED05",
+ "alias": "#MASKED_NAME# 5",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_5",
"next_action": {
"type": -1
},
@@ -59,8 +59,8 @@
"state": 1
},
{
- "alias": "Home Network Switch",
- "id": "800623145DFF1AA096363EFD161C2E661A9D8DED04",
+ "alias": "#MASKED_NAME# 6",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_6",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/HS300(US)_2.0_1.0.12.json b/tests/fixtures/iot/HS300(US)_2.0_1.0.12.json
index bdab432e..bca72089 100644
--- a/tests/fixtures/iot/HS300(US)_2.0_1.0.12.json
+++ b/tests/fixtures/iot/HS300(US)_2.0_1.0.12.json
@@ -15,8 +15,8 @@
"child_num": 6,
"children": [
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -24,8 +24,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -33,8 +33,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D02",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
@@ -42,8 +42,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D03",
+ "alias": "#MASKED_NAME# 4",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_4",
"next_action": {
"type": -1
},
@@ -51,8 +51,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D04",
+ "alias": "#MASKED_NAME# 5",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_5",
"next_action": {
"type": -1
},
@@ -60,8 +60,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006A0F1D01120C3F93794F7AACACDBE1EAD246D05",
+ "alias": "#MASKED_NAME# 6",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_6",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/HS300(US)_2.0_1.0.3.json b/tests/fixtures/iot/HS300(US)_2.0_1.0.3.json
index 3b99cf36..8a5b22c4 100644
--- a/tests/fixtures/iot/HS300(US)_2.0_1.0.3.json
+++ b/tests/fixtures/iot/HS300(US)_2.0_1.0.3.json
@@ -11,12 +11,12 @@
},
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Power Strip_5C33",
+ "alias": "#MASKED_NAME#",
"child_num": 6,
"children": [
{
- "alias": "Plug 1",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031900",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -24,8 +24,8 @@
"state": 0
},
{
- "alias": "Plug 2",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031901",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -33,8 +33,8 @@
"state": 0
},
{
- "alias": "Plug 3",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031902",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
@@ -42,8 +42,8 @@
"state": 0
},
{
- "alias": "Plug 4",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031903",
+ "alias": "#MASKED_NAME# 4",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_4",
"next_action": {
"type": -1
},
@@ -51,8 +51,8 @@
"state": 0
},
{
- "alias": "Plug 5",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031904",
+ "alias": "#MASKED_NAME# 5",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_5",
"next_action": {
"type": -1
},
@@ -60,8 +60,8 @@
"state": 0
},
{
- "alias": "Plug 6",
- "id": "8006AF35494E7DB13DDE9B8F40BF2E001E77031905",
+ "alias": "#MASKED_NAME# 6",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_6",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KL110(US)_1.0_1.8.11.json b/tests/fixtures/iot/KL110(US)_1.0_1.8.11.json
index 94c38858..89b623bd 100644
--- a/tests/fixtures/iot/KL110(US)_1.0_1.8.11.json
+++ b/tests/fixtures/iot/KL110(US)_1.0_1.8.11.json
@@ -21,7 +21,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Bulb3",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL120(US)_1.0_1.8.11.json b/tests/fixtures/iot/KL120(US)_1.0_1.8.11.json
index 1d8e1fce..0bbc9886 100644
--- a/tests/fixtures/iot/KL120(US)_1.0_1.8.11.json
+++ b/tests/fixtures/iot/KL120(US)_1.0_1.8.11.json
@@ -19,7 +19,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Home Family Room Table",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL120(US)_1.0_1.8.6.json b/tests/fixtures/iot/KL120(US)_1.0_1.8.6.json
index c251f2fa..50bd202e 100644
--- a/tests/fixtures/iot/KL120(US)_1.0_1.8.6.json
+++ b/tests/fixtures/iot/KL120(US)_1.0_1.8.6.json
@@ -34,11 +34,11 @@
},
"description": "Smart Wi-Fi LED Bulb with Tunable White Light",
"dev_state": "normal",
- "deviceId": "801200814AD69370AC59DE5501319C051AF409C3",
+ "deviceId": "0000000000000000000000000000000000000000",
"disco_ver": "1.0",
"err_code": 0,
"heapsize": 290784,
- "hwId": "111E35908497A05512E259BB76801E10",
+ "hwId": "00000000000000000000000000000000",
"hw_ver": "1.0",
"is_color": 0,
"is_dimmable": 1,
@@ -52,10 +52,10 @@
"on_off": 1,
"saturation": 0
},
- "mic_mac": "D80D17150474",
+ "mic_mac": "D80D17000000",
"mic_type": "IOT.SMARTBULB",
"model": "KL120(US)",
- "oemId": "1210657CD7FBDC72895644388EEFAE8B",
+ "oemId": "00000000000000000000000000000000",
"preferred_state": [
{
"brightness": 100,
diff --git a/tests/fixtures/iot/KL125(US)_1.20_1.0.5.json b/tests/fixtures/iot/KL125(US)_1.20_1.0.5.json
index 1fca6924..aedcb1f6 100644
--- a/tests/fixtures/iot/KL125(US)_1.20_1.0.5.json
+++ b/tests/fixtures/iot/KL125(US)_1.20_1.0.5.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "kasa-bc01",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL125(US)_2.0_1.0.7.json b/tests/fixtures/iot/KL125(US)_2.0_1.0.7.json
index b7fa640b..9d19ca57 100644
--- a/tests/fixtures/iot/KL125(US)_2.0_1.0.7.json
+++ b/tests/fixtures/iot/KL125(US)_2.0_1.0.7.json
@@ -22,7 +22,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test bulb 6",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL130(EU)_1.0_1.8.8.json b/tests/fixtures/iot/KL130(EU)_1.0_1.8.8.json
index f15e3602..ce303462 100644
--- a/tests/fixtures/iot/KL130(EU)_1.0_1.8.8.json
+++ b/tests/fixtures/iot/KL130(EU)_1.0_1.8.8.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KL130(US)_1.0_1.8.11.json b/tests/fixtures/iot/KL130(US)_1.0_1.8.11.json
index 3ee4cb2e..d9eaaca1 100644
--- a/tests/fixtures/iot/KL130(US)_1.0_1.8.11.json
+++ b/tests/fixtures/iot/KL130(US)_1.0_1.8.11.json
@@ -21,7 +21,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Bulb2",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL135(US)_1.0_1.0.15.json b/tests/fixtures/iot/KL135(US)_1.0_1.0.15.json
index b6670a7a..38a8805d 100644
--- a/tests/fixtures/iot/KL135(US)_1.0_1.0.15.json
+++ b/tests/fixtures/iot/KL135(US)_1.0_1.0.15.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KL135(US)_1.0_1.0.6.json b/tests/fixtures/iot/KL135(US)_1.0_1.0.6.json
index dc0ef45a..be34f9c5 100644
--- a/tests/fixtures/iot/KL135(US)_1.0_1.0.6.json
+++ b/tests/fixtures/iot/KL135(US)_1.0_1.0.6.json
@@ -20,7 +20,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "KL135 Bulb",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL400L5(US)_1.0_1.0.5.json b/tests/fixtures/iot/KL400L5(US)_1.0_1.0.5.json
index 64adf555..1bcd088b 100644
--- a/tests/fixtures/iot/KL400L5(US)_1.0_1.0.5.json
+++ b/tests/fixtures/iot/KL400L5(US)_1.0_1.0.5.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 0,
"active_mode": "none",
- "alias": "Kl400",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL400L5(US)_1.0_1.0.8.json b/tests/fixtures/iot/KL400L5(US)_1.0_1.0.8.json
index a737cd2a..6a15c16c 100644
--- a/tests/fixtures/iot/KL400L5(US)_1.0_1.0.8.json
+++ b/tests/fixtures/iot/KL400L5(US)_1.0_1.0.8.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 0,
"active_mode": "none",
- "alias": "Kl400",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL420L5(US)_1.0_1.0.2.json b/tests/fixtures/iot/KL420L5(US)_1.0_1.0.2.json
index 0d19e794..2d16adba 100644
--- a/tests/fixtures/iot/KL420L5(US)_1.0_1.0.2.json
+++ b/tests/fixtures/iot/KL420L5(US)_1.0_1.0.2.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 1,
"active_mode": "none",
- "alias": "Kl420 test",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL430(UN)_2.0_1.0.8.json b/tests/fixtures/iot/KL430(UN)_2.0_1.0.8.json
index a956575b..8a924c19 100644
--- a/tests/fixtures/iot/KL430(UN)_2.0_1.0.8.json
+++ b/tests/fixtures/iot/KL430(UN)_2.0_1.0.8.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 1,
"active_mode": "none",
- "alias": "Bedroom light strip",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL430(US)_1.0_1.0.10.json b/tests/fixtures/iot/KL430(US)_1.0_1.0.10.json
index 9b6d8413..5bda5762 100644
--- a/tests/fixtures/iot/KL430(US)_1.0_1.0.10.json
+++ b/tests/fixtures/iot/KL430(US)_1.0_1.0.10.json
@@ -23,7 +23,7 @@
"system": {
"get_sysinfo": {
"active_mode": "schedule",
- "alias": "Bedroom Lightstrip",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL430(US)_2.0_1.0.11.json b/tests/fixtures/iot/KL430(US)_2.0_1.0.11.json
index f39c5519..380250ff 100644
--- a/tests/fixtures/iot/KL430(US)_2.0_1.0.11.json
+++ b/tests/fixtures/iot/KL430(US)_2.0_1.0.11.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KL430(US)_2.0_1.0.8.json b/tests/fixtures/iot/KL430(US)_2.0_1.0.8.json
index e69a9dc1..c5cf550b 100644
--- a/tests/fixtures/iot/KL430(US)_2.0_1.0.8.json
+++ b/tests/fixtures/iot/KL430(US)_2.0_1.0.8.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 1,
"active_mode": "none",
- "alias": "89 strip",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL430(US)_2.0_1.0.9.json b/tests/fixtures/iot/KL430(US)_2.0_1.0.9.json
index d5f2eafb..2d9f7535 100644
--- a/tests/fixtures/iot/KL430(US)_2.0_1.0.9.json
+++ b/tests/fixtures/iot/KL430(US)_2.0_1.0.9.json
@@ -10,7 +10,7 @@
"get_sysinfo": {
"LEF": 1,
"active_mode": "none",
- "alias": "kl430 updated",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL50(US)_1.0_1.1.13.json b/tests/fixtures/iot/KL50(US)_1.0_1.1.13.json
index f3e43c9a..6e30c136 100644
--- a/tests/fixtures/iot/KL50(US)_1.0_1.1.13.json
+++ b/tests/fixtures/iot/KL50(US)_1.0_1.1.13.json
@@ -22,7 +22,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Kl50",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KL60(UN)_1.0_1.1.4.json b/tests/fixtures/iot/KL60(UN)_1.0_1.1.4.json
index fa842b47..22dadaee 100644
--- a/tests/fixtures/iot/KL60(UN)_1.0_1.1.4.json
+++ b/tests/fixtures/iot/KL60(UN)_1.0_1.1.4.json
@@ -32,7 +32,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "TP-LINK_Smart Bulb_9179",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
@@ -60,7 +60,7 @@
"on_off": 0
},
"longitude_i": 0,
- "mic_mac": "74DA88C89179",
+ "mic_mac": "74DA88000000",
"mic_type": "IOT.SMARTBULB",
"model": "KL60(UN)",
"oemId": "00000000000000000000000000000000",
diff --git a/tests/fixtures/iot/KL60(US)_1.0_1.1.13.json b/tests/fixtures/iot/KL60(US)_1.0_1.1.13.json
index e52cb85c..6834d925 100644
--- a/tests/fixtures/iot/KL60(US)_1.0_1.1.13.json
+++ b/tests/fixtures/iot/KL60(US)_1.0_1.1.13.json
@@ -22,7 +22,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Gold fil",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/iot/KP100(US)_3.0_1.0.1.json b/tests/fixtures/iot/KP100(US)_3.0_1.0.1.json
index fb62654b..46e9ec4e 100644
--- a/tests/fixtures/iot/KP100(US)_3.0_1.0.1.json
+++ b/tests/fixtures/iot/KP100(US)_3.0_1.0.1.json
@@ -2,7 +2,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Kasa",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Mini",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/KP105(UK)_1.0_1.0.5.json b/tests/fixtures/iot/KP105(UK)_1.0_1.0.5.json
index ce194375..91e310d3 100644
--- a/tests/fixtures/iot/KP105(UK)_1.0_1.0.5.json
+++ b/tests/fixtures/iot/KP105(UK)_1.0_1.0.5.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": -7,
diff --git a/tests/fixtures/iot/KP115(US)_1.0_1.0.17.json b/tests/fixtures/iot/KP115(US)_1.0_1.0.17.json
index afb5a5fe..fb5efac8 100644
--- a/tests/fixtures/iot/KP115(US)_1.0_1.0.17.json
+++ b/tests/fixtures/iot/KP115(US)_1.0_1.0.17.json
@@ -11,7 +11,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test plug",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Mini",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/KP125(US)_1.0_1.0.6.json b/tests/fixtures/iot/KP125(US)_1.0_1.0.6.json
index cb32e7c6..2bb0d21e 100644
--- a/tests/fixtures/iot/KP125(US)_1.0_1.0.6.json
+++ b/tests/fixtures/iot/KP125(US)_1.0_1.0.6.json
@@ -11,7 +11,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test plug",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Wi-Fi Plug Mini",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/KP200(US)_3.0_1.0.3.json b/tests/fixtures/iot/KP200(US)_3.0_1.0.3.json
index fef495d6..40a57fd5 100644
--- a/tests/fixtures/iot/KP200(US)_3.0_1.0.3.json
+++ b/tests/fixtures/iot/KP200(US)_3.0_1.0.3.json
@@ -1,12 +1,12 @@
{
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Smart Plug_C2D6",
+ "alias": "#MASKED_NAME#",
"child_num": 2,
"children": [
{
- "alias": "One ",
- "id": "80066788DFFFD572D9F2E4A5A6847669213E039F00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 1
},
{
- "alias": "Two ",
- "id": "80066788DFFFD572D9F2E4A5A6847669213E039F01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP303(UK)_1.0_1.0.3.json b/tests/fixtures/iot/KP303(UK)_1.0_1.0.3.json
index d02d766b..b5c6a105 100644
--- a/tests/fixtures/iot/KP303(UK)_1.0_1.0.3.json
+++ b/tests/fixtures/iot/KP303(UK)_1.0_1.0.3.json
@@ -1,12 +1,12 @@
{
"system": {
"get_sysinfo": {
- "alias": "Bedroom Power Strip",
+ "alias": "#MASKED_NAME#",
"child_num": 3,
"children": [
{
- "alias": "Plug 1",
- "id": "8006E9854025B67C3F9D99BA1E66223D1C9A8A7700",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 1
},
{
- "alias": "Plug 2",
- "id": "8006E9854025B67C3F9D99BA1E66223D1C9A8A7701",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -23,8 +23,8 @@
"state": 0
},
{
- "alias": "Plug 3",
- "id": "8006E9854025B67C3F9D99BA1E66223D1C9A8A7702",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP303(US)_2.0_1.0.3.json b/tests/fixtures/iot/KP303(US)_2.0_1.0.3.json
index 96c2f8c9..a9590557 100644
--- a/tests/fixtures/iot/KP303(US)_2.0_1.0.3.json
+++ b/tests/fixtures/iot/KP303(US)_2.0_1.0.3.json
@@ -1,12 +1,12 @@
{
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Power Strip_BDF6",
+ "alias": "#MASKED_NAME#",
"child_num": 3,
"children": [
{
- "alias": "Plug 1",
- "id": "800681855E0E9AEF096F4891B3DC88C71E59F42E00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 0
},
{
- "alias": "Plug 2",
- "id": "800681855E0E9AEF096F4891B3DC88C71E59F42E01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -23,8 +23,8 @@
"state": 0
},
{
- "alias": "Plug 3",
- "id": "800681855E0E9AEF096F4891B3DC88C71E59F42E02",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP303(US)_2.0_1.0.9.json b/tests/fixtures/iot/KP303(US)_2.0_1.0.9.json
index d500ebb8..333df3f6 100644
--- a/tests/fixtures/iot/KP303(US)_2.0_1.0.9.json
+++ b/tests/fixtures/iot/KP303(US)_2.0_1.0.9.json
@@ -5,8 +5,8 @@
"child_num": 3,
"children": [
{
- "alias": "#MASKED_NAME#",
- "id": "800639AA097730E58235162FCDA301CE1F038F9101",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "800639AA097730E58235162FCDA301CE1F038F9102",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
@@ -23,8 +23,8 @@
"state": 0
},
{
- "alias": "#MASKED_NAME#",
- "id": "800639AA097730E58235162FCDA301CE1F038F9100",
+ "alias": "#MASKED_NAME# 3",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_3",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP400(US)_1.0_1.0.10.json b/tests/fixtures/iot/KP400(US)_1.0_1.0.10.json
index afdb7bfc..cd09a434 100644
--- a/tests/fixtures/iot/KP400(US)_1.0_1.0.10.json
+++ b/tests/fixtures/iot/KP400(US)_1.0_1.0.10.json
@@ -17,12 +17,12 @@
},
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Smart Plug_2ECE",
+ "alias": "#MASKED_NAME#",
"child_num": 2,
"children": [
{
- "alias": "Rope",
- "id": "00",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"action": 1,
"schd_sec": 69240,
@@ -32,8 +32,8 @@
"state": 0
},
{
- "alias": "Plug 2",
- "id": "01",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP400(US)_2.0_1.0.6.json b/tests/fixtures/iot/KP400(US)_2.0_1.0.6.json
index 23cd22d1..3f838a91 100644
--- a/tests/fixtures/iot/KP400(US)_2.0_1.0.6.json
+++ b/tests/fixtures/iot/KP400(US)_2.0_1.0.6.json
@@ -1,12 +1,12 @@
{
"system": {
"get_sysinfo": {
- "alias": "TP-LINK_Smart Plug_DC2A",
+ "alias": "#MASKED_NAME#",
"child_num": 2,
"children": [
{
- "alias": "Anc ",
- "id": "8006B8E953CC4149E2B13AA27E0D18EF1DCFBF3400",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 1
},
{
- "alias": "Plug 2",
- "id": "8006B8E953CC4149E2B13AA27E0D18EF1DCFBF3401",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP400(US)_3.0_1.0.3.json b/tests/fixtures/iot/KP400(US)_3.0_1.0.3.json
index e93eea8f..ec1c37f3 100644
--- a/tests/fixtures/iot/KP400(US)_3.0_1.0.3.json
+++ b/tests/fixtures/iot/KP400(US)_3.0_1.0.3.json
@@ -5,8 +5,8 @@
"child_num": 2,
"children": [
{
- "alias": "#MASKED_NAME#",
- "id": "8006521377E30159055A751347B5A5E321A8D0A100",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 1
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006521377E30159055A751347B5A5E321A8D0A101",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP400(US)_3.0_1.0.4.json b/tests/fixtures/iot/KP400(US)_3.0_1.0.4.json
index 18580f4e..5a60a400 100644
--- a/tests/fixtures/iot/KP400(US)_3.0_1.0.4.json
+++ b/tests/fixtures/iot/KP400(US)_3.0_1.0.4.json
@@ -5,8 +5,8 @@
"child_num": 2,
"children": [
{
- "alias": "#MASKED_NAME#",
- "id": "8006521377E30159055A751347B5A5E321A8D0A100",
+ "alias": "#MASKED_NAME# 1",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_1",
"next_action": {
"type": -1
},
@@ -14,8 +14,8 @@
"state": 0
},
{
- "alias": "#MASKED_NAME#",
- "id": "8006521377E30159055A751347B5A5E321A8D0A101",
+ "alias": "#MASKED_NAME# 2",
+ "id": "SCRUBBED_CHILD_DEVICE_ID_2",
"next_action": {
"type": -1
},
diff --git a/tests/fixtures/iot/KP401(US)_1.0_1.0.0.json b/tests/fixtures/iot/KP401(US)_1.0_1.0.0.json
index 644c4e5f..f3006cf4 100644
--- a/tests/fixtures/iot/KP401(US)_1.0_1.0.0.json
+++ b/tests/fixtures/iot/KP401(US)_1.0_1.0.0.json
@@ -2,7 +2,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Kp401",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Outdoor Plug",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/KP405(US)_1.0_1.0.5.json b/tests/fixtures/iot/KP405(US)_1.0_1.0.5.json
index ad6357f3..806bdc27 100644
--- a/tests/fixtures/iot/KP405(US)_1.0_1.0.5.json
+++ b/tests/fixtures/iot/KP405(US)_1.0_1.0.5.json
@@ -15,7 +15,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Porch Lights",
+ "alias": "#MASKED_NAME#",
"brightness": 50,
"dev_name": "Kasa Smart Wi-Fi Outdoor Plug-In Dimmer",
"deviceId": "0000000000000000000000000000000000000000",
diff --git a/tests/fixtures/iot/KS200(US)_1.0_1.0.8.json b/tests/fixtures/iot/KS200(US)_1.0_1.0.8.json
index 58971dd0..4fc94890 100644
--- a/tests/fixtures/iot/KS200(US)_1.0_1.0.8.json
+++ b/tests/fixtures/iot/KS200(US)_1.0_1.0.8.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KS200M(US)_1.0_1.0.10.json b/tests/fixtures/iot/KS200M(US)_1.0_1.0.10.json
index 24acdb97..f9498ae9 100644
--- a/tests/fixtures/iot/KS200M(US)_1.0_1.0.10.json
+++ b/tests/fixtures/iot/KS200M(US)_1.0_1.0.10.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KS200M(US)_1.0_1.0.8.json b/tests/fixtures/iot/KS200M(US)_1.0_1.0.8.json
index 3806895b..719dab2e 100644
--- a/tests/fixtures/iot/KS200M(US)_1.0_1.0.8.json
+++ b/tests/fixtures/iot/KS200M(US)_1.0_1.0.8.json
@@ -66,7 +66,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test KS200M",
+ "alias": "#MASKED_NAME#",
"dev_name": "Smart Light Switch with PIR",
"deviceId": "0000000000000000000000000000000000000000",
"err_code": 0,
diff --git a/tests/fixtures/iot/KS220(US)_1.0_1.0.13.json b/tests/fixtures/iot/KS220(US)_1.0_1.0.13.json
index f5c8c1dd..debdd722 100644
--- a/tests/fixtures/iot/KS220(US)_1.0_1.0.13.json
+++ b/tests/fixtures/iot/KS220(US)_1.0_1.0.13.json
@@ -11,7 +11,7 @@
"stopConnect": 0,
"tcspInfo": "",
"tcspStatus": 1,
- "username": "#MASKED_NAME#"
+ "username": "user@example.com"
},
"get_intl_fw_list": {
"err_code": 0,
diff --git a/tests/fixtures/iot/KS220M(US)_1.0_1.0.4.json b/tests/fixtures/iot/KS220M(US)_1.0_1.0.4.json
index 40da46fd..3dceb322 100644
--- a/tests/fixtures/iot/KS220M(US)_1.0_1.0.4.json
+++ b/tests/fixtures/iot/KS220M(US)_1.0_1.0.4.json
@@ -78,7 +78,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Garage Entryway Lights",
+ "alias": "#MASKED_NAME#",
"brightness": 100,
"dev_name": "Wi-Fi Smart Dimmer with sensor",
"deviceId": "0000000000000000000000000000000000000000",
diff --git a/tests/fixtures/iot/KS230(US)_1.0_1.0.14.json b/tests/fixtures/iot/KS230(US)_1.0_1.0.14.json
index a9e529bc..8876a1af 100644
--- a/tests/fixtures/iot/KS230(US)_1.0_1.0.14.json
+++ b/tests/fixtures/iot/KS230(US)_1.0_1.0.14.json
@@ -14,7 +14,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "Test KS230",
+ "alias": "#MASKED_NAME#",
"brightness": 60,
"dc_state": 0,
"dev_name": "Wi-Fi Smart 3-Way Dimmer",
diff --git a/tests/fixtures/iot/LB110(US)_1.0_1.8.11.json b/tests/fixtures/iot/LB110(US)_1.0_1.8.11.json
index ec49e91b..8df62f23 100644
--- a/tests/fixtures/iot/LB110(US)_1.0_1.8.11.json
+++ b/tests/fixtures/iot/LB110(US)_1.0_1.8.11.json
@@ -21,7 +21,7 @@
"system": {
"get_sysinfo": {
"active_mode": "none",
- "alias": "TP-LINK_Smart Bulb_43EC",
+ "alias": "#MASKED_NAME#",
"ctrl_protocols": {
"name": "Linkie",
"version": "1.0"
diff --git a/tests/fixtures/smart/EP25(US)_2.6_1.0.1.json b/tests/fixtures/smart/EP25(US)_2.6_1.0.1.json
index 61e12b25..e83c6221 100644
--- a/tests/fixtures/smart/EP25(US)_2.6_1.0.1.json
+++ b/tests/fixtures/smart/EP25(US)_2.6_1.0.1.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "EP25(US)",
- "device_type": "SMART.KASAPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "00-00-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "EP25(US)",
+ "device_type": "SMART.KASAPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "00-00-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/EP25(US)_2.6_1.0.2.json b/tests/fixtures/smart/EP25(US)_2.6_1.0.2.json
index 2d3e2e5e..4aebbe0e 100644
--- a/tests/fixtures/smart/EP25(US)_2.6_1.0.2.json
+++ b/tests/fixtures/smart/EP25(US)_2.6_1.0.2.json
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "EP25(US)",
- "device_type": "SMART.KASAPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "EP25(US)",
+ "device_type": "SMART.KASAPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/EP40M(US)_1.0_1.1.0.json b/tests/fixtures/smart/EP40M(US)_1.0_1.1.0.json
index 1126fad5..9eef29dc 100644
--- a/tests/fixtures/smart/EP40M(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/EP40M(US)_1.0_1.1.0.json
@@ -379,21 +379,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "EP40M(US)",
- "device_type": "SMART.KASAPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-09-0D-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "matter",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "EP40M(US)",
+ "device_type": "SMART.KASAPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-09-0D-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "matter",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": true,
diff --git a/tests/fixtures/smart/H100(EU)_1.0_1.2.3.json b/tests/fixtures/smart/H100(EU)_1.0_1.2.3.json
index 4d4936c6..ba09016a 100644
--- a/tests/fixtures/smart/H100(EU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/H100(EU)_1.0_1.2.3.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "H100(EU)",
- "device_type": "SMART.TAPOHUB",
- "factory_default": true,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "H100(EU)",
+ "device_type": "SMART.TAPOHUB",
+ "factory_default": true,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": ""
+ }
},
"get_auto_update_info": {
"enable": true,
diff --git a/tests/fixtures/smart/H100(EU)_1.0_1.5.10.json b/tests/fixtures/smart/H100(EU)_1.0_1.5.10.json
index 021309c7..8173333a 100644
--- a/tests/fixtures/smart/H100(EU)_1.0_1.5.10.json
+++ b/tests/fixtures/smart/H100(EU)_1.0_1.5.10.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "H100(EU)",
- "device_type": "SMART.TAPOHUB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "H100(EU)",
+ "device_type": "SMART.TAPOHUB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_alarm_configure": {
"duration": 10,
diff --git a/tests/fixtures/smart/H100(EU)_1.0_1.5.5.json b/tests/fixtures/smart/H100(EU)_1.0_1.5.5.json
index 639122bd..fadb35d2 100644
--- a/tests/fixtures/smart/H100(EU)_1.0_1.5.5.json
+++ b/tests/fixtures/smart/H100(EU)_1.0_1.5.5.json
@@ -92,21 +92,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "H100(EU)",
- "device_type": "SMART.TAPOHUB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "H100(EU)",
+ "device_type": "SMART.TAPOHUB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_alarm_configure": {
"duration": 10,
@@ -195,7 +198,7 @@
"ver_code": 1
}
],
- "device_id": "0000000000000000000000000000000000000000"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
}
],
"start_index": 0,
@@ -213,7 +216,7 @@
"current_humidity_exception": -34,
"current_temp": 22.2,
"current_temp_exception": 0,
- "device_id": "0000000000000000000000000000000000000000",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
"fw_ver": "1.7.0 Build 230424 Rel.170332",
"hw_id": "00000000000000000000000000000000",
"hw_ver": "1.0",
diff --git a/tests/fixtures/smart/HS200(US)_5.26_1.0.3.json b/tests/fixtures/smart/HS200(US)_5.26_1.0.3.json
index e67435a9..f17269cc 100644
--- a/tests/fixtures/smart/HS200(US)_5.26_1.0.3.json
+++ b/tests/fixtures/smart/HS200(US)_5.26_1.0.3.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "HS200(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "74-FE-CE-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "HS200(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "74-FE-CE-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/HS220(US)_3.26_1.0.1.json b/tests/fixtures/smart/HS220(US)_3.26_1.0.1.json
index 63ec680b..99818984 100644
--- a/tests/fixtures/smart/HS220(US)_3.26_1.0.1.json
+++ b/tests/fixtures/smart/HS220(US)_3.26_1.0.1.json
@@ -100,20 +100,23 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "owner": "00000000000000000000000000000000",
- "device_type": "SMART.KASASWITCH",
- "device_model": "HS220(US)",
- "ip": "127.0.0.123",
- "mac": "24-2F-D0-00-00-00",
- "is_support_iot_cloud": true,
- "obd_src": "tplink",
- "factory_default": false,
- "mgt_encrypt_schm": {
- "is_support_https": false,
- "encrypt_type": "AES",
- "http_port": 80,
- "lv": 2
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "HS220(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "24-2F-D0-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
}
},
"get_antitheft_rules": {
diff --git a/tests/fixtures/smart/KH100(EU)_1.0_1.2.3.json b/tests/fixtures/smart/KH100(EU)_1.0_1.2.3.json
index 4ef13a07..0f24be14 100644
--- a/tests/fixtures/smart/KH100(EU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/KH100(EU)_1.0_1.2.3.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KH100(EU)",
- "device_type": "SMART.KASAHUB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-42-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KH100(EU)",
+ "device_type": "SMART.KASAHUB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_alarm_configure": {
"duration": 300,
diff --git a/tests/fixtures/smart/KH100(EU)_1.0_1.5.12.json b/tests/fixtures/smart/KH100(EU)_1.0_1.5.12.json
index 937fe36c..53684a58 100644
--- a/tests/fixtures/smart/KH100(EU)_1.0_1.5.12.json
+++ b/tests/fixtures/smart/KH100(EU)_1.0_1.5.12.json
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KH100(EU)",
- "device_type": "SMART.KASAHUB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-42-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KH100(EU)",
+ "device_type": "SMART.KASAHUB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_alarm_configure": {
"duration": 300,
diff --git a/tests/fixtures/smart/KH100(UK)_1.0_1.5.6.json b/tests/fixtures/smart/KH100(UK)_1.0_1.5.6.json
index 33e4cec6..c0eeb89b 100644
--- a/tests/fixtures/smart/KH100(UK)_1.0_1.5.6.json
+++ b/tests/fixtures/smart/KH100(UK)_1.0_1.5.6.json
@@ -1,4 +1,4 @@
- {
+{
"component_nego": {
"component_list": [
{
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KH100(UK)",
- "device_type": "SMART.KASAHUB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KH100(UK)",
+ "device_type": "SMART.KASAHUB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_alarm_configure": {
"duration": 300,
diff --git a/tests/fixtures/smart/KP125M(US)_1.0_1.1.3.json b/tests/fixtures/smart/KP125M(US)_1.0_1.1.3.json
index c7b6ecb9..41a34cb3 100644
--- a/tests/fixtures/smart/KP125M(US)_1.0_1.1.3.json
+++ b/tests/fixtures/smart/KP125M(US)_1.0_1.1.3.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KP125M(US)",
- "device_type": "SMART.KASAPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "00-00-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KP125M(US)",
+ "device_type": "SMART.KASAPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "00-00-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_current_power": {
"current_power": 17
@@ -124,7 +127,7 @@
"longitude": 0,
"mac": "00-00-00-00-00-00",
"model": "KP125M",
- "nickname": "IyNNQVNLRUROQU1FIyM=",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"on_time": 5332,
"overheated": false,
@@ -133,7 +136,7 @@
"rssi": -62,
"signal_level": 2,
"specs": "",
- "ssid": "IyNNQVNLRUROQU1FIyM=",
+ "ssid": "I01BU0tFRF9TU0lEIw==",
"time_diff": -360,
"type": "SMART.KASAPLUG"
},
diff --git a/tests/fixtures/smart/KP125M(US)_1.0_1.2.3.json b/tests/fixtures/smart/KP125M(US)_1.0_1.2.3.json
index 710febeb..9878b65b 100644
--- a/tests/fixtures/smart/KP125M(US)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/KP125M(US)_1.0_1.2.3.json
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KP125M(US)",
- "device_type": "SMART.KASAPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "78-8C-B5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KP125M(US)",
+ "device_type": "SMART.KASAPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "78-8C-B5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/KS205(US)_1.0_1.0.2.json b/tests/fixtures/smart/KS205(US)_1.0_1.0.2.json
index c94d4f2a..60611f33 100644
--- a/tests/fixtures/smart/KS205(US)_1.0_1.0.2.json
+++ b/tests/fixtures/smart/KS205(US)_1.0_1.0.2.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS205(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "00-00-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS205(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "00-00-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/KS205(US)_1.0_1.1.0.json b/tests/fixtures/smart/KS205(US)_1.0_1.1.0.json
index f9ac5af9..9f7419ec 100644
--- a/tests/fixtures/smart/KS205(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/KS205(US)_1.0_1.1.0.json
@@ -76,21 +76,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS205(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "40-ED-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS205(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "40-ED-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": ""
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/KS225(US)_1.0_1.0.2.json b/tests/fixtures/smart/KS225(US)_1.0_1.0.2.json
index e6945cb8..1f2d9d2b 100644
--- a/tests/fixtures/smart/KS225(US)_1.0_1.0.2.json
+++ b/tests/fixtures/smart/KS225(US)_1.0_1.0.2.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS225(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "00-00-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS225(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "00-00-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/KS225(US)_1.0_1.1.0.json b/tests/fixtures/smart/KS225(US)_1.0_1.1.0.json
index 798642d3..61ead929 100644
--- a/tests/fixtures/smart/KS225(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/KS225(US)_1.0_1.1.0.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS225(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS225(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": ""
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/KS240(US)_1.0_1.0.4.json b/tests/fixtures/smart/KS240(US)_1.0_1.0.4.json
index 2775ee7c..15092b85 100644
--- a/tests/fixtures/smart/KS240(US)_1.0_1.0.4.json
+++ b/tests/fixtures/smart/KS240(US)_1.0_1.0.4.json
@@ -414,21 +414,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS240(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS240(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": false,
diff --git a/tests/fixtures/smart/KS240(US)_1.0_1.0.5.json b/tests/fixtures/smart/KS240(US)_1.0_1.0.5.json
index 6d14f7bf..fb6c667d 100644
--- a/tests/fixtures/smart/KS240(US)_1.0_1.0.5.json
+++ b/tests/fixtures/smart/KS240(US)_1.0_1.0.5.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS240(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS240(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": false,
@@ -206,7 +209,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000001"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
},
{
"component_list": [
@@ -267,7 +270,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000000"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
}
],
"start_index": 0,
@@ -279,7 +282,7 @@
"avatar": "switch_ks240",
"bind_count": 1,
"category": "kasa.switch.outlet.sub-fan",
- "device_id": "000000000000000000000000000000000000000000",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"device_on": true,
"fan_sleep_mode_on": false,
"fan_speed_level": 1,
@@ -317,7 +320,7 @@
],
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000001",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
"device_on": false,
"fade_off_time": 1,
"fade_on_time": 1,
diff --git a/tests/fixtures/smart/KS240(US)_1.0_1.0.7.json b/tests/fixtures/smart/KS240(US)_1.0_1.0.7.json
index a3f28309..4630a977 100644
--- a/tests/fixtures/smart/KS240(US)_1.0_1.0.7.json
+++ b/tests/fixtures/smart/KS240(US)_1.0_1.0.7.json
@@ -425,21 +425,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "KS240(US)",
- "device_type": "SMART.KASASWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "KS240(US)",
+ "device_type": "SMART.KASASWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": true,
diff --git a/tests/fixtures/smart/L510B(EU)_3.0_1.0.5.json b/tests/fixtures/smart/L510B(EU)_3.0_1.0.5.json
index a53e93bb..f89dfc69 100644
--- a/tests/fixtures/smart/L510B(EU)_3.0_1.0.5.json
+++ b/tests/fixtures/smart/L510B(EU)_3.0_1.0.5.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L510B(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-E9-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L510B(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-E9-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L510E(US)_3.0_1.0.5.json b/tests/fixtures/smart/L510E(US)_3.0_1.0.5.json
index 9a51ea45..a81222e4 100644
--- a/tests/fixtures/smart/L510E(US)_3.0_1.0.5.json
+++ b/tests/fixtures/smart/L510E(US)_3.0_1.0.5.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L510E(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L510E(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L510E(US)_3.0_1.1.2.json b/tests/fixtures/smart/L510E(US)_3.0_1.1.2.json
index 055674d2..523d4992 100644
--- a/tests/fixtures/smart/L510E(US)_3.0_1.1.2.json
+++ b/tests/fixtures/smart/L510E(US)_3.0_1.1.2.json
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L510E(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L510E(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L530E(EU)_3.0_1.0.6.json b/tests/fixtures/smart/L530E(EU)_3.0_1.0.6.json
index 10b9d300..05c04522 100644
--- a/tests/fixtures/smart/L530E(EU)_3.0_1.0.6.json
+++ b/tests/fixtures/smart/L530E(EU)_3.0_1.0.6.json
@@ -100,21 +100,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L530E(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-E9-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L530E(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-E9-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L530E(EU)_3.0_1.1.0.json b/tests/fixtures/smart/L530E(EU)_3.0_1.1.0.json
index b5b90d32..a32c0463 100644
--- a/tests/fixtures/smart/L530E(EU)_3.0_1.1.0.json
+++ b/tests/fixtures/smart/L530E(EU)_3.0_1.1.0.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L530E(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-E9-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L530E(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-E9-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L530E(EU)_3.0_1.1.6.json b/tests/fixtures/smart/L530E(EU)_3.0_1.1.6.json
index 0e0ad2fa..8da76d78 100644
--- a/tests/fixtures/smart/L530E(EU)_3.0_1.1.6.json
+++ b/tests/fixtures/smart/L530E(EU)_3.0_1.1.6.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L530E(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-E9-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L530E(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-E9-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
@@ -175,7 +178,7 @@
"longitude": 0,
"mac": "5C-E9-31-00-00-00",
"model": "L530",
- "nickname": "TGl2aW5nIFJvb20gQnVsYg==",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"overheated": false,
"region": "Europe/Berlin",
diff --git a/tests/fixtures/smart/L530E(US)_2.0_1.1.0.json b/tests/fixtures/smart/L530E(US)_2.0_1.1.0.json
index 6dac1048..0c80d3a5 100644
--- a/tests/fixtures/smart/L530E(US)_2.0_1.1.0.json
+++ b/tests/fixtures/smart/L530E(US)_2.0_1.1.0.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L530E(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-62-8B-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L530E(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-62-8B-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L630(EU)_1.0_1.1.2.json b/tests/fixtures/smart/L630(EU)_1.0_1.1.2.json
index 4ca91c9b..3fb263be 100644
--- a/tests/fixtures/smart/L630(EU)_1.0_1.1.2.json
+++ b/tests/fixtures/smart/L630(EU)_1.0_1.1.2.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L630(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "40-AE-30-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L630(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "40-AE-30-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L900-10(EU)_1.0_1.0.17.json b/tests/fixtures/smart/L900-10(EU)_1.0_1.0.17.json
index 5d05bc94..816cf896 100644
--- a/tests/fixtures/smart/L900-10(EU)_1.0_1.0.17.json
+++ b/tests/fixtures/smart/L900-10(EU)_1.0_1.0.17.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L900-10(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L900-10(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L900-10(US)_1.0_1.0.11.json b/tests/fixtures/smart/L900-10(US)_1.0_1.0.11.json
index 8665c8f3..5c81fd32 100644
--- a/tests/fixtures/smart/L900-10(US)_1.0_1.0.11.json
+++ b/tests/fixtures/smart/L900-10(US)_1.0_1.0.11.json
@@ -100,20 +100,23 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L900-10(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "54-AF-97-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L900-10(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "54-AF-97-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L900-5(EU)_1.0_1.0.17.json b/tests/fixtures/smart/L900-5(EU)_1.0_1.0.17.json
index a281f2ec..7c7ac420 100644
--- a/tests/fixtures/smart/L900-5(EU)_1.0_1.0.17.json
+++ b/tests/fixtures/smart/L900-5(EU)_1.0_1.0.17.json
@@ -104,21 +104,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L900-5(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-42-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L900-5(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L900-5(EU)_1.0_1.1.0.json b/tests/fixtures/smart/L900-5(EU)_1.0_1.1.0.json
index 136d3a0f..98980a4c 100644
--- a/tests/fixtures/smart/L900-5(EU)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/L900-5(EU)_1.0_1.1.0.json
@@ -108,21 +108,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L900-5(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-42-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L900-5(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L920-5(EU)_1.0_1.0.7.json b/tests/fixtures/smart/L920-5(EU)_1.0_1.0.7.json
index a55707ae..3315b19b 100644
--- a/tests/fixtures/smart/L920-5(EU)_1.0_1.0.7.json
+++ b/tests/fixtures/smart/L920-5(EU)_1.0_1.0.7.json
@@ -104,20 +104,23 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L920-5(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": true,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "1C-61-B4-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false
- },
- "obd_src": "tplink",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L920-5(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": true,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "1C-61-B4-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false
+ },
+ "obd_src": "tplink",
+ "owner": ""
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L920-5(EU)_1.0_1.1.3.json b/tests/fixtures/smart/L920-5(EU)_1.0_1.1.3.json
index 5f03b5b6..0f845bf3 100644
--- a/tests/fixtures/smart/L920-5(EU)_1.0_1.1.3.json
+++ b/tests/fixtures/smart/L920-5(EU)_1.0_1.1.3.json
@@ -116,21 +116,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L920-5(EU)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "B4-B0-24-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L920-5(EU)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "B4-B0-24-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L920-5(US)_1.0_1.1.0.json b/tests/fixtures/smart/L920-5(US)_1.0_1.1.0.json
index 2ea0c69f..95e8f969 100644
--- a/tests/fixtures/smart/L920-5(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/L920-5(US)_1.0_1.1.0.json
@@ -112,21 +112,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L920-5(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "00-00-00-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L920-5(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "00-00-00-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L920-5(US)_1.0_1.1.3.json b/tests/fixtures/smart/L920-5(US)_1.0_1.1.3.json
index 5463944d..992f6399 100644
--- a/tests/fixtures/smart/L920-5(US)_1.0_1.1.3.json
+++ b/tests/fixtures/smart/L920-5(US)_1.0_1.1.3.json
@@ -116,21 +116,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L920-5(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "34-60-F9-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L920-5(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "34-60-F9-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/L930-5(US)_1.0_1.1.2.json b/tests/fixtures/smart/L930-5(US)_1.0_1.1.2.json
index de7ae2c7..c374ebc5 100644
--- a/tests/fixtures/smart/L930-5(US)_1.0_1.1.2.json
+++ b/tests/fixtures/smart/L930-5(US)_1.0_1.1.2.json
@@ -124,21 +124,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "L930-5(US)",
- "device_type": "SMART.TAPOBULB",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "L930-5(US)",
+ "device_type": "SMART.TAPOBULB",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P100(US)_1.0.0_1.1.3.json b/tests/fixtures/smart/P100(US)_1.0.0_1.1.3.json
index 337c6f2c..2ae738cd 100644
--- a/tests/fixtures/smart/P100(US)_1.0.0_1.1.3.json
+++ b/tests/fixtures/smart/P100(US)_1.0.0_1.1.3.json
@@ -56,18 +56,21 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P100",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "mac": "1C-3B-F3-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false
- },
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P100",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "mac": "1C-3B-F3-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false
+ },
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
@@ -93,7 +96,7 @@
"hw_ver": "1.0.0",
"ip": "127.0.0.123",
"latitude": 0,
- "location": "hallway",
+ "location": "#MASKED_NAME#",
"longitude": 0,
"mac": "1C-3B-F3-00-00-00",
"model": "P100",
diff --git a/tests/fixtures/smart/P100(US)_1.0.0_1.3.7.json b/tests/fixtures/smart/P100(US)_1.0.0_1.3.7.json
index cdddc72e..5347d070 100644
--- a/tests/fixtures/smart/P100(US)_1.0.0_1.3.7.json
+++ b/tests/fixtures/smart/P100(US)_1.0.0_1.3.7.json
@@ -64,20 +64,23 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P100",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "CC-32-E5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P100",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "CC-32-E5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
@@ -108,7 +111,7 @@
"ip": "127.0.0.123",
"lang": "en_US",
"latitude": 0,
- "location": "bedroom",
+ "location": "#MASKED_NAME#",
"longitude": 0,
"mac": "CC-32-E5-00-00-00",
"model": "P100",
diff --git a/tests/fixtures/smart/P100(US)_1.0.0_1.4.0.json b/tests/fixtures/smart/P100(US)_1.0.0_1.4.0.json
index 5ec33343..ab75faf5 100644
--- a/tests/fixtures/smart/P100(US)_1.0.0_1.4.0.json
+++ b/tests/fixtures/smart/P100(US)_1.0.0_1.4.0.json
@@ -64,20 +64,23 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P100",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "74-DA-88-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P100",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "74-DA-88-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P110(EU)_1.0_1.0.7.json b/tests/fixtures/smart/P110(EU)_1.0_1.0.7.json
index 6332f259..dd7a0360 100644
--- a/tests/fixtures/smart/P110(EU)_1.0_1.0.7.json
+++ b/tests/fixtures/smart/P110(EU)_1.0_1.0.7.json
@@ -72,19 +72,22 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P110(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "34-60-F9-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false
- },
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P110(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "34-60-F9-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false
+ },
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P110(EU)_1.0_1.2.3.json b/tests/fixtures/smart/P110(EU)_1.0_1.2.3.json
index 415e8ce6..62e580fc 100644
--- a/tests/fixtures/smart/P110(EU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/P110(EU)_1.0_1.2.3.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P110(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "48-22-54-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P110(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "48-22-54-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P110(UK)_1.0_1.3.0.json b/tests/fixtures/smart/P110(UK)_1.0_1.3.0.json
index 339c5fb2..0c7f6e83 100644
--- a/tests/fixtures/smart/P110(UK)_1.0_1.3.0.json
+++ b/tests/fixtures/smart/P110(UK)_1.0_1.3.0.json
@@ -88,21 +88,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P110(UK)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "48-22-54-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P110(UK)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "48-22-54-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P110M(AU)_1.0_1.2.3.json b/tests/fixtures/smart/P110M(AU)_1.0_1.2.3.json
index efb88c85..2fea4379 100644
--- a/tests/fixtures/smart/P110M(AU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/P110M(AU)_1.0_1.2.3.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P110M(AU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-09-0D-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P110M(AU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-09-0D-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_off_config": {
"delay_min": 120,
@@ -124,19 +127,6 @@
"get_connect_cloud_state": {
"status": 1
},
- "get_energy_usage": {
- "today_runtime": 306,
- "month_runtime": 12572,
- "today_energy": 173,
- "month_energy": 6110,
- "local_time": "2024-11-22 21:03:25",
- "electricity_charge": [
- 0,
- 0,
- 0
- ],
- "current_power": 74116
- },
"get_current_power": {
"current_power": 74
},
@@ -313,6 +303,19 @@
},
"type": "constant"
},
+ "get_energy_usage": {
+ "current_power": 74116,
+ "electricity_charge": [
+ 0,
+ 0,
+ 0
+ ],
+ "local_time": "2024-11-22 21:03:25",
+ "month_energy": 6110,
+ "month_runtime": 12572,
+ "today_energy": 173,
+ "today_runtime": 306
+ },
"get_fw_download_state": {
"auto_upgrade": false,
"download_progress": 0,
diff --git a/tests/fixtures/smart/P110M(EU)_1.0_1.2.3.json b/tests/fixtures/smart/P110M(EU)_1.0_1.2.3.json
index d8453319..81174d7b 100644
--- a/tests/fixtures/smart/P110M(EU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/P110M(EU)_1.0_1.2.3.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P110M(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "matter",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P110M(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "matter",
+ "owner": ""
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P115(EU)_1.0_1.2.3.json b/tests/fixtures/smart/P115(EU)_1.0_1.2.3.json
index 48cd46f2..33d7465c 100644
--- a/tests/fixtures/smart/P115(EU)_1.0_1.2.3.json
+++ b/tests/fixtures/smart/P115(EU)_1.0_1.2.3.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P115(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": true,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-42-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": ""
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P115(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": true,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": ""
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P115(US)_1.0_1.1.3.json b/tests/fixtures/smart/P115(US)_1.0_1.1.3.json
index 70035368..151f7300 100644
--- a/tests/fixtures/smart/P115(US)_1.0_1.1.3.json
+++ b/tests/fixtures/smart/P115(US)_1.0_1.1.3.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P115(US)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "B0-19-21-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P115(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "B0-19-21-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P125M(US)_1.0_1.1.0.json b/tests/fixtures/smart/P125M(US)_1.0_1.1.0.json
index 78e876d7..1e0cf7e2 100644
--- a/tests/fixtures/smart/P125M(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/P125M(US)_1.0_1.1.0.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P125M(US)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "48-22-54-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P125M(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "48-22-54-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P135(US)_1.0_1.0.5.json b/tests/fixtures/smart/P135(US)_1.0_1.0.5.json
index 9f6c3b03..f1099cc7 100644
--- a/tests/fixtures/smart/P135(US)_1.0_1.0.5.json
+++ b/tests/fixtures/smart/P135(US)_1.0_1.0.5.json
@@ -96,21 +96,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P135(US)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P135(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/P135(US)_1.0_1.2.0.json b/tests/fixtures/smart/P135(US)_1.0_1.2.0.json
new file mode 100644
index 00000000..ec193037
--- /dev/null
+++ b/tests/fixtures/smart/P135(US)_1.0_1.2.0.json
@@ -0,0 +1,419 @@
+{
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "inherit",
+ "ver_code": 1
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "wireless",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "led",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "brightness",
+ "ver_code": 1
+ },
+ {
+ "id": "preset",
+ "ver_code": 1
+ },
+ {
+ "id": "on_off_gradually",
+ "ver_code": 2
+ },
+ {
+ "id": "dimmer_calibration",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "matter",
+ "ver_code": 2
+ }
+ ]
+ },
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P135(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-09-0D-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000",
+ "protocol_version": 1
+ }
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_update_info": {
+ "enable": true,
+ "random_range": 120,
+ "time": 180
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "accessory_at_low_battery": false,
+ "avatar": "plug",
+ "brightness": 100,
+ "default_states": {
+ "re_power_type": "always_off",
+ "re_power_type_capability": [
+ "last_states",
+ "always_on",
+ "always_off"
+ ],
+ "type": "last_states"
+ },
+ "device_id": "0000000000000000000000000000000000000000",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.2.0 Build 240415 Rel.171222",
+ "has_set_location_info": false,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "ip": "127.0.0.123",
+ "lang": "",
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "F0-09-0D-00-00-00",
+ "model": "P135",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 3428,
+ "overheat_status": "normal",
+ "region": "America/Los_Angeles",
+ "rssi": -35,
+ "signal_level": 3,
+ "specs": "",
+ "ssid": "I01BU0tFRF9TU0lEIw==",
+ "time_diff": -480,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_time": {
+ "region": "America/Los_Angeles",
+ "time_diff": -480,
+ "timestamp": 1734735856
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 57,
+ "past7": 57,
+ "today": 57
+ }
+ },
+ "get_fw_download_state": {
+ "auto_upgrade": false,
+ "download_progress": 0,
+ "reboot_time": 5,
+ "status": 0,
+ "upgrade_time": 5
+ },
+ "get_inherit_info": null,
+ "get_latest_fw": {
+ "fw_size": 0,
+ "fw_ver": "1.2.0 Build 240415 Rel.171222",
+ "hw_id": "",
+ "need_to_upgrade": false,
+ "oem_id": "",
+ "release_date": "",
+ "release_note": "",
+ "type": 0
+ },
+ "get_led_info": {
+ "bri_config": {
+ "bri_type": "overall",
+ "overall_bri": 50
+ },
+ "led_rule": "always",
+ "led_status": true,
+ "night_mode": {
+ "end_time": 420,
+ "night_mode_type": "custom",
+ "start_time": 1320
+ }
+ },
+ "get_matter_setup_info": {
+ "setup_code": "00000000000",
+ "setup_payload": "00:0000000000000000000"
+ },
+ "get_next_event": {},
+ "get_on_off_gradually_info": {
+ "off_state": {
+ "duration": 1,
+ "enable": true,
+ "max_duration": 60
+ },
+ "on_state": {
+ "duration": 1,
+ "enable": true,
+ "max_duration": 60
+ }
+ },
+ "get_preset_rules": {
+ "brightness": [
+ 100,
+ 75,
+ 50,
+ 25,
+ 1
+ ]
+ },
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ },
+ "get_wireless_scan_info": {
+ "ap_list": [
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "start_index": 0,
+ "sum": 15,
+ "wep_supported": false
+ },
+ "qs_component_nego": {
+ "component_list": [
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "ble_whole_setup",
+ "ver_code": 1
+ },
+ {
+ "id": "matter",
+ "ver_code": 2
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "inherit",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ }
+ ],
+ "extra_info": {
+ "device_model": "P135",
+ "device_type": "SMART.TAPOPLUG",
+ "is_klap": true
+ }
+ }
+}
diff --git a/tests/fixtures/smart/P210M(US)_1.0_1.0.3.json b/tests/fixtures/smart/P210M(US)_1.0_1.0.3.json
new file mode 100644
index 00000000..61ac4762
--- /dev/null
+++ b/tests/fixtures/smart/P210M(US)_1.0_1.0.3.json
@@ -0,0 +1,1585 @@
+{
+ "child_devices": {
+ "SCRUBBED_CHILD_DEVICE_ID_1": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "energy_monitoring",
+ "ver_code": 2
+ },
+ {
+ "id": "current_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "power_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "charging_protection",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_current_power": {
+ "current_power": 68
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "charging_status": "normal",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "DC6279000000",
+ "model": "P210M",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 170204,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overcurrent_status": "normal",
+ "overheat_status": "normal",
+ "position": 1,
+ "power_protection_status": "normal",
+ "protection_enabled": false,
+ "protection_power": 0,
+ "region": "America/Los_Angeles",
+ "slot_number": 2,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "power_usage": {
+ "past30": 275,
+ "past7": 275,
+ "today": 168
+ },
+ "saved_power": {
+ "past30": 3289,
+ "past7": 3289,
+ "today": 745
+ },
+ "time_usage": {
+ "past30": 3564,
+ "past7": 3564,
+ "today": 913
+ }
+ },
+ "get_electricity_price_config": {
+ "constant_price": 0,
+ "time_of_use_config": {
+ "summer": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ },
+ "winter": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ }
+ },
+ "type": "constant"
+ },
+ "get_emeter_data": {
+ "current_ma": 589,
+ "energy_wh": 249,
+ "power_mw": 68325,
+ "voltage_mv": 120254
+ },
+ "get_emeter_vgain_igain": {
+ "data": [
+ {
+ "igain": 3788,
+ "slot_id": 0,
+ "vgain": 30382
+ },
+ {
+ "igain": 3833,
+ "slot_id": 1,
+ "vgain": 30253
+ }
+ ]
+ },
+ "get_energy_usage": {
+ "electricity_charge": [
+ 0,
+ 0,
+ 0
+ ],
+ "local_time": "2024-12-20 15:13:58",
+ "month_energy": 275,
+ "month_runtime": 3564,
+ "today_energy": 168,
+ "today_runtime": 913
+ },
+ "get_max_power": {
+ "max_power": 1835
+ },
+ "get_next_event": {},
+ "get_protection_power": {
+ "enabled": false,
+ "protection_power": 0
+ },
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ },
+ "SCRUBBED_CHILD_DEVICE_ID_2": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "energy_monitoring",
+ "ver_code": 2
+ },
+ {
+ "id": "current_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "power_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "charging_protection",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_current_power": {
+ "current_power": 0
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "charging_status": "normal",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "DC6279000000",
+ "model": "P210M",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 170204,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overcurrent_status": "normal",
+ "overheat_status": "normal",
+ "position": 2,
+ "power_protection_status": "normal",
+ "protection_enabled": false,
+ "protection_power": 0,
+ "region": "America/Los_Angeles",
+ "slot_number": 2,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "power_usage": {
+ "past30": 0,
+ "past7": 0,
+ "today": 0
+ },
+ "saved_power": {
+ "past30": 3564,
+ "past7": 3564,
+ "today": 913
+ },
+ "time_usage": {
+ "past30": 3564,
+ "past7": 3564,
+ "today": 913
+ }
+ },
+ "get_electricity_price_config": {
+ "constant_price": 0,
+ "time_of_use_config": {
+ "summer": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ },
+ "winter": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ }
+ },
+ "type": "constant"
+ },
+ "get_emeter_data": {
+ "current_ma": 0,
+ "energy_wh": 0,
+ "power_mw": 0,
+ "voltage_mv": 119720
+ },
+ "get_emeter_vgain_igain": {
+ "data": [
+ {
+ "igain": 3788,
+ "slot_id": 0,
+ "vgain": 30382
+ },
+ {
+ "igain": 3833,
+ "slot_id": 1,
+ "vgain": 30253
+ }
+ ]
+ },
+ "get_energy_usage": {
+ "electricity_charge": [
+ 0,
+ 0,
+ 0
+ ],
+ "local_time": "2024-12-20 15:13:58",
+ "month_energy": 0,
+ "month_runtime": 3564,
+ "today_energy": 0,
+ "today_runtime": 913
+ },
+ "get_max_power": {
+ "max_power": 1827
+ },
+ "get_next_event": {},
+ "get_protection_power": {
+ "enabled": false,
+ "protection_power": 0
+ },
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ }
+ },
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "wireless",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "led",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "control_child",
+ "ver_code": 2
+ },
+ {
+ "id": "child_device",
+ "ver_code": 2
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "matter",
+ "ver_code": 2
+ },
+ {
+ "id": "energy_monitoring",
+ "ver_code": 2
+ },
+ {
+ "id": "current_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "power_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "charging_protection",
+ "ver_code": 2
+ }
+ ]
+ },
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P210M(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "DC-62-79-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000",
+ "protocol_version": 1
+ }
+ },
+ "get_auto_update_info": {
+ "enable": true,
+ "random_range": 120,
+ "time": 180
+ },
+ "get_child_device_component_list": {
+ "child_component_list": [
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "energy_monitoring",
+ "ver_code": 2
+ },
+ {
+ "id": "current_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "power_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "charging_protection",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
+ },
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "energy_monitoring",
+ "ver_code": 2
+ },
+ {
+ "id": "current_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "power_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "charging_protection",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
+ }
+ ],
+ "start_index": 0,
+ "sum": 2
+ },
+ "get_child_device_list": {
+ "child_device_list": [
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "charging_status": "normal",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "DC6279000000",
+ "model": "P210M",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 170202,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overcurrent_status": "normal",
+ "overheat_status": "normal",
+ "position": 1,
+ "power_protection_status": "normal",
+ "protection_enabled": false,
+ "protection_power": 0,
+ "region": "America/Los_Angeles",
+ "slot_number": 2,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "charging_status": "normal",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "DC6279000000",
+ "model": "P210M",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 170202,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overcurrent_status": "normal",
+ "overheat_status": "normal",
+ "position": 2,
+ "power_protection_status": "normal",
+ "protection_enabled": false,
+ "protection_power": 0,
+ "region": "America/Los_Angeles",
+ "slot_number": 2,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ }
+ ],
+ "start_index": 0,
+ "sum": 2
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_device_info": {
+ "avatar": "",
+ "device_id": "0000000000000000000000000000000000000000",
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "ip": "127.0.0.123",
+ "lang": "en_US",
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "DC-62-79-00-00-00",
+ "model": "P210M",
+ "nickname": "",
+ "oem_id": "00000000000000000000000000000000",
+ "region": "America/Los_Angeles",
+ "rssi": -53,
+ "signal_level": 2,
+ "specs": "",
+ "ssid": "I01BU0tFRF9TU0lEIw==",
+ "time_diff": -480,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_time": {
+ "region": "America/Los_Angeles",
+ "time_diff": -480,
+ "timestamp": 1734736436
+ },
+ "get_device_usage": {
+ "power_usage": {
+ "past30": 275,
+ "past7": 275,
+ "today": 168
+ },
+ "saved_power": {
+ "past30": 3289,
+ "past7": 3289,
+ "today": 745
+ },
+ "time_usage": {
+ "past30": 3564,
+ "past7": 3564,
+ "today": 913
+ }
+ },
+ "get_electricity_price_config": {
+ "constant_price": 0,
+ "time_of_use_config": {
+ "summer": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ },
+ "winter": {
+ "midpeak": 0,
+ "offpeak": 0,
+ "onpeak": 0,
+ "period": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "weekday_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "weekend_config": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ }
+ },
+ "type": "constant"
+ },
+ "get_emeter_vgain_igain": {
+ "data": [
+ {
+ "igain": 3788,
+ "slot_id": 0,
+ "vgain": 30382
+ },
+ {
+ "igain": 3833,
+ "slot_id": 1,
+ "vgain": 30253
+ }
+ ]
+ },
+ "get_fw_download_state": {
+ "auto_upgrade": false,
+ "download_progress": 0,
+ "reboot_time": 5,
+ "status": 0,
+ "upgrade_time": 5
+ },
+ "get_latest_fw": {
+ "fw_size": 0,
+ "fw_ver": "1.0.3 Build 240703 Rel.114246",
+ "hw_id": "",
+ "need_to_upgrade": false,
+ "oem_id": "",
+ "release_date": "",
+ "release_note": "",
+ "type": 0
+ },
+ "get_led_info": {
+ "bri_config": {
+ "bri_type": "overall",
+ "overall_bri": 50
+ },
+ "led_rule": "always",
+ "led_status": true,
+ "night_mode": {
+ "end_time": 420,
+ "night_mode_type": "custom",
+ "start_time": 1320
+ }
+ },
+ "get_matter_setup_info": {
+ "setup_code": "00000000000",
+ "setup_payload": "00:000000000000-000000"
+ },
+ "get_protection_power": {
+ "enabled": false,
+ "protection_power": 0
+ },
+ "get_wireless_scan_info": {
+ "ap_list": [
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "start_index": 0,
+ "sum": 29,
+ "wep_supported": false
+ },
+ "qs_component_nego": {
+ "component_list": [
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "ble_whole_setup",
+ "ver_code": 1
+ },
+ {
+ "id": "matter",
+ "ver_code": 2
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "inherit",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "control_child",
+ "ver_code": 2
+ },
+ {
+ "id": "child_device",
+ "ver_code": 2
+ }
+ ],
+ "extra_info": {
+ "device_model": "P210M",
+ "device_type": "SMART.TAPOPLUG",
+ "is_klap": true
+ }
+ }
+}
diff --git a/tests/fixtures/smart/P300(EU)_1.0_1.0.13.json b/tests/fixtures/smart/P300(EU)_1.0_1.0.13.json
index 0d7d4a3b..73f76e83 100644
--- a/tests/fixtures/smart/P300(EU)_1.0_1.0.13.json
+++ b/tests/fixtures/smart/P300(EU)_1.0_1.0.13.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P300(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "78-8C-B5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P300(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "78-8C-B5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": false,
@@ -170,7 +173,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000002"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
},
{
"component_list": [
@@ -235,7 +238,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000001"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
},
{
"component_list": [
@@ -300,7 +303,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000000"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3"
}
],
"start_index": 0,
@@ -318,7 +321,7 @@
},
"type": "custom"
},
- "device_id": "000000000000000000000000000000000000000002",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
"device_on": false,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.13 Build 230925 Rel.150200",
@@ -347,7 +350,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000001",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"device_on": false,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.13 Build 230925 Rel.150200",
@@ -379,7 +382,7 @@
},
"type": "custom"
},
- "device_id": "000000000000000000000000000000000000000000",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3",
"device_on": false,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.13 Build 230925 Rel.150200",
diff --git a/tests/fixtures/smart/P300(EU)_1.0_1.0.15.json b/tests/fixtures/smart/P300(EU)_1.0_1.0.15.json
index dd40708e..e9d4b54f 100644
--- a/tests/fixtures/smart/P300(EU)_1.0_1.0.15.json
+++ b/tests/fixtures/smart/P300(EU)_1.0_1.0.15.json
@@ -495,21 +495,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P300(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "78-8C-B5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P300(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "78-8C-B5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": false,
diff --git a/tests/fixtures/smart/P300(EU)_1.0_1.0.7.json b/tests/fixtures/smart/P300(EU)_1.0_1.0.7.json
index 17df5ac5..eaa03a35 100644
--- a/tests/fixtures/smart/P300(EU)_1.0_1.0.7.json
+++ b/tests/fixtures/smart/P300(EU)_1.0_1.0.7.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P300(EU)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "78-8C-B5-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P300(EU)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "78-8C-B5-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": true,
@@ -170,7 +173,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000001"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
},
{
"component_list": [
@@ -235,7 +238,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000002"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
},
{
"component_list": [
@@ -300,7 +303,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000003"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3"
}
],
"start_index": 0,
@@ -315,7 +318,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000001",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
"device_on": true,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.7 Build 220715 Rel.200458",
@@ -329,7 +332,7 @@
"nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"on_time": 366,
- "original_device_id": "8022852468EC205A8178C7CBE81FC119213BC020",
+ "original_device_id": "0000000000000000000000000000000000000000",
"overheat_status": "normal",
"position": 1,
"region": "Europe/Berlin",
@@ -344,7 +347,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000002",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"device_on": true,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.7 Build 220715 Rel.200458",
@@ -358,7 +361,7 @@
"nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"on_time": 366,
- "original_device_id": "8022852468EC205A8178C7CBE81FC119213BC020",
+ "original_device_id": "0000000000000000000000000000000000000000",
"overheat_status": "normal",
"position": 2,
"region": "Europe/Berlin",
@@ -373,7 +376,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000003",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3",
"device_on": true,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.7 Build 220715 Rel.200458",
@@ -387,7 +390,7 @@
"nickname": "I01BU0tFRF9OQU1FIw==",
"oem_id": "00000000000000000000000000000000",
"on_time": 366,
- "original_device_id": "8022852468EC205A8178C7CBE81FC119213BC020",
+ "original_device_id": "0000000000000000000000000000000000000000",
"overheat_status": "normal",
"position": 3,
"region": "Europe/Berlin",
diff --git a/tests/fixtures/smart/P304M(UK)_1.0_1.0.3.json b/tests/fixtures/smart/P304M(UK)_1.0_1.0.3.json
index 4e67f482..398977ad 100644
--- a/tests/fixtures/smart/P304M(UK)_1.0_1.0.3.json
+++ b/tests/fixtures/smart/P304M(UK)_1.0_1.0.3.json
@@ -1385,21 +1385,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "P304M(UK)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-6E-84-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P304M(UK)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-6E-84-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": true,
diff --git a/tests/fixtures/smart/P306(US)_1.0_1.1.2.json b/tests/fixtures/smart/P306(US)_1.0_1.1.2.json
new file mode 100644
index 00000000..a5fcb1e8
--- /dev/null
+++ b/tests/fixtures/smart/P306(US)_1.0_1.1.2.json
@@ -0,0 +1,1708 @@
+{
+ "child_devices": {
+ "SCRUBBED_CHILD_DEVICE_ID_1": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "usb",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169807,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 4,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 3561,
+ "past7": 3561,
+ "today": 907
+ }
+ },
+ "get_next_event": {},
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ },
+ "SCRUBBED_CHILD_DEVICE_ID_2": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169808,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 3,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 3561,
+ "past7": 3561,
+ "today": 907
+ }
+ },
+ "get_next_event": {},
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ },
+ "SCRUBBED_CHILD_DEVICE_ID_3": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169808,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 2,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 3561,
+ "past7": 3561,
+ "today": 907
+ }
+ },
+ "get_next_event": {},
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ },
+ "SCRUBBED_CHILD_DEVICE_ID_4": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_auto_off_config": {
+ "delay_min": 120,
+ "enable": false
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_4",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169808,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 1,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 3561,
+ "past7": 3561,
+ "today": 907
+ }
+ },
+ "get_next_event": {},
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ },
+ "SCRUBBED_CHILD_DEVICE_ID_5": {
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "brightness",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ }
+ ]
+ },
+ "get_antitheft_rules": {
+ "antitheft_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_countdown_rules": {
+ "countdown_rule_max_count": 1,
+ "enable": false,
+ "rule_list": []
+ },
+ "get_device_info": {
+ "avatar": "bedside_lamp_1",
+ "bind_count": 1,
+ "brightness": 100,
+ "category": "plug.powerstrip.sub-bulb",
+ "default_states": {
+ "brightness": {
+ "type": "last_states",
+ "value": 100
+ },
+ "re_power_type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_5",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 7169,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 5,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOBULB"
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 2425,
+ "past7": 2425,
+ "today": 758
+ }
+ },
+ "get_next_event": {},
+ "get_schedule_rules": {
+ "enable": false,
+ "rule_list": [],
+ "schedule_rule_max_count": 32,
+ "start_index": 0,
+ "sum": 0
+ }
+ }
+ },
+ "component_nego": {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "wireless",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "led",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "control_child",
+ "ver_code": 2
+ },
+ {
+ "id": "child_device",
+ "ver_code": 2
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ },
+ {
+ "id": "homekit",
+ "ver_code": 2
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ }
+ ]
+ },
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "P306(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-6E-84-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000",
+ "protocol_version": 1
+ }
+ },
+ "get_auto_update_info": {
+ "enable": true,
+ "random_range": 120,
+ "time": 180
+ },
+ "get_child_device_component_list": {
+ "child_component_list": [
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
+ },
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
+ },
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3"
+ },
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_off",
+ "ver_code": 2
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_4"
+ },
+ {
+ "component_list": [
+ {
+ "id": "device",
+ "ver_code": 2
+ },
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "time",
+ "ver_code": 1
+ },
+ {
+ "id": "device_local_time",
+ "ver_code": 1
+ },
+ {
+ "id": "schedule",
+ "ver_code": 2
+ },
+ {
+ "id": "countdown",
+ "ver_code": 2
+ },
+ {
+ "id": "antitheft",
+ "ver_code": 1
+ },
+ {
+ "id": "account",
+ "ver_code": 1
+ },
+ {
+ "id": "synchronize",
+ "ver_code": 1
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "cloud_connect",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "default_states",
+ "ver_code": 1
+ },
+ {
+ "id": "brightness",
+ "ver_code": 1
+ },
+ {
+ "id": "localSmart",
+ "ver_code": 1
+ },
+ {
+ "id": "overheat_protection",
+ "ver_code": 1
+ },
+ {
+ "id": "auto_light_control",
+ "ver_code": 1
+ }
+ ],
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_5"
+ }
+ ],
+ "start_index": 0,
+ "sum": 5
+ },
+ "get_child_device_list": {
+ "child_device_list": [
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "usb",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169805,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 4,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169805,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 3,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_3",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169805,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 2,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ {
+ "auto_off_remain_time": 0,
+ "auto_off_status": "off",
+ "avatar": "plug",
+ "bind_count": 1,
+ "category": "plug.powerstrip.sub-plug",
+ "default_states": {
+ "type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_4",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "is_usb": false,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 169805,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 1,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOPLUG"
+ },
+ {
+ "avatar": "bedside_lamp_1",
+ "bind_count": 1,
+ "brightness": 100,
+ "category": "plug.powerstrip.sub-bulb",
+ "default_states": {
+ "brightness": {
+ "type": "last_states",
+ "value": 100
+ },
+ "re_power_type": "last_states"
+ },
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_5",
+ "device_on": true,
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A86E84000000",
+ "model": "P306",
+ "nickname": "I01BU0tFRF9OQU1FIw==",
+ "oem_id": "00000000000000000000000000000000",
+ "on_time": 7166,
+ "original_device_id": "0000000000000000000000000000000000000000",
+ "overheat_status": "normal",
+ "position": 5,
+ "region": "America/Los_Angeles",
+ "slot_number": 5,
+ "status_follow_edge": true,
+ "type": "SMART.TAPOBULB"
+ }
+ ],
+ "start_index": 0,
+ "sum": 5
+ },
+ "get_connect_cloud_state": {
+ "status": 0
+ },
+ "get_device_info": {
+ "avatar": "",
+ "device_id": "0000000000000000000000000000000000000000",
+ "fw_id": "00000000000000000000000000000000",
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "has_set_location_info": true,
+ "hw_id": "00000000000000000000000000000000",
+ "hw_ver": "1.0",
+ "ip": "127.0.0.123",
+ "lang": "en_US",
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A8-6E-84-00-00-00",
+ "model": "P306",
+ "nickname": "",
+ "oem_id": "00000000000000000000000000000000",
+ "region": "America/Los_Angeles",
+ "rssi": -46,
+ "signal_level": 3,
+ "specs": "",
+ "ssid": "I01BU0tFRF9TU0lEIw==",
+ "time_diff": -480,
+ "type": "SMART.TAPOPLUG"
+ },
+ "get_device_time": {
+ "region": "America/Los_Angeles",
+ "time_diff": -480,
+ "timestamp": 1734736024
+ },
+ "get_device_usage": {
+ "time_usage": {
+ "past30": 3561,
+ "past7": 3561,
+ "today": 907
+ }
+ },
+ "get_fw_download_state": {
+ "auto_upgrade": false,
+ "download_progress": 0,
+ "reboot_time": 5,
+ "status": 0,
+ "upgrade_time": 5
+ },
+ "get_homekit_info": {
+ "mfi_setup_code": "000-00-000",
+ "mfi_setup_id": "0000",
+ "mfi_token_token": "000000000000000000000000000000000000000000000000/00000000000000000000000000000000000000000000000000000000/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/0000000000000000000",
+ "mfi_token_uuid": "00000000-0000-0000-0000-000000000000"
+ },
+ "get_latest_fw": {
+ "fw_size": 0,
+ "fw_ver": "1.1.2 Build 240531 Rel.204226",
+ "hw_id": "",
+ "need_to_upgrade": false,
+ "oem_id": "",
+ "release_date": "",
+ "release_note": "",
+ "type": 0
+ },
+ "get_led_info": {
+ "bri_config": {
+ "bri_type": "overall",
+ "overall_bri": 50
+ },
+ "led_rule": "always",
+ "led_status": true,
+ "night_mode": {
+ "end_time": 420,
+ "night_mode_type": "custom",
+ "start_time": 1320
+ }
+ },
+ "get_wireless_scan_info": {
+ "ap_list": [
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "bssid": "000000000000",
+ "channel": 0,
+ "cipher_type": 2,
+ "key_type": "wpa2_psk",
+ "signal_level": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "start_index": 0,
+ "sum": 24,
+ "wep_supported": false
+ },
+ "qs_component_nego": {
+ "component_list": [
+ {
+ "id": "quick_setup",
+ "ver_code": 3
+ },
+ {
+ "id": "sunrise_sunset",
+ "ver_code": 1
+ },
+ {
+ "id": "ble_whole_setup",
+ "ver_code": 1
+ },
+ {
+ "id": "iot_cloud",
+ "ver_code": 1
+ },
+ {
+ "id": "inherit",
+ "ver_code": 1
+ },
+ {
+ "id": "firmware",
+ "ver_code": 2
+ },
+ {
+ "id": "control_child",
+ "ver_code": 2
+ },
+ {
+ "id": "child_device",
+ "ver_code": 2
+ }
+ ],
+ "extra_info": {
+ "device_model": "P306",
+ "device_type": "SMART.TAPOPLUG",
+ "is_klap": true
+ }
+ }
+}
diff --git a/tests/fixtures/smart/S500D(US)_1.0_1.0.5.json b/tests/fixtures/smart/S500D(US)_1.0_1.0.5.json
index a141e700..3e6ec48d 100644
--- a/tests/fixtures/smart/S500D(US)_1.0_1.0.5.json
+++ b/tests/fixtures/smart/S500D(US)_1.0_1.0.5.json
@@ -92,21 +92,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "S500D(US)",
- "device_type": "SMART.TAPOSWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "48-22-54-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "S500D(US)",
+ "device_type": "SMART.TAPOSWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "48-22-54-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/S505(US)_1.0_1.0.2.json b/tests/fixtures/smart/S505(US)_1.0_1.0.2.json
index c9c63cd7..340bd3a1 100644
--- a/tests/fixtures/smart/S505(US)_1.0_1.0.2.json
+++ b/tests/fixtures/smart/S505(US)_1.0_1.0.2.json
@@ -80,21 +80,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "S505(US)",
- "device_type": "SMART.TAPOSWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "S505(US)",
+ "device_type": "SMART.TAPOSWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/S505D(US)_1.0_1.1.0.json b/tests/fixtures/smart/S505D(US)_1.0_1.1.0.json
index 6adac986..0c990d75 100644
--- a/tests/fixtures/smart/S505D(US)_1.0_1.1.0.json
+++ b/tests/fixtures/smart/S505D(US)_1.0_1.1.0.json
@@ -100,21 +100,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "S505D(US)",
- "device_type": "SMART.TAPOSWITCH",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "48-22-54-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "KLAP",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "matter",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "S505D(US)",
+ "device_type": "SMART.TAPOSWITCH",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "48-22-54-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "KLAP",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "matter",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/TP15(US)_1.0_1.0.3.json b/tests/fixtures/smart/TP15(US)_1.0_1.0.3.json
index 404bfe2f..8d0964b3 100644
--- a/tests/fixtures/smart/TP15(US)_1.0_1.0.3.json
+++ b/tests/fixtures/smart/TP15(US)_1.0_1.0.3.json
@@ -76,21 +76,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "TP15(US)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "5C-62-8B-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "TP15(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-62-8B-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_antitheft_rules": {
"antitheft_rule_max_count": 1,
diff --git a/tests/fixtures/smart/TP25(US)_1.0_1.0.2.json b/tests/fixtures/smart/TP25(US)_1.0_1.0.2.json
index 1e3321f8..b9165414 100644
--- a/tests/fixtures/smart/TP25(US)_1.0_1.0.2.json
+++ b/tests/fixtures/smart/TP25(US)_1.0_1.0.2.json
@@ -84,21 +84,24 @@
]
},
"discovery_result": {
- "device_id": "00000000000000000000000000000000",
- "device_model": "TP25(US)",
- "device_type": "SMART.TAPOPLUG",
- "factory_default": false,
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "3C-52-A1-00-00-00",
- "mgt_encrypt_schm": {
- "encrypt_type": "AES",
- "http_port": 80,
- "is_support_https": false,
- "lv": 2
- },
- "obd_src": "tplink",
- "owner": "00000000000000000000000000000000"
+ "error_code": 0,
+ "result": {
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "TP25(US)",
+ "device_type": "SMART.TAPOPLUG",
+ "factory_default": false,
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "3C-52-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "encrypt_type": "AES",
+ "http_port": 80,
+ "is_support_https": false,
+ "lv": 2
+ },
+ "obd_src": "tplink",
+ "owner": "00000000000000000000000000000000"
+ }
},
"get_auto_update_info": {
"enable": false,
@@ -170,7 +173,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000000"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1"
},
{
"component_list": [
@@ -235,7 +238,7 @@
"ver_code": 1
}
],
- "device_id": "000000000000000000000000000000000000000001"
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2"
}
],
"start_index": 0,
@@ -250,7 +253,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000000",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_1",
"device_on": false,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.2 Build 230206 Rel.095245",
@@ -279,7 +282,7 @@
"default_states": {
"type": "last_states"
},
- "device_id": "000000000000000000000000000000000000000001",
+ "device_id": "SCRUBBED_CHILD_DEVICE_ID_2",
"device_on": true,
"fw_id": "00000000000000000000000000000000",
"fw_ver": "1.0.2 Build 230206 Rel.095245",
diff --git a/tests/fixtures/smartcam/C100_4.0_1.3.14.json b/tests/fixtures/smartcam/C100_4.0_1.3.14.json
new file mode 100644
index 00000000..144cf5f6
--- /dev/null
+++ b/tests/fixtures/smartcam/C100_4.0_1.3.14.json
@@ -0,0 +1,779 @@
+{
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C100",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.3.14 Build 240513 Rel.43631n(5553)",
+ "hardware_version": "4.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ },
+ "protocol_version": 1
+ }
+ },
+ "getAlertPlan": {
+ "msg_alarm_plan": {
+ "chn1_msg_alarm_plan": {
+ ".name": "chn1_msg_alarm_plan",
+ ".type": "plan",
+ "alarm_plan_1": "0000-0000,127",
+ "enabled": "off"
+ }
+ }
+ },
+ "getAppComponentList": {
+ "app_component": {
+ "app_component_list": [
+ {
+ "name": "sdCard",
+ "version": 1
+ },
+ {
+ "name": "timezone",
+ "version": 1
+ },
+ {
+ "name": "system",
+ "version": 3
+ },
+ {
+ "name": "led",
+ "version": 1
+ },
+ {
+ "name": "playback",
+ "version": 4
+ },
+ {
+ "name": "detection",
+ "version": 3
+ },
+ {
+ "name": "alert",
+ "version": 1
+ },
+ {
+ "name": "firmware",
+ "version": 2
+ },
+ {
+ "name": "account",
+ "version": 2
+ },
+ {
+ "name": "quickSetup",
+ "version": 1
+ },
+ {
+ "name": "video",
+ "version": 2
+ },
+ {
+ "name": "lensMask",
+ "version": 2
+ },
+ {
+ "name": "lightFrequency",
+ "version": 1
+ },
+ {
+ "name": "dayNightMode",
+ "version": 1
+ },
+ {
+ "name": "osd",
+ "version": 2
+ },
+ {
+ "name": "record",
+ "version": 1
+ },
+ {
+ "name": "videoRotation",
+ "version": 1
+ },
+ {
+ "name": "audio",
+ "version": 2
+ },
+ {
+ "name": "diagnose",
+ "version": 1
+ },
+ {
+ "name": "msgPush",
+ "version": 3
+ },
+ {
+ "name": "deviceShare",
+ "version": 1
+ },
+ {
+ "name": "tapoCare",
+ "version": 1
+ },
+ {
+ "name": "blockZone",
+ "version": 1
+ },
+ {
+ "name": "personDetection",
+ "version": 2
+ },
+ {
+ "name": "babyCryDetection",
+ "version": 1
+ },
+ {
+ "name": "needSubscriptionServiceList",
+ "version": 1
+ },
+ {
+ "name": "iotCloud",
+ "version": 1
+ },
+ {
+ "name": "recordDownload",
+ "version": 1
+ },
+ {
+ "name": "detectionRegion",
+ "version": 2
+ },
+ {
+ "name": "staticIp",
+ "version": 1
+ }
+ ]
+ }
+ },
+ "getAudioConfig": {
+ "audio_config": {
+ "microphone": {
+ ".name": "microphone",
+ ".type": "audio_config",
+ "channels": "1",
+ "encode_type": "G711alaw",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "100"
+ },
+ "speaker": {
+ ".name": "speaker",
+ ".type": "audio_config",
+ "volume": "40"
+ }
+ }
+ },
+ "getBCDConfig": {
+ "sound_detection": {
+ "bcd": {
+ ".name": "bcd",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getCircularRecordingConfig": {
+ "harddisk_manage": {
+ "harddisk": {
+ ".name": "harddisk",
+ ".type": "storage",
+ "loop": "on"
+ }
+ }
+ },
+ "getClockStatus": {
+ "system": {
+ "clock_status": {
+ "local_time": "2024-12-15 11:11:55",
+ "seconds_from_1970": 1734279115
+ }
+ }
+ },
+ "getConnectionType": {
+ "link_type": "wifi",
+ "rssi": "4",
+ "rssiValue": -15,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ "getDetectionConfig": {
+ "motion_detection": {
+ "motion_det": {
+ ".name": "motion_det",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getDeviceInfo": {
+ "device_info": {
+ "basic_info": {
+ "avatar": "camera c100",
+ "barcode": "",
+ "dev_id": "0000000000000000000000000000000000000000",
+ "device_alias": "#MASKED_NAME#",
+ "device_info": "C100 4.0 IPC",
+ "device_model": "C100",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "features": "3",
+ "ffs": false,
+ "has_set_location_info": 1,
+ "hw_desc": "00000000000000000000000000000000",
+ "hw_version": "4.0",
+ "is_cal": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "F0-A7-31-00-00-00",
+ "oem_id": "00000000000000000000000000000000",
+ "sw_version": "1.3.14 Build 240513 Rel.43631n(5553)"
+ }
+ }
+ },
+ "getFirmwareAutoUpgradeConfig": {
+ "auto_upgrade": {
+ "common": {
+ ".name": "common",
+ ".type": "on_off",
+ "enabled": "off",
+ "random_range": "120",
+ "time": "03:00"
+ }
+ }
+ },
+ "getFirmwareUpdateStatus": {
+ "cloud_config": {
+ "upgrade_status": {
+ "lastUpgradingSuccess": true,
+ "state": "normal"
+ }
+ }
+ },
+ "getLastAlarmInfo": {
+ "system": {
+ "last_alarm_info": {
+ "last_alarm_time": "",
+ "last_alarm_type": ""
+ }
+ }
+ },
+ "getLdc": {
+ "image": {
+ "common": {
+ ".name": "common",
+ ".type": "para",
+ "area_compensation": "default",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "exp_gain": "0",
+ "exp_type": "auto",
+ "focus_limited": "600",
+ "focus_type": "semi_auto",
+ "high_light_compensation": "off",
+ "inf_delay": "10",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "1",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "off",
+ "smartir_level": "100",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off"
+ },
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getLedStatus": {
+ "led": {
+ "config": {
+ ".name": "config",
+ ".type": "led",
+ "enabled": "on"
+ }
+ }
+ },
+ "getLensMaskConfig": {
+ "lens_mask": {
+ "lens_mask_info": {
+ ".name": "lens_mask_info",
+ ".type": "lens_mask_info",
+ "enabled": "off"
+ }
+ }
+ },
+ "getLightFrequencyInfo": {
+ "image": {
+ "common": {
+ ".name": "common",
+ ".type": "para",
+ "area_compensation": "default",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "exp_gain": "0",
+ "exp_type": "auto",
+ "focus_limited": "600",
+ "focus_type": "semi_auto",
+ "high_light_compensation": "off",
+ "inf_delay": "10",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "1",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "off",
+ "smartir_level": "100",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off"
+ }
+ }
+ },
+ "getMediaEncrypt": {
+ "cet": {
+ "media_encrypt": {
+ ".name": "media_encrypt",
+ ".type": "on_off",
+ "enabled": "on"
+ }
+ }
+ },
+ "getMsgPushConfig": {
+ "msg_push": {
+ "chn1_msg_push_info": {
+ ".name": "chn1_msg_push_info",
+ ".type": "on_off",
+ "notification_enabled": "off",
+ "rich_notification_enabled": "off"
+ }
+ }
+ },
+ "getNightVisionModeConfig": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getPersonDetectionConfig": {
+ "people_detection": {
+ "detection": {
+ ".name": "detection",
+ ".type": "on_off",
+ "enabled": "off",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getRecordPlan": {
+ "record_plan": {
+ "chn1_channel": {
+ ".name": "chn1_channel",
+ ".type": "plan",
+ "enabled": "on",
+ "friday": "[\"0000-2400:2\"]",
+ "monday": "[\"0000-2400:2\"]",
+ "saturday": "[\"0000-2400:2\"]",
+ "sunday": "[\"0000-2400:2\"]",
+ "thursday": "[\"0000-2400:2\"]",
+ "tuesday": "[\"0000-2400:2\"]",
+ "wednesday": "[\"0000-2400:2\"]"
+ }
+ }
+ },
+ "getRotationStatus": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getSdCardStatus": {
+ "harddisk_manage": {
+ "hd_info": [
+ {
+ "hd_info_1": {
+ "detect_status": "offline",
+ "disk_name": "1",
+ "free_space": "0B",
+ "loop_record_status": "0",
+ "msg_push_free_space": "0B",
+ "msg_push_total_space": "0B",
+ "percent": "0",
+ "picture_free_space": "0B",
+ "picture_total_space": "0B",
+ "record_duration": "0",
+ "record_free_duration": "0",
+ "record_start_time": "0",
+ "rw_attr": "r",
+ "status": "offline",
+ "total_space": "0B",
+ "type": "local",
+ "video_free_space": "0B",
+ "video_total_space": "0B",
+ "write_protect": "0"
+ }
+ }
+ ]
+ }
+ },
+ "getTamperDetectionConfig": {
+ "tamper_detection": {
+ "tamper_det": {
+ ".name": "tamper_det",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getTimezone": {
+ "system": {
+ "basic": {
+ ".name": "basic",
+ ".type": "setting",
+ "timezone": "UTC-05:00",
+ "timing_mode": "manual",
+ "zone_id": "America/New_York"
+ }
+ }
+ },
+ "getVideoCapability": {
+ "video_capability": {
+ "main": {
+ ".name": "main",
+ ".type": "capability",
+ "bitrate_types": [
+ "cbr",
+ "vbr"
+ ],
+ "bitrates": [
+ "256",
+ "512",
+ "1024",
+ "2048"
+ ],
+ "encode_types": [
+ "H264"
+ ],
+ "frame_rates": [
+ "65537",
+ "65546",
+ "65551"
+ ],
+ "qualitys": [
+ "1",
+ "3",
+ "5"
+ ],
+ "resolutions": [
+ "1920*1080",
+ "1280*720",
+ "640*360"
+ ]
+ }
+ }
+ },
+ "getVideoQualities": {
+ "video": {
+ "main": {
+ ".name": "main",
+ ".type": "stream",
+ "bitrate": "1024",
+ "bitrate_type": "vbr",
+ "encode_type": "H264",
+ "frame_rate": "65551",
+ "gop_factor": "2",
+ "name": "VideoEncoder_1",
+ "quality": "3",
+ "resolution": "1920*1080",
+ "stream_type": "general"
+ }
+ }
+ },
+ "getWhitelampConfig": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getWhitelampStatus": {
+ "rest_time": 0,
+ "status": 0
+ },
+ "get_audio_capability": {
+ "get": {
+ "audio_capability": {
+ "device_microphone": {
+ ".name": "device_microphone",
+ ".type": "capability",
+ "aec": "1",
+ "channels": "1",
+ "echo_cancelling": "0",
+ "encode_type": [
+ "G711alaw"
+ ],
+ "half_duplex": "1",
+ "mute": "1",
+ "noise_cancelling": "1",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ },
+ "device_speaker": {
+ ".name": "device_speaker",
+ ".type": "capability",
+ "channels": "1",
+ "decode_type": [
+ "G711"
+ ],
+ "mute": "0",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ }
+ }
+ }
+ },
+ "get_audio_config": {
+ "get": {
+ "audio_config": {
+ "microphone": {
+ ".name": "microphone",
+ ".type": "audio_config",
+ "channels": "1",
+ "encode_type": "G711alaw",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "100"
+ },
+ "speaker": {
+ ".name": "speaker",
+ ".type": "audio_config",
+ "volume": "40"
+ }
+ }
+ }
+ },
+ "get_cet": {
+ "get": {
+ "cet": {
+ "vhttpd": {
+ ".name": "vhttpd",
+ ".type": "server",
+ "port": "8800"
+ }
+ }
+ }
+ },
+ "get_function": {
+ "get": {
+ "function": {
+ "module_spec": {
+ ".name": "module_spec",
+ ".type": "module-spec",
+ "ae_weighting_table_resolution": "5*5",
+ "ai_enhance_capability": "1",
+ "app_version": "1.0.0",
+ "audio": [
+ "speaker",
+ "microphone"
+ ],
+ "audioexception_detection": "0",
+ "auth_encrypt": "1",
+ "backlight_coexistence": "1",
+ "change_password": "1",
+ "client_info": "1",
+ "cloud_storage_version": "1.0",
+ "custom_area_compensation": "1",
+ "custom_auto_mode_exposure_level": "0",
+ "device_share": [
+ "preview",
+ "playback",
+ "voice",
+ "cloud_storage"
+ ],
+ "download": [
+ "video"
+ ],
+ "events": [
+ "motion",
+ "tamper"
+ ],
+ "greeter": "1.0",
+ "http_system_state_audio_support": "1",
+ "intrusion_detection": "1",
+ "led": "1",
+ "lens_mask": "1",
+ "linecrossing_detection": "1",
+ "linkage_capability": "1",
+ "local_storage": "1",
+ "media_encrypt": "1",
+ "msg_alarm": "1",
+ "msg_alarm_list": [
+ "sound",
+ "light"
+ ],
+ "msg_alarm_separate_list": [
+ "light",
+ "sound"
+ ],
+ "msg_push": "1",
+ "multi_user": "0",
+ "multicast": "0",
+ "network": [
+ "wifi"
+ ],
+ "ota_upgrade": "1",
+ "p2p_support_versions": [
+ "1.1"
+ ],
+ "playback": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "playback_scale": "1",
+ "preview": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "privacy_mask_api_version": "1.0",
+ "record_max_slot_cnt": "10",
+ "record_type": [
+ "timing",
+ "motion"
+ ],
+ "relay_support_versions": [
+ "1.3"
+ ],
+ "reonboarding": "1",
+ "smart_detection": "1",
+ "smart_msg_push_capability": "1",
+ "ssl_cer_version": "1.0",
+ "storage_api_version": "2.2",
+ "stream_max_sessions": "10",
+ "streaming_support_versions": [
+ "1.0"
+ ],
+ "target_track": "0",
+ "timing_reboot": "1",
+ "verification_change_password": "1",
+ "video_codec": [
+ "h264"
+ ],
+ "video_detection_digital_sensitivity": "1",
+ "wifi_cascade_connection": "1",
+ "wifi_connection_info": "1",
+ "wireless_hotspot": "1"
+ }
+ }
+ }
+ }
+}
diff --git a/tests/fixtures/smartcam/C210(EU)_2.0_1.4.2.json b/tests/fixtures/smartcam/C210(EU)_2.0_1.4.2.json
index ba2e0010..609c46be 100644
--- a/tests/fixtures/smartcam/C210(EU)_2.0_1.4.2.json
+++ b/tests/fixtures/smartcam/C210(EU)_2.0_1.4.2.json
@@ -1,35 +1,38 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "0000000000",
- "connect_type": "wireless",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "last_alarm_time": "1729264456",
- "last_alarm_type": "motion",
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "C210",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.IPCAMERA",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.4.2 Build 240829 Rel.54953n",
- "hardware_version": "2.0",
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "40-AE-30-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1729264456",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C210",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.4.2 Build 240829 Rel.54953n",
+ "hardware_version": "2.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "40-AE-30-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
}
},
"getAlertConfig": {
diff --git a/tests/fixtures/smartcam/C210(EU)_2.0_1.4.3.json b/tests/fixtures/smartcam/C210(EU)_2.0_1.4.3.json
index a2f7666e..d4de5b9f 100644
--- a/tests/fixtures/smartcam/C210(EU)_2.0_1.4.3.json
+++ b/tests/fixtures/smartcam/C210(EU)_2.0_1.4.3.json
@@ -1,35 +1,39 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "0000000000",
- "connect_type": "wireless",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "last_alarm_time": "0",
- "last_alarm_type": "",
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "C210",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.IPCAMERA",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.4.3 Build 241010 Rel.33858n",
- "hardware_version": "2.0",
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "40-AE-30-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1733422805",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C210",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.4.3 Build 241010 Rel.33858n",
+ "hardware_version": "2.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "40-AE-30-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ },
+ "protocol_version": 1
}
},
"getAlertConfig": {
@@ -263,15 +267,22 @@
"getClockStatus": {
"system": {
"clock_status": {
- "local_time": "2024-11-01 13:58:50",
- "seconds_from_1970": 1730469530
+ "local_time": "2024-12-15 11:28:40",
+ "seconds_from_1970": 1734262120
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {
+ "status": 0
}
}
},
"getConnectionType": {
"link_type": "wifi",
"rssi": "3",
- "rssiValue": -57,
+ "rssiValue": -61,
"ssid": "I01BU0tFRF9TU0lEIw=="
},
"getDetectionConfig": {
@@ -318,7 +329,7 @@
"getFirmwareAutoUpgradeConfig": {
"auto_upgrade": {
"common": {
- "enabled": "on",
+ "enabled": "off",
"random_range": "120",
"time": "03:00"
}
@@ -335,8 +346,8 @@
"getLastAlarmInfo": {
"system": {
"last_alarm_info": {
- "last_alarm_time": "0",
- "last_alarm_type": ""
+ "last_alarm_time": "1733422805",
+ "last_alarm_type": "motion"
}
}
},
@@ -958,5 +969,35 @@
}
}
}
+ },
+ "scanApList": {
+ "onboarding": {
+ "scan": {
+ "ap_list": [
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "wpa3_supported": "false"
+ }
+ }
}
}
diff --git a/tests/fixtures/smartcam/C225(US)_2.0_1.0.11.json b/tests/fixtures/smartcam/C225(US)_2.0_1.0.11.json
new file mode 100644
index 00000000..24227c41
--- /dev/null
+++ b/tests/fixtures/smartcam/C225(US)_2.0_1.0.11.json
@@ -0,0 +1,1283 @@
+{
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1734729039",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "normal"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C225",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.0.11 Build 240826 Rel.62730n",
+ "hardware_version": "2.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-42-A1-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ },
+ "obd_src": "tplink"
+ }
+ },
+ "getAlertConfig": {
+ "msg_alarm": {
+ "capability": {
+ "alarm_duration_support": "1",
+ "alarm_volume_support": "1",
+ "alert_event_type_support": "1",
+ "usr_def_audio_alarm_max_num": "15",
+ "usr_def_audio_alarm_support": "1",
+ "usr_def_audio_max_duration": "15",
+ "usr_def_audio_type": "0",
+ "usr_def_start_file_id": "8195"
+ },
+ "chn1_msg_alarm_info": {
+ "alarm_duration": "0",
+ "alarm_mode": [
+ "light",
+ "sound"
+ ],
+ "alarm_type": "0",
+ "alarm_volume": "high",
+ "enabled": "off",
+ "light_alarm_enabled": "on",
+ "light_type": "1",
+ "sound_alarm_enabled": "on"
+ },
+ "usr_def_audio": []
+ }
+ },
+ "getAlertPlan": {
+ "msg_alarm_plan": {
+ "chn1_msg_alarm_plan": {
+ "alarm_plan_1": "0000-0000,127",
+ "enabled": "off"
+ }
+ }
+ },
+ "getAlertTypeList": {
+ "msg_alarm": {
+ "alert_type": {
+ "alert_type_list": [
+ "Siren",
+ "Emergency",
+ "Red Alert"
+ ]
+ }
+ }
+ },
+ "getAppComponentList": {
+ "app_component": {
+ "app_component_list": [
+ {
+ "name": "sdCard",
+ "version": 1
+ },
+ {
+ "name": "timezone",
+ "version": 1
+ },
+ {
+ "name": "system",
+ "version": 3
+ },
+ {
+ "name": "led",
+ "version": 1
+ },
+ {
+ "name": "playback",
+ "version": 6
+ },
+ {
+ "name": "detection",
+ "version": 3
+ },
+ {
+ "name": "alert",
+ "version": 2
+ },
+ {
+ "name": "firmware",
+ "version": 2
+ },
+ {
+ "name": "account",
+ "version": 2
+ },
+ {
+ "name": "quickSetup",
+ "version": 1
+ },
+ {
+ "name": "ptz",
+ "version": 1
+ },
+ {
+ "name": "video",
+ "version": 3
+ },
+ {
+ "name": "lensMask",
+ "version": 2
+ },
+ {
+ "name": "lightFrequency",
+ "version": 1
+ },
+ {
+ "name": "dayNightMode",
+ "version": 1
+ },
+ {
+ "name": "osd",
+ "version": 2
+ },
+ {
+ "name": "record",
+ "version": 1
+ },
+ {
+ "name": "videoRotation",
+ "version": 1
+ },
+ {
+ "name": "audio",
+ "version": 3
+ },
+ {
+ "name": "diagnose",
+ "version": 1
+ },
+ {
+ "name": "msgPush",
+ "version": 3
+ },
+ {
+ "name": "linecrossingDetection",
+ "version": 2
+ },
+ {
+ "name": "deviceShare",
+ "version": 1
+ },
+ {
+ "name": "tamperDetection",
+ "version": 1
+ },
+ {
+ "name": "tapoCare",
+ "version": 1
+ },
+ {
+ "name": "targetTrack",
+ "version": 1
+ },
+ {
+ "name": "blockZone",
+ "version": 1
+ },
+ {
+ "name": "babyCryDetection",
+ "version": 1
+ },
+ {
+ "name": "personDetection",
+ "version": 2
+ },
+ {
+ "name": "needSubscriptionServiceList",
+ "version": 1
+ },
+ {
+ "name": "patrol",
+ "version": 1
+ },
+ {
+ "name": "panoramicView",
+ "version": 1
+ },
+ {
+ "name": "vehicleDetection",
+ "version": 1
+ },
+ {
+ "name": "petDetection",
+ "version": 1
+ },
+ {
+ "name": "meowDetection",
+ "version": 1
+ },
+ {
+ "name": "barkDetection",
+ "version": 1
+ },
+ {
+ "name": "glassDetection",
+ "version": 1
+ },
+ {
+ "name": "alarmDetection",
+ "version": 1
+ },
+ {
+ "name": "infLamp",
+ "version": 1
+ },
+ {
+ "name": "markerBox",
+ "version": 1
+ },
+ {
+ "name": "nvmp",
+ "version": 1
+ },
+ {
+ "name": "iotCloud",
+ "version": 1
+ },
+ {
+ "name": "hdr",
+ "version": 1
+ },
+ {
+ "name": "homekit",
+ "version": 1
+ },
+ {
+ "name": "upnpc",
+ "version": 2
+ },
+ {
+ "name": "bleOnboarding",
+ "version": 2
+ },
+ {
+ "name": "recordDownload",
+ "version": 1
+ },
+ {
+ "name": "smartTrack",
+ "version": 1
+ },
+ {
+ "name": "encryption",
+ "version": 3
+ },
+ {
+ "name": "staticIp",
+ "version": 2
+ },
+ {
+ "name": "detectionRegion",
+ "version": 2
+ }
+ ]
+ }
+ },
+ "getAudioConfig": {
+ "audio_config": {
+ "microphone": {
+ "bitrate": "64",
+ "channels": "1",
+ "echo_cancelling": "off",
+ "encode_type": "G711alaw",
+ "input_device_type": "MicIn",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "80"
+ },
+ "speaker": {
+ "mute": "off",
+ "output_device_type": "SpeakerOut",
+ "volume": "80"
+ }
+ }
+ },
+ "getBCDConfig": {
+ "sound_detection": {
+ "bcd": {
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getBarkDetectionConfig": {
+ "bark_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "50"
+ }
+ }
+ },
+ "getCircularRecordingConfig": {
+ "harddisk_manage": {
+ "harddisk": {
+ "loop": "on"
+ }
+ }
+ },
+ "getClockStatus": {
+ "system": {
+ "clock_status": {
+ "local_time": "2024-12-20 15:15:46",
+ "seconds_from_1970": 1734736546
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {
+ "status": 0
+ }
+ }
+ },
+ "getConnectionType": {
+ "link_type": "wifi",
+ "rssi": "4",
+ "rssiValue": -9,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ "getDetectionConfig": {
+ "motion_detection": {
+ "motion_det": {
+ "digital_sensitivity": "60",
+ "enabled": "off",
+ "non_vehicle_enabled": "off",
+ "people_enabled": "off",
+ "sensitivity": "medium",
+ "vehicle_enabled": "off"
+ }
+ }
+ },
+ "getDeviceInfo": {
+ "device_info": {
+ "basic_info": {
+ "avatar": "camera c225",
+ "barcode": "",
+ "dev_id": "0000000000000000000000000000000000000000",
+ "device_alias": "#MASKED_NAME#",
+ "device_info": "C225 2.0 IPC",
+ "device_model": "C225",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "features": 3,
+ "ffs": false,
+ "has_set_location_info": 0,
+ "hw_desc": "00000000000000000000000000000000",
+ "hw_id": "00000000000000000000000000000000",
+ "hw_version": "2.0",
+ "is_cal": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "A8-42-A1-00-00-00",
+ "manufacturer_name": "TP-LINK",
+ "mobile_access": "0",
+ "no_rtsp_constrain": 1,
+ "oem_id": "00000000000000000000000000000000",
+ "region": "US",
+ "sw_version": "1.0.11 Build 240826 Rel.62730n"
+ }
+ }
+ },
+ "getFirmwareAutoUpgradeConfig": {
+ "auto_upgrade": {
+ "common": {
+ "enabled": "on",
+ "random_range": "120",
+ "time": "03:00"
+ }
+ }
+ },
+ "getFirmwareUpdateStatus": {
+ "cloud_config": {
+ "upgrade_status": {
+ "lastUpgradingSuccess": true,
+ "state": "normal"
+ }
+ }
+ },
+ "getGlassDetectionConfig": {
+ "glass_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "50"
+ }
+ }
+ },
+ "getLastAlarmInfo": {
+ "system": {
+ "last_alarm_info": {
+ "last_alarm_time": "1734729039",
+ "last_alarm_type": "motion"
+ }
+ }
+ },
+ "getLdc": {
+ "image": {
+ "common": {
+ "area_compensation": "default",
+ "auto_exp_antiflicker": "off",
+ "auto_exp_gain_max": "0",
+ "backlight": "off",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "eis": "off",
+ "exp_gain": "100",
+ "exp_level": "0",
+ "exp_type": "auto",
+ "focus_limited": "10",
+ "focus_type": "manual",
+ "high_light_compensation": "off",
+ "inf_delay": "5",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "4",
+ "inf_sensitivity_day2night": "1400",
+ "inf_sensitivity_night2day": "9100",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "iris_level": "160",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "auto_ir",
+ "smartir_level": "0",
+ "smartwtl": "auto_wtl",
+ "smartwtl_digital_level": "50",
+ "smartwtl_level": "3",
+ "style": "standard",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off",
+ "wtl_delay": "5",
+ "wtl_end_time": "21600",
+ "wtl_sensitivity": "4",
+ "wtl_sensitivity_day2night": "1400",
+ "wtl_sensitivity_night2day": "9100",
+ "wtl_start_time": "64800",
+ "wtl_type": "auto"
+ },
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "30",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "5",
+ "wtl_manual_start_flag": "off"
+ }
+ }
+ },
+ "getLedStatus": {
+ "led": {
+ "config": {
+ "enabled": "on"
+ }
+ }
+ },
+ "getLensMaskConfig": {
+ "lens_mask": {
+ "lens_mask_info": {
+ "enabled": "off"
+ }
+ }
+ },
+ "getLightFrequencyInfo": {
+ "image": {
+ "common": {
+ "area_compensation": "default",
+ "auto_exp_antiflicker": "off",
+ "auto_exp_gain_max": "0",
+ "backlight": "off",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "eis": "off",
+ "exp_gain": "100",
+ "exp_level": "0",
+ "exp_type": "auto",
+ "focus_limited": "10",
+ "focus_type": "manual",
+ "high_light_compensation": "off",
+ "inf_delay": "5",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "4",
+ "inf_sensitivity_day2night": "1400",
+ "inf_sensitivity_night2day": "9100",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "iris_level": "160",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "auto_ir",
+ "smartir_level": "0",
+ "smartwtl": "auto_wtl",
+ "smartwtl_digital_level": "50",
+ "smartwtl_level": "3",
+ "style": "standard",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off",
+ "wtl_delay": "5",
+ "wtl_end_time": "21600",
+ "wtl_sensitivity": "4",
+ "wtl_sensitivity_day2night": "1400",
+ "wtl_sensitivity_night2day": "9100",
+ "wtl_start_time": "64800",
+ "wtl_type": "auto"
+ }
+ }
+ },
+ "getMediaEncrypt": {
+ "cet": {
+ "media_encrypt": {
+ "enabled": "on"
+ }
+ }
+ },
+ "getMeowDetectionConfig": {
+ "meow_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "50"
+ }
+ }
+ },
+ "getMsgPushConfig": {
+ "msg_push": {
+ "chn1_msg_push_info": {
+ "notification_enabled": "on",
+ "rich_notification_enabled": "off"
+ }
+ }
+ },
+ "getNightVisionCapability": {
+ "image_capability": {
+ "supplement_lamp": {
+ "night_vision_mode_range": [
+ "inf_night_vision"
+ ],
+ "supplement_lamp_type": [
+ "infrared_lamp"
+ ]
+ }
+ }
+ },
+ "getNightVisionModeConfig": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "30",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "5",
+ "wtl_manual_start_flag": "off"
+ }
+ }
+ },
+ "getPersonDetectionConfig": {
+ "people_detection": {
+ "detection": {
+ "enabled": "on",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getPetDetectionConfig": {
+ "pet_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getPresetConfig": {
+ "preset": {
+ "preset": {
+ "id": [],
+ "name": [],
+ "position_pan": [],
+ "position_tilt": [],
+ "position_zoom": [],
+ "read_only": []
+ }
+ }
+ },
+ "getRecordPlan": {
+ "record_plan": {
+ "chn1_channel": {
+ "enabled": "on",
+ "friday": "[\"0000-2400:2\"]",
+ "monday": "[\"0000-2400:2\"]",
+ "saturday": "[\"0000-2400:2\"]",
+ "sunday": "[\"0000-2400:2\"]",
+ "thursday": "[\"0000-2400:2\"]",
+ "tuesday": "[\"0000-2400:2\"]",
+ "wednesday": "[\"0000-2400:2\"]"
+ }
+ }
+ },
+ "getRotationStatus": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "30",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "5",
+ "wtl_manual_start_flag": "off"
+ }
+ }
+ },
+ "getSdCardStatus": {
+ "harddisk_manage": {
+ "hd_info": [
+ {
+ "hd_info_1": {
+ "crossline_free_space": "0B",
+ "crossline_free_space_accurate": "0B",
+ "crossline_total_space": "0B",
+ "crossline_total_space_accurate": "0B",
+ "detect_status": "normal",
+ "disk_name": "1",
+ "free_space": "98.6GB",
+ "free_space_accurate": "105903970616B",
+ "loop_record_status": "0",
+ "msg_push_free_space": "0B",
+ "msg_push_free_space_accurate": "0B",
+ "msg_push_total_space": "0B",
+ "msg_push_total_space_accurate": "0B",
+ "percent": "100",
+ "picture_free_space": "0B",
+ "picture_free_space_accurate": "0B",
+ "picture_total_space": "0B",
+ "picture_total_space_accurate": "0B",
+ "record_duration": "0",
+ "record_free_duration": "0",
+ "record_start_time": "1729454840",
+ "rw_attr": "rw",
+ "status": "normal",
+ "total_space": "118.8GB",
+ "total_space_accurate": "127531646976B",
+ "type": "local",
+ "video_free_space": "98.6GB",
+ "video_free_space_accurate": "105903970616B",
+ "video_total_space": "114.0GB",
+ "video_total_space_accurate": "122406567936B",
+ "write_protect": "0"
+ }
+ }
+ ]
+ }
+ },
+ "getTamperDetectionConfig": {
+ "tamper_detection": {
+ "tamper_det": {
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getTargetTrackConfig": {
+ "target_track": {
+ "target_track_info": {
+ "back_time": "30",
+ "enabled": "off",
+ "track_mode": "pantilt",
+ "track_time": "0"
+ }
+ }
+ },
+ "getTimezone": {
+ "system": {
+ "basic": {
+ "timezone": "UTC-08:00",
+ "timing_mode": "ntp",
+ "zone_id": "America/Los_Angeles"
+ }
+ }
+ },
+ "getVehicleDetectionConfig": {
+ "vehicle_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getVideoCapability": {
+ "video_capability": {
+ "main": {
+ "bitrate_types": [
+ "cbr",
+ "vbr"
+ ],
+ "bitrates": [
+ "256",
+ "512",
+ "1024",
+ "1536",
+ "2048"
+ ],
+ "change_fps_support": "1",
+ "encode_types": [
+ "H264",
+ "H265"
+ ],
+ "frame_rates": [
+ "65551",
+ "65556",
+ "65561",
+ "65566"
+ ],
+ "hdrs": [
+ "0",
+ "1"
+ ],
+ "minor_stream_support": "1",
+ "qualitys": [
+ "1",
+ "3",
+ "5"
+ ],
+ "resolutions": [
+ "2688*1520",
+ "1920*1080"
+ ]
+ }
+ }
+ },
+ "getVideoQualities": {
+ "video": {
+ "main": {
+ "bitrate": "2048",
+ "bitrate_type": "vbr",
+ "default_bitrate": "2048",
+ "encode_type": "H264",
+ "frame_rate": "65551",
+ "hdr": "0",
+ "name": "VideoEncoder_1",
+ "quality": "3",
+ "resolution": "2688*1520",
+ "smart_codec": "off"
+ }
+ }
+ },
+ "getWhitelampConfig": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "30",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "5",
+ "wtl_manual_start_flag": "off"
+ }
+ }
+ },
+ "getWhitelampStatus": {
+ "rest_time": 0,
+ "status": 0
+ },
+ "get_audio_capability": {
+ "get": {
+ "audio_capability": {
+ "device_microphone": {
+ "aec": "1",
+ "channels": "1",
+ "echo_cancelling": "0",
+ "encode_type": [
+ "G711alaw"
+ ],
+ "half_duplex": "1",
+ "mute": "1",
+ "noise_cancelling": "1",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ },
+ "device_speaker": {
+ "channels": "1",
+ "decode_type": [
+ "G711alaw"
+ ],
+ "mute": "0",
+ "output_device_type": "0",
+ "sampling_rate": [
+ "8"
+ ],
+ "system_volume": "80",
+ "volume": "1"
+ }
+ }
+ }
+ },
+ "get_audio_config": {
+ "get": {
+ "audio_config": {
+ "microphone": {
+ "bitrate": "64",
+ "channels": "1",
+ "echo_cancelling": "off",
+ "encode_type": "G711alaw",
+ "input_device_type": "MicIn",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "80"
+ },
+ "speaker": {
+ "mute": "off",
+ "output_device_type": "SpeakerOut",
+ "volume": "80"
+ }
+ }
+ }
+ },
+ "get_cet": {
+ "get": {
+ "cet": {
+ "vhttpd": {
+ "port": "8800"
+ }
+ }
+ }
+ },
+ "get_function": {
+ "get": {
+ "function": {
+ "module_spec": {
+ "ae_weighting_table_resolution": "5*5",
+ "ai_enhance_capability": "1",
+ "ai_enhance_range": [
+ "traditional_enhance"
+ ],
+ "ai_firmware_upgrade": "0",
+ "alarm_out_num": "0",
+ "app_version": "1.0.0",
+ "audio": [
+ "speaker",
+ "microphone"
+ ],
+ "auth_encrypt": "1",
+ "auto_ip_configurable": "1",
+ "backlight_coexistence": "1",
+ "change_password": "1",
+ "client_info": "1",
+ "cloud_storage_version": "1.0",
+ "config_recovery": [
+ "audio_config",
+ "OSD",
+ "image",
+ "video"
+ ],
+ "custom_area_compensation": "1",
+ "custom_auto_mode_exposure_level": "1",
+ "daynight_subdivision": "1",
+ "device_share": [
+ "preview",
+ "playback",
+ "voice",
+ "cloud_storage",
+ "motor"
+ ],
+ "download": [
+ "video"
+ ],
+ "events": [
+ "motion",
+ "tamper"
+ ],
+ "force_iframe_support": "1",
+ "http_system_state_audio_support": "1",
+ "image_capability": "1",
+ "image_list": [
+ "supplement_lamp",
+ "expose"
+ ],
+ "ir_led_pwm_control": "1",
+ "led": "1",
+ "lens_mask": "1",
+ "linkage_capability": "1",
+ "local_storage": "1",
+ "media_encrypt": "1",
+ "motor": "0",
+ "msg_alarm_list": [
+ "sound",
+ "light"
+ ],
+ "msg_push": "1",
+ "multi_user": "0",
+ "multicast": "0",
+ "network": [
+ "wifi",
+ "ethernet"
+ ],
+ "osd_capability": "1",
+ "ota_upgrade": "1",
+ "p2p_support_versions": [
+ "2.0"
+ ],
+ "personalized_audio_alarm": "0",
+ "playback": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "playback_scale": "1",
+ "preview": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "ptz": "1",
+ "record_max_slot_cnt": "6",
+ "record_type": [
+ "timing",
+ "motion"
+ ],
+ "relay_support_versions": [
+ "2.0"
+ ],
+ "remote_upgrade": "1",
+ "reonboarding": "0",
+ "smart_codec": "0",
+ "smart_detection": "1",
+ "ssl_cer_version": "1.0",
+ "storage_api_version": "2.2",
+ "storage_capability": "1",
+ "stream_max_sessions": "10",
+ "streaming_support_versions": [
+ "2.0"
+ ],
+ "tapo_care_version": "1.0.0",
+ "target_track": "1",
+ "timing_reboot": "1",
+ "verification_change_password": "1",
+ "video_codec": [
+ "h264",
+ "h265"
+ ],
+ "video_detection_digital_sensitivity": "1",
+ "wide_range_inf_sensitivity": "1",
+ "wifi_connection_info": "1",
+ "wireless_hotspot": "0"
+ }
+ }
+ }
+ },
+ "scanApList": {
+ "onboarding": {
+ "scan": {
+ "ap_list": [
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 4,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 5,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "wpa3_supported": "true"
+ }
+ }
+ }
+}
diff --git a/tests/fixtures/smartcam/C325WB(EU)_1.0_1.1.17.json b/tests/fixtures/smartcam/C325WB(EU)_1.0_1.1.17.json
new file mode 100644
index 00000000..b04cbd06
--- /dev/null
+++ b/tests/fixtures/smartcam/C325WB(EU)_1.0_1.1.17.json
@@ -0,0 +1,1065 @@
+{
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1734490369",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "normal"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C325WB",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.1.17 Build 240529 Rel.57938n",
+ "hardware_version": "1.0",
+ "ip": "127.0.0.123",
+ "isResetWiFi": false,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
+ }
+ },
+ "getAlertConfig": {
+ "msg_alarm": {
+ "capability": {
+ "alarm_duration_support": "1",
+ "alarm_volume_support": "1",
+ "alert_event_type_support": "1",
+ "usr_def_audio_alarm_max_num": "2",
+ "usr_def_audio_alarm_support": "1",
+ "usr_def_audio_max_duration": "15",
+ "usr_def_audio_type": "0",
+ "usr_def_start_file_id": "8195"
+ },
+ "chn1_msg_alarm_info": {
+ "alarm_duration": "0",
+ "alarm_mode": [
+ "sound",
+ "light"
+ ],
+ "alarm_type": "0",
+ "alarm_volume": "high",
+ "enabled": "off",
+ "light_alarm_enabled": "on",
+ "light_type": "1",
+ "sound_alarm_enabled": "on"
+ },
+ "usr_def_audio": []
+ }
+ },
+ "getAlertPlan": {
+ "msg_alarm_plan": {
+ "chn1_msg_alarm_plan": {
+ "alarm_plan_1": "0000-0000,127",
+ "enabled": "off"
+ }
+ }
+ },
+ "getAlertTypeList": {
+ "msg_alarm": {
+ "alert_type": {
+ "alert_type_list": [
+ "Siren",
+ "Emergency",
+ "Red Alert"
+ ]
+ }
+ }
+ },
+ "getAppComponentList": {
+ "app_component": {
+ "app_component_list": [
+ {
+ "name": "sdCard",
+ "version": 1
+ },
+ {
+ "name": "timezone",
+ "version": 1
+ },
+ {
+ "name": "system",
+ "version": 4
+ },
+ {
+ "name": "led",
+ "version": 1
+ },
+ {
+ "name": "playback",
+ "version": 6
+ },
+ {
+ "name": "detection",
+ "version": 3
+ },
+ {
+ "name": "alert",
+ "version": 2
+ },
+ {
+ "name": "firmware",
+ "version": 2
+ },
+ {
+ "name": "account",
+ "version": 1
+ },
+ {
+ "name": "quickSetup",
+ "version": 1
+ },
+ {
+ "name": "video",
+ "version": 3
+ },
+ {
+ "name": "lensMask",
+ "version": 2
+ },
+ {
+ "name": "lightFrequency",
+ "version": 1
+ },
+ {
+ "name": "osd",
+ "version": 2
+ },
+ {
+ "name": "record",
+ "version": 1
+ },
+ {
+ "name": "videoRotation",
+ "version": 1
+ },
+ {
+ "name": "audio",
+ "version": 3
+ },
+ {
+ "name": "diagnose",
+ "version": 1
+ },
+ {
+ "name": "msgPush",
+ "version": 3
+ },
+ {
+ "name": "linecrossingDetection",
+ "version": 2
+ },
+ {
+ "name": "deviceShare",
+ "version": 1
+ },
+ {
+ "name": "tamperDetection",
+ "version": 1
+ },
+ {
+ "name": "darkLightNightVision",
+ "version": 3
+ },
+ {
+ "name": "tapoCare",
+ "version": 1
+ },
+ {
+ "name": "blockZone",
+ "version": 1
+ },
+ {
+ "name": "personDetection",
+ "version": 2
+ },
+ {
+ "name": "needSubscriptionServiceList",
+ "version": 1
+ },
+ {
+ "name": "vehicleDetection",
+ "version": 1
+ },
+ {
+ "name": "petDetection",
+ "version": 1
+ },
+ {
+ "name": "whiteLamp",
+ "version": 1
+ },
+ {
+ "name": "markerBox",
+ "version": 1
+ },
+ {
+ "name": "nvmp",
+ "version": 1
+ },
+ {
+ "name": "detectionRegion",
+ "version": 2
+ },
+ {
+ "name": "recordDownload",
+ "version": 1
+ },
+ {
+ "name": "iotCloud",
+ "version": 1
+ },
+ {
+ "name": "snapshot",
+ "version": 2
+ },
+ {
+ "name": "upnpc",
+ "version": 2
+ }
+ ]
+ }
+ },
+ "getAudioConfig": {
+ "audio_config": {
+ "microphone": {
+ "bitrate": "64",
+ "channels": "1",
+ "echo_cancelling": "off",
+ "encode_type": "G711alaw",
+ "input_device_type": "MicIn",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "0"
+ },
+ "speaker": {
+ "mute": "off",
+ "output_device_type": "SpeakerOut",
+ "volume": "100"
+ }
+ }
+ },
+ "getCircularRecordingConfig": {
+ "harddisk_manage": {
+ "harddisk": {
+ "loop": "on"
+ }
+ }
+ },
+ "getClockStatus": {
+ "system": {
+ "clock_status": {
+ "local_time": "2024-12-18 12:59:13",
+ "seconds_from_1970": 1734490753
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {
+ "status": 0
+ }
+ }
+ },
+ "getConnectionType": {
+ "link_type": "wifi",
+ "rssi": "2",
+ "rssiValue": -63,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ "getDetectionConfig": {
+ "motion_detection": {
+ "motion_det": {
+ "digital_sensitivity": "60",
+ "enabled": "on",
+ "non_vehicle_enabled": "off",
+ "people_enabled": "off",
+ "sensitivity": "medium",
+ "vehicle_enabled": "off"
+ }
+ }
+ },
+ "getDeviceInfo": {
+ "device_info": {
+ "basic_info": {
+ "avatar": "camera c100",
+ "barcode": "",
+ "dev_id": "0000000000000000000000000000000000000000",
+ "device_alias": "#MASKED_NAME#",
+ "device_info": "C325WB 1.0 IPC",
+ "device_model": "C325WB",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "features": 3,
+ "ffs": false,
+ "has_set_location_info": 1,
+ "hw_desc": "00000000000000000000000000000000",
+ "hw_id": "00000000000000000000000000000000",
+ "hw_version": "1.0",
+ "is_cal": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "F0-A7-31-00-00-00",
+ "manufacturer_name": "TP-LINK",
+ "mobile_access": "0",
+ "oem_id": "00000000000000000000000000000000",
+ "region": "EU",
+ "sw_version": "1.1.17 Build 240529 Rel.57938n"
+ }
+ }
+ },
+ "getFirmwareAutoUpgradeConfig": {
+ "auto_upgrade": {
+ "common": {
+ "enabled": "on",
+ "random_range": "120",
+ "time": "03:00"
+ }
+ }
+ },
+ "getFirmwareUpdateStatus": {
+ "cloud_config": {
+ "upgrade_status": {
+ "lastUpgradingSuccess": true,
+ "state": "normal"
+ }
+ }
+ },
+ "getLastAlarmInfo": {
+ "system": {
+ "last_alarm_info": {
+ "last_alarm_time": "1734490369",
+ "last_alarm_type": "motion"
+ }
+ }
+ },
+ "getLdc": {
+ "image": {
+ "common": {
+ "area_compensation": "default",
+ "auto_exp_antiflicker": "off",
+ "auto_exp_gain_max": "0",
+ "backlight": "off",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "eis": "off",
+ "exp_gain": "0",
+ "exp_level": "0",
+ "exp_type": "auto",
+ "focus_limited": "10",
+ "focus_type": "manual",
+ "high_light_compensation": "off",
+ "inf_delay": "5",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "4",
+ "inf_sensitivity_day2night": "1400",
+ "inf_sensitivity_night2day": "9100",
+ "inf_start_time": "64800",
+ "inf_type": "off",
+ "iris_level": "160",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "auto_ir",
+ "smartir_level": "0",
+ "smartwtl": "auto_wtl",
+ "smartwtl_digital_level": "100",
+ "smartwtl_level": "5",
+ "style": "standard",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off",
+ "wtl_delay": "5",
+ "wtl_end_time": "21600",
+ "wtl_sensitivity": "4",
+ "wtl_sensitivity_day2night": "1400",
+ "wtl_sensitivity_night2day": "9100",
+ "wtl_start_time": "64800",
+ "wtl_type": "auto"
+ },
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "5",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "wtl_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "30"
+ }
+ }
+ },
+ "getLedStatus": {
+ "led": {
+ "config": {
+ "enabled": "on"
+ }
+ }
+ },
+ "getLensMaskConfig": {
+ "lens_mask": {
+ "lens_mask_info": {
+ "enabled": "off"
+ }
+ }
+ },
+ "getLightFrequencyInfo": {
+ "image": {
+ "common": {
+ "area_compensation": "default",
+ "auto_exp_antiflicker": "off",
+ "auto_exp_gain_max": "0",
+ "backlight": "off",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "eis": "off",
+ "exp_gain": "0",
+ "exp_level": "0",
+ "exp_type": "auto",
+ "focus_limited": "10",
+ "focus_type": "manual",
+ "high_light_compensation": "off",
+ "inf_delay": "5",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "4",
+ "inf_sensitivity_day2night": "1400",
+ "inf_sensitivity_night2day": "9100",
+ "inf_start_time": "64800",
+ "inf_type": "off",
+ "iris_level": "160",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "auto_ir",
+ "smartir_level": "0",
+ "smartwtl": "auto_wtl",
+ "smartwtl_digital_level": "100",
+ "smartwtl_level": "5",
+ "style": "standard",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off",
+ "wtl_delay": "5",
+ "wtl_end_time": "21600",
+ "wtl_sensitivity": "4",
+ "wtl_sensitivity_day2night": "1400",
+ "wtl_sensitivity_night2day": "9100",
+ "wtl_start_time": "64800",
+ "wtl_type": "auto"
+ }
+ }
+ },
+ "getMediaEncrypt": {
+ "cet": {
+ "media_encrypt": {
+ "enabled": "on"
+ }
+ }
+ },
+ "getMsgPushConfig": {
+ "msg_push": {
+ "chn1_msg_push_info": {
+ "notification_enabled": "off",
+ "rich_notification_enabled": "off"
+ }
+ }
+ },
+ "getNightVisionCapability": {
+ "image_capability": {
+ "supplement_lamp": {
+ "night_vision_mode_range": [
+ "wtl_night_vision",
+ "md_night_vision",
+ "shed_night_vision"
+ ],
+ "supplement_lamp_type": [
+ "infrared_lamp",
+ "white_lamp"
+ ]
+ }
+ }
+ },
+ "getNightVisionModeConfig": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "5",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "wtl_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "30"
+ }
+ }
+ },
+ "getPersonDetectionConfig": {
+ "people_detection": {
+ "detection": {
+ "enabled": "on",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getPetDetectionConfig": {
+ "pet_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getRecordPlan": {
+ "record_plan": {
+ "chn1_channel": {
+ "enabled": "on",
+ "friday": "[\"0000-2400:2\"]",
+ "monday": "[\"0000-2400:2\"]",
+ "saturday": "[\"0000-2400:2\"]",
+ "sunday": "[\"0000-2400:2\"]",
+ "thursday": "[\"0000-2400:2\"]",
+ "tuesday": "[\"0000-2400:2\"]",
+ "wednesday": "[\"0000-2400:2\"]"
+ }
+ }
+ },
+ "getRotationStatus": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "5",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "wtl_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "30"
+ }
+ }
+ },
+ "getSdCardStatus": {
+ "harddisk_manage": {
+ "hd_info": [
+ {
+ "hd_info_1": {
+ "crossline_free_space": "0B",
+ "crossline_free_space_accurate": "0B",
+ "crossline_total_space": "0B",
+ "crossline_total_space_accurate": "0B",
+ "detect_status": "normal",
+ "disk_name": "1",
+ "free_space": "0B",
+ "free_space_accurate": "0B",
+ "loop_record_status": "1",
+ "msg_push_free_space": "0B",
+ "msg_push_free_space_accurate": "0B",
+ "msg_push_total_space": "0B",
+ "msg_push_total_space_accurate": "0B",
+ "percent": "0",
+ "picture_free_space": "0B",
+ "picture_free_space_accurate": "0B",
+ "picture_total_space": "0B",
+ "picture_total_space_accurate": "0B",
+ "record_duration": "0",
+ "record_free_duration": "0",
+ "record_start_time": "1733281333",
+ "rw_attr": "rw",
+ "status": "normal",
+ "total_space": "118.8GB",
+ "total_space_accurate": "127565725696B",
+ "type": "local",
+ "video_free_space": "0B",
+ "video_free_space_accurate": "0B",
+ "video_total_space": "114.0GB",
+ "video_total_space_accurate": "122406567936B",
+ "write_protect": "0"
+ }
+ }
+ ]
+ }
+ },
+ "getTamperDetectionConfig": {
+ "tamper_detection": {
+ "tamper_det": {
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getTimezone": {
+ "system": {
+ "basic": {
+ "timezone": "UTC+10:00",
+ "timing_mode": "ntp",
+ "zone_id": "Australia/Brisbane"
+ }
+ }
+ },
+ "getVehicleDetectionConfig": {
+ "vehicle_detection": {
+ "detection": {
+ "enabled": "off",
+ "sensitivity": "60"
+ }
+ }
+ },
+ "getVideoCapability": {
+ "video_capability": {
+ "main": {
+ "bitrate_types": [
+ "cbr",
+ "vbr"
+ ],
+ "bitrates": [
+ "256",
+ "512",
+ "1024",
+ "1536",
+ "3072"
+ ],
+ "encode_types": [
+ "H264",
+ "H265"
+ ],
+ "frame_rates": [
+ "65537",
+ "65546",
+ "65551",
+ "65556"
+ ],
+ "hdrs": [
+ "0",
+ "1"
+ ],
+ "minor_stream_support": "1",
+ "qualitys": [
+ "1",
+ "3",
+ "5"
+ ],
+ "resolutions": [
+ "2688*1520",
+ "1920*1080",
+ "1280*720"
+ ]
+ }
+ }
+ },
+ "getVideoQualities": {
+ "video": {
+ "main": {
+ "bitrate": "1536",
+ "bitrate_type": "vbr",
+ "default_bitrate": "3072",
+ "encode_type": "H264",
+ "frame_rate": "65556",
+ "hdr": "0",
+ "name": "VideoEncoder_1",
+ "quality": "3",
+ "resolution": "2688*1520",
+ "smart_codec": "off"
+ }
+ }
+ },
+ "getWhitelampConfig": {
+ "image": {
+ "switch": {
+ "best_view_distance": "0",
+ "clear_licence_plate_mode": "off",
+ "flip_type": "off",
+ "full_color_min_keep_time": "5",
+ "full_color_people_enhance": "off",
+ "image_scene_mode": "normal",
+ "image_scene_mode_autoday": "normal",
+ "image_scene_mode_autonight": "normal",
+ "image_scene_mode_common": "normal",
+ "image_scene_mode_shedday": "normal",
+ "image_scene_mode_shednight": "normal",
+ "ldc": "off",
+ "night_vision_mode": "wtl_night_vision",
+ "overexposure_people_suppression": "off",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_force_time": "300",
+ "wtl_intensity_level": "30"
+ }
+ }
+ },
+ "getWhitelampStatus": {
+ "rest_time": 0,
+ "status": 0
+ },
+ "get_audio_capability": {
+ "get": {
+ "audio_capability": {
+ "device_microphone": {
+ "aec": "1",
+ "channels": "1",
+ "echo_cancelling": "0",
+ "encode_type": [
+ "G711alaw"
+ ],
+ "half_duplex": "1",
+ "mute": "1",
+ "noise_cancelling": "1",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ },
+ "device_speaker": {
+ "channels": "1",
+ "decode_type": [
+ "G711alaw",
+ "G711ulaw"
+ ],
+ "mute": "0",
+ "output_device_type": "0",
+ "sampling_rate": [
+ "8",
+ "16"
+ ],
+ "system_volume": "95",
+ "volume": "1"
+ }
+ }
+ }
+ },
+ "get_audio_config": {
+ "get": {
+ "audio_config": {
+ "microphone": {
+ "bitrate": "64",
+ "channels": "1",
+ "echo_cancelling": "off",
+ "encode_type": "G711alaw",
+ "input_device_type": "MicIn",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "0"
+ },
+ "speaker": {
+ "mute": "off",
+ "output_device_type": "SpeakerOut",
+ "volume": "100"
+ }
+ }
+ }
+ },
+ "get_cet": {
+ "get": {
+ "cet": {
+ "vhttpd": {
+ "port": "8800"
+ }
+ }
+ }
+ },
+ "get_function": {
+ "get": {
+ "function": {
+ "module_spec": {
+ "ae_weighting_table_resolution": "5*5",
+ "ai_enhance_capability": "1",
+ "ai_enhance_range": [
+ "traditional_enhance"
+ ],
+ "alarm_out_num": "0",
+ "app_version": "1.0.0",
+ "audio": [
+ "speaker",
+ "microphone"
+ ],
+ "audio_alarm_clock": "1",
+ "audio_lib": "1",
+ "auth_encrypt": "1",
+ "auto_ip_configurable": "1",
+ "backlight_coexistence": "1",
+ "change_password": "1",
+ "client_info": "1",
+ "cloud_storage_version": "1.0",
+ "config_recovery": [
+ "audio_config",
+ "image",
+ "OSD",
+ "video"
+ ],
+ "custom_area_compensation": "1",
+ "daynight_subdivision": "1",
+ "device_share": [
+ "preview",
+ "playback",
+ "voice",
+ "cloud_storage",
+ "motor"
+ ],
+ "diagnose": "1",
+ "diagnose_capability": "1",
+ "download": [
+ "video"
+ ],
+ "events": [
+ "motion",
+ "tamper"
+ ],
+ "gb28181": "1",
+ "greeter": "1.0",
+ "http_system_state_audio_support": "1",
+ "image_capability": "1",
+ "image_list": [
+ "supplement_lamp",
+ "expose"
+ ],
+ "led": "1",
+ "lens_mask": "1",
+ "linkage_capability": "1",
+ "local_storage": "1",
+ "media_encrypt": "1",
+ "msg_alarm_list": [
+ "sound",
+ "light"
+ ],
+ "msg_push": "1",
+ "multi_user": "0",
+ "network": [
+ "wifi",
+ "ethernet"
+ ],
+ "osd_capability": "1",
+ "ota_upgrade": "1",
+ "p2p_support_versions": [
+ "2.0"
+ ],
+ "playback": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "playback_scale": "1",
+ "playback_version": "1.1",
+ "preview": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "privacy_mask_api_version": "1.0",
+ "ptz": "1",
+ "record_max_slot_cnt": "10",
+ "record_type": [
+ "timing",
+ "motion"
+ ],
+ "relay_support_versions": [
+ "2.0"
+ ],
+ "remote_upgrade": "1",
+ "reonboarding": "1",
+ "smart_codec": "0",
+ "smart_detection": "1",
+ "smart_msg_push_capability": "1",
+ "ssl_cer_version": "1.0",
+ "storage_api_version": "2.2",
+ "stream_max_sessions": "10",
+ "streaming_support_versions": [
+ "2.0"
+ ],
+ "tapo_care_version": "1.0.0",
+ "target_track": "1",
+ "timing_reboot": "1",
+ "tums": "1",
+ "tums_config": "1",
+ "tums_msg_push": "1",
+ "verification_change_password": "1",
+ "video_codec": [
+ "h264",
+ "h265"
+ ],
+ "video_detection_digital_sensitivity": "1",
+ "video_message": "1",
+ "wide_range_inf_sensitivity": "1",
+ "wifi_cascade_connection": "0",
+ "wifi_connection_info": "1",
+ "wireless_hotspot": "0"
+ }
+ }
+ }
+ },
+ "scanApList": {
+ "onboarding": {
+ "scan": {
+ "ap_list": [
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 0,
+ "bssid": "000000000000",
+ "encryption": 0,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 0,
+ "bssid": "000000000000",
+ "encryption": 0,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 5,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 0,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "wpa3_supported": "false"
+ }
+ }
+ }
+}
diff --git a/tests/fixtures/smartcam/C520WS(US)_1.0_1.2.8.json b/tests/fixtures/smartcam/C520WS(US)_1.0_1.2.8.json
index 072fea80..c425da79 100644
--- a/tests/fixtures/smartcam/C520WS(US)_1.0_1.2.8.json
+++ b/tests/fixtures/smartcam/C520WS(US)_1.0_1.2.8.json
@@ -1,36 +1,39 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "000 000000 0000000000",
- "connect_type": "wireless",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "last_alarm_time": "0",
- "last_alarm_type": "",
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "C520WS",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.IPCAMERA",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.2.8 Build 240606 Rel.39146n",
- "hardware_version": "1.0",
- "ip": "127.0.0.123",
- "isResetWiFi": false,
- "is_support_iot_cloud": true,
- "mac": "F0-A7-31-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1734386954",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "C520WS",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.2.8 Build 240606 Rel.39146n",
+ "hardware_version": "1.0",
+ "ip": "127.0.0.123",
+ "isResetWiFi": false,
+ "is_support_iot_cloud": true,
+ "mac": "F0-A7-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
}
},
"getAlertConfig": {
@@ -280,15 +283,22 @@
"getClockStatus": {
"system": {
"clock_status": {
- "local_time": "2024-12-02 13:12:15",
- "seconds_from_1970": 1733163135
+ "local_time": "2024-12-16 17:09:43",
+ "seconds_from_1970": 1734386983
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {
+ "status": 0
}
}
},
"getConnectionType": {
"link_type": "wifi",
"rssi": "4",
- "rssiValue": -47,
+ "rssiValue": -45,
"ssid": "I01BU0tFRF9TU0lEIw=="
},
"getDetectionConfig": {
@@ -352,8 +362,8 @@
"getLastAlarmInfo": {
"system": {
"last_alarm_info": {
- "last_alarm_time": "0",
- "last_alarm_type": ""
+ "last_alarm_time": "1734386954",
+ "last_alarm_type": "motion"
}
}
},
@@ -1022,5 +1032,119 @@
}
}
}
+ },
+ "scanApList": {
+ "onboarding": {
+ "scan": {
+ "ap_list": [
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "wpa3_supported": "false"
+ }
+ }
}
}
diff --git a/tests/fixtures/smartcam/H200(EU)_1.0_1.3.2.json b/tests/fixtures/smartcam/H200(EU)_1.0_1.3.2.json
index 04bcc262..4ef99fae 100644
--- a/tests/fixtures/smartcam/H200(EU)_1.0_1.3.2.json
+++ b/tests/fixtures/smartcam/H200(EU)_1.0_1.3.2.json
@@ -1,33 +1,37 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "",
- "connect_type": "wired",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "H200",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.TAPOHUB",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.3.2 Build 20240424 rel.75425",
- "hardware_version": "1.0",
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-6E-84-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "",
+ "connect_type": "wired",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "H200",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.TAPOHUB",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.3.2 Build 20240424 rel.75425",
+ "hardware_version": "1.0",
+ "ip": "127.0.0.123",
+ "isResetWiFi": false,
+ "is_support_iot_cloud": true,
+ "mac": "A8-6E-84-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
}
},
"getAlertConfig": {},
@@ -211,8 +215,8 @@
"fw_ver": "1.11.0 Build 230821 Rel.113553",
"hw_id": "00000000000000000000000000000000",
"hw_ver": "1.0",
- "jamming_rssi": -108,
- "jamming_signal_level": 2,
+ "jamming_rssi": -119,
+ "jamming_signal_level": 1,
"lastOnboardingTimestamp": 1714016798,
"mac": "202351000000",
"model": "S200B",
@@ -221,7 +225,7 @@
"parent_device_id": "0000000000000000000000000000000000000000",
"region": "Europe/London",
"report_interval": 16,
- "rssi": -66,
+ "rssi": -60,
"signal_level": 3,
"specs": "EU",
"status": "online",
@@ -242,8 +246,17 @@
"getClockStatus": {
"system": {
"clock_status": {
- "local_time": "2024-11-01 13:56:27",
- "seconds_from_1970": 1730469387
+ "local_time": "1984-10-21 23:48:23",
+ "seconds_from_1970": 467246903
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {
+ "current_ssid": "",
+ "err_code": 0,
+ "status": 0
}
}
},
@@ -326,6 +339,10 @@
}
}
},
+ "getMatterSetupInfo": {
+ "setup_code": "00000000000",
+ "setup_payload": "00:000000-000000000000"
+ },
"getMediaEncrypt": {
"cet": {
"media_encrypt": {
@@ -350,7 +367,7 @@
"getSirenConfig": {
"duration": 300,
"siren_type": "Doorbell Ring 1",
- "volume": "6"
+ "volume": "1"
},
"getSirenStatus": {
"status": "off",
@@ -386,5 +403,98 @@
"zone_id": "Europe/London"
}
}
+ },
+ "scanApList": {
+ "onboarding": {
+ "scan": {
+ "ap_list": [
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 0,
+ "bssid": "000000000000",
+ "encryption": 0,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 3,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 4,
+ "bssid": "000000000000",
+ "encryption": 3,
+ "rssi": 2,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ {
+ "auth": 3,
+ "bssid": "000000000000",
+ "encryption": 2,
+ "rssi": 1,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ }
+ ],
+ "wpa3_supported": "false"
+ }
+ }
}
}
diff --git a/tests/fixtures/smartcam/H200(US)_1.0_1.3.6.json b/tests/fixtures/smartcam/H200(US)_1.0_1.3.6.json
index f1a6ae15..26c03793 100644
--- a/tests/fixtures/smartcam/H200(US)_1.0_1.3.6.json
+++ b/tests/fixtures/smartcam/H200(US)_1.0_1.3.6.json
@@ -1,34 +1,37 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "",
- "connect_type": "wired",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "H200",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.TAPOHUB",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.3.6 Build 20240829 rel.71119",
- "hardware_version": "1.0",
- "ip": "127.0.0.123",
- "isResetWiFi": false,
- "is_support_iot_cloud": true,
- "mac": "24-2F-D0-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "",
+ "connect_type": "wired",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "H200",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.TAPOHUB",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.3.6 Build 20240829 rel.71119",
+ "hardware_version": "1.0",
+ "ip": "127.0.0.123",
+ "isResetWiFi": false,
+ "is_support_iot_cloud": true,
+ "mac": "24-2F-D0-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
}
},
"getAlertConfig": {},
diff --git a/tests/fixtures/smartcam/TC65_1.0_1.3.9.json b/tests/fixtures/smartcam/TC65_1.0_1.3.9.json
index 5b05a1b3..cec6b759 100644
--- a/tests/fixtures/smartcam/TC65_1.0_1.3.9.json
+++ b/tests/fixtures/smartcam/TC65_1.0_1.3.9.json
@@ -1,35 +1,38 @@
{
"discovery_result": {
- "decrypted_data": {
- "connect_ssid": "0000000",
- "connect_type": "wireless",
- "device_id": "0000000000000000000000000000000000000000",
- "http_port": 443,
- "last_alarm_time": "1698149810",
- "last_alarm_type": "motion",
- "owner": "00000000000000000000000000000000",
- "sd_status": "offline"
- },
- "device_id": "00000000000000000000000000000000",
- "device_model": "TC65",
- "device_name": "#MASKED_NAME#",
- "device_type": "SMART.IPCAMERA",
- "encrypt_info": {
- "data": "",
- "key": "",
- "sym_schm": "AES"
- },
- "encrypt_type": [
- "3"
- ],
- "factory_default": false,
- "firmware_version": "1.3.9 Build 231024 Rel.72919n(4555)",
- "hardware_version": "1.0",
- "ip": "127.0.0.123",
- "is_support_iot_cloud": true,
- "mac": "A8-6E-84-00-00-00",
- "mgt_encrypt_schm": {
- "is_support_https": true
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1698149810",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "TC65",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.3.9 Build 231024 Rel.72919n(4555)",
+ "hardware_version": "1.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "A8-6E-84-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
}
},
"getAlertPlan": {
diff --git a/tests/fixtures/smartcam/TC70_3.0_1.3.11.json b/tests/fixtures/smartcam/TC70_3.0_1.3.11.json
new file mode 100644
index 00000000..b5726982
--- /dev/null
+++ b/tests/fixtures/smartcam/TC70_3.0_1.3.11.json
@@ -0,0 +1,870 @@
+{
+ "discovery_result": {
+ "error_code": 0,
+ "result": {
+ "decrypted_data": {
+ "connect_ssid": "#MASKED_SSID#",
+ "connect_type": "wireless",
+ "device_id": "0000000000000000000000000000000000000000",
+ "http_port": 443,
+ "last_alarm_time": "1734271551",
+ "last_alarm_type": "motion",
+ "owner": "00000000000000000000000000000000",
+ "sd_status": "offline"
+ },
+ "device_id": "00000000000000000000000000000000",
+ "device_model": "TC70",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "encrypt_info": {
+ "data": "",
+ "key": "",
+ "sym_schm": "AES"
+ },
+ "encrypt_type": [
+ "3"
+ ],
+ "factory_default": false,
+ "firmware_version": "1.3.11 Build 231121 Rel.39429n(4555)",
+ "hardware_version": "3.0",
+ "ip": "127.0.0.123",
+ "is_support_iot_cloud": true,
+ "mac": "5C-E9-31-00-00-00",
+ "mgt_encrypt_schm": {
+ "is_support_https": true
+ }
+ }
+ },
+ "getAlertPlan": {
+ "msg_alarm_plan": {
+ "chn1_msg_alarm_plan": {
+ ".name": "chn1_msg_alarm_plan",
+ ".type": "plan",
+ "alarm_plan_1": "0000-0000,127",
+ "enabled": "off"
+ }
+ }
+ },
+ "getAppComponentList": {
+ "app_component": {
+ "app_component_list": [
+ {
+ "name": "sdCard",
+ "version": 1
+ },
+ {
+ "name": "timezone",
+ "version": 1
+ },
+ {
+ "name": "system",
+ "version": 3
+ },
+ {
+ "name": "led",
+ "version": 1
+ },
+ {
+ "name": "playback",
+ "version": 4
+ },
+ {
+ "name": "detection",
+ "version": 1
+ },
+ {
+ "name": "alert",
+ "version": 1
+ },
+ {
+ "name": "firmware",
+ "version": 2
+ },
+ {
+ "name": "account",
+ "version": 1
+ },
+ {
+ "name": "quickSetup",
+ "version": 1
+ },
+ {
+ "name": "ptz",
+ "version": 1
+ },
+ {
+ "name": "video",
+ "version": 2
+ },
+ {
+ "name": "lensMask",
+ "version": 2
+ },
+ {
+ "name": "lightFrequency",
+ "version": 1
+ },
+ {
+ "name": "dayNightMode",
+ "version": 1
+ },
+ {
+ "name": "osd",
+ "version": 2
+ },
+ {
+ "name": "record",
+ "version": 1
+ },
+ {
+ "name": "videoRotation",
+ "version": 1
+ },
+ {
+ "name": "audio",
+ "version": 2
+ },
+ {
+ "name": "diagnose",
+ "version": 1
+ },
+ {
+ "name": "msgPush",
+ "version": 3
+ },
+ {
+ "name": "deviceShare",
+ "version": 1
+ },
+ {
+ "name": "tapoCare",
+ "version": 1
+ },
+ {
+ "name": "blockZone",
+ "version": 1
+ },
+ {
+ "name": "personDetection",
+ "version": 1
+ },
+ {
+ "name": "targetTrack",
+ "version": 1
+ },
+ {
+ "name": "babyCryDetection",
+ "version": 1
+ },
+ {
+ "name": "needSubscriptionServiceList",
+ "version": 1
+ },
+ {
+ "name": "iotCloud",
+ "version": 1
+ },
+ {
+ "name": "recordDownload",
+ "version": 1
+ }
+ ]
+ }
+ },
+ "getAudioConfig": {
+ "audio_config": {
+ "microphone": {
+ ".name": "microphone",
+ ".type": "audio_config",
+ "channels": "1",
+ "encode_type": "G711alaw",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "100"
+ },
+ "speaker": {
+ ".name": "speaker",
+ ".type": "audio_config",
+ "volume": "100"
+ }
+ }
+ },
+ "getBCDConfig": {
+ "sound_detection": {
+ "bcd": {
+ ".name": "bcd",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getCircularRecordingConfig": {
+ "harddisk_manage": {
+ "harddisk": {
+ ".name": "harddisk",
+ ".type": "storage",
+ "loop": "on"
+ }
+ }
+ },
+ "getClockStatus": {
+ "system": {
+ "clock_status": {
+ "local_time": "2024-12-18 22:59:11",
+ "seconds_from_1970": 1734562751
+ }
+ }
+ },
+ "getConnectionType": {
+ "link_type": "wifi",
+ "rssi": "4",
+ "rssiValue": -50,
+ "ssid": "I01BU0tFRF9TU0lEIw=="
+ },
+ "getDetectionConfig": {
+ "motion_detection": {
+ "motion_det": {
+ ".name": "motion_det",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "on",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getDeviceInfo": {
+ "device_info": {
+ "basic_info": {
+ "avatar": "camera c212",
+ "barcode": "",
+ "dev_id": "0000000000000000000000000000000000000000",
+ "device_alias": "#MASKED_NAME#",
+ "device_info": "TC70 3.0 IPC",
+ "device_model": "TC70",
+ "device_name": "#MASKED_NAME#",
+ "device_type": "SMART.IPCAMERA",
+ "features": "3",
+ "ffs": false,
+ "has_set_location_info": 1,
+ "hw_desc": "00000000000000000000000000000000",
+ "hw_version": "3.0",
+ "is_cal": true,
+ "latitude": 0,
+ "longitude": 0,
+ "mac": "5C-E9-31-00-00-00",
+ "oem_id": "00000000000000000000000000000000",
+ "sw_version": "1.3.11 Build 231121 Rel.39429n(4555)"
+ }
+ }
+ },
+ "getFirmwareAutoUpgradeConfig": {
+ "auto_upgrade": {
+ "common": {
+ ".name": "common",
+ ".type": "on_off",
+ "enabled": "off",
+ "random_range": "120",
+ "time": "03:00"
+ }
+ }
+ },
+ "getFirmwareUpdateStatus": {
+ "cloud_config": {
+ "upgrade_status": {
+ "lastUpgradingSuccess": false,
+ "state": "normal"
+ }
+ }
+ },
+ "getLastAlarmInfo": {
+ "system": {
+ "last_alarm_info": {
+ "last_alarm_time": "1734271551",
+ "last_alarm_type": "motion"
+ }
+ }
+ },
+ "getLdc": {
+ "image": {
+ "common": {
+ ".name": "common",
+ ".type": "para",
+ "area_compensation": "default",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "exp_gain": "0",
+ "exp_type": "auto",
+ "focus_limited": "600",
+ "focus_type": "semi_auto",
+ "high_light_compensation": "off",
+ "inf_delay": "10",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "1",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "off",
+ "smartir_level": "100",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off"
+ },
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getLedStatus": {
+ "led": {
+ "config": {
+ ".name": "config",
+ ".type": "led",
+ "enabled": "on"
+ }
+ }
+ },
+ "getLensMaskConfig": {
+ "lens_mask": {
+ "lens_mask_info": {
+ ".name": "lens_mask_info",
+ ".type": "lens_mask_info",
+ "enabled": "on"
+ }
+ }
+ },
+ "getLightFrequencyInfo": {
+ "image": {
+ "common": {
+ ".name": "common",
+ ".type": "para",
+ "area_compensation": "default",
+ "chroma": "50",
+ "contrast": "50",
+ "dehaze": "off",
+ "exp_gain": "0",
+ "exp_type": "auto",
+ "focus_limited": "600",
+ "focus_type": "semi_auto",
+ "high_light_compensation": "off",
+ "inf_delay": "10",
+ "inf_end_time": "21600",
+ "inf_sensitivity": "1",
+ "inf_start_time": "64800",
+ "inf_type": "auto",
+ "light_freq_mode": "auto",
+ "lock_blue_colton": "0",
+ "lock_blue_gain": "0",
+ "lock_gb_gain": "0",
+ "lock_gr_gain": "0",
+ "lock_green_colton": "0",
+ "lock_red_colton": "0",
+ "lock_red_gain": "0",
+ "lock_source": "local",
+ "luma": "50",
+ "saturation": "50",
+ "sharpness": "50",
+ "shutter": "1/25",
+ "smartir": "off",
+ "smartir_level": "100",
+ "wb_B_gain": "50",
+ "wb_G_gain": "50",
+ "wb_R_gain": "50",
+ "wb_type": "auto",
+ "wd_gain": "50",
+ "wide_dynamic": "off"
+ }
+ }
+ },
+ "getMediaEncrypt": {
+ "cet": {
+ "media_encrypt": {
+ ".name": "media_encrypt",
+ ".type": "on_off",
+ "enabled": "on"
+ }
+ }
+ },
+ "getMsgPushConfig": {
+ "msg_push": {
+ "chn1_msg_push_info": {
+ ".name": "chn1_msg_push_info",
+ ".type": "on_off",
+ "notification_enabled": "on",
+ "rich_notification_enabled": "off"
+ }
+ }
+ },
+ "getNightVisionModeConfig": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getPersonDetectionConfig": {
+ "people_detection": {
+ "detection": {
+ ".name": "detection",
+ ".type": "on_off",
+ "enabled": "off"
+ }
+ }
+ },
+ "getPresetConfig": {
+ "preset": {
+ "preset": {
+ "id": [
+ "1"
+ ],
+ "name": [
+ "Viewpoint 1"
+ ],
+ "position_pan": [
+ "0.088935"
+ ],
+ "position_tilt": [
+ "-1.000000"
+ ],
+ "read_only": [
+ "0"
+ ]
+ }
+ }
+ },
+ "getRecordPlan": {
+ "record_plan": {
+ "chn1_channel": {
+ ".name": "chn1_channel",
+ ".type": "plan",
+ "enabled": "on",
+ "friday": "[\"0000-2400:2\"]",
+ "monday": "[\"0000-2400:2\"]",
+ "saturday": "[\"0000-2400:2\"]",
+ "sunday": "[\"0000-2400:2\"]",
+ "thursday": "[\"0000-2400:2\"]",
+ "tuesday": "[\"0000-2400:2\"]",
+ "wednesday": "[\"0000-2400:2\"]"
+ }
+ }
+ },
+ "getRotationStatus": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getSdCardStatus": {
+ "harddisk_manage": {
+ "hd_info": [
+ {
+ "hd_info_1": {
+ "detect_status": "offline",
+ "disk_name": "1",
+ "free_space": "0B",
+ "loop_record_status": "0",
+ "msg_push_free_space": "0B",
+ "msg_push_total_space": "0B",
+ "percent": "0",
+ "picture_free_space": "0B",
+ "picture_total_space": "0B",
+ "record_duration": "0",
+ "record_free_duration": "0",
+ "record_start_time": "0",
+ "rw_attr": "r",
+ "status": "offline",
+ "total_space": "0B",
+ "type": "local",
+ "video_free_space": "0B",
+ "video_total_space": "0B",
+ "write_protect": "0"
+ }
+ }
+ ]
+ }
+ },
+ "getTamperDetectionConfig": {
+ "tamper_detection": {
+ "tamper_det": {
+ ".name": "tamper_det",
+ ".type": "on_off",
+ "digital_sensitivity": "50",
+ "enabled": "off",
+ "sensitivity": "medium"
+ }
+ }
+ },
+ "getTargetTrackConfig": {
+ "target_track": {
+ "target_track_info": {
+ ".name": "target_track_info",
+ ".type": "target_track_info",
+ "enabled": "off"
+ }
+ }
+ },
+ "getTimezone": {
+ "system": {
+ "basic": {
+ ".name": "basic",
+ ".type": "setting",
+ "timezone": "UTC-00:00",
+ "timing_mode": "ntp",
+ "zone_id": "Europe/London"
+ }
+ }
+ },
+ "getVideoCapability": {
+ "video_capability": {
+ "main": {
+ ".name": "main",
+ ".type": "capability",
+ "bitrate_types": [
+ "cbr",
+ "vbr"
+ ],
+ "bitrates": [
+ "256",
+ "512",
+ "1024",
+ "2048"
+ ],
+ "encode_types": [
+ "H264"
+ ],
+ "frame_rates": [
+ "65537",
+ "65546",
+ "65551"
+ ],
+ "qualitys": [
+ "1",
+ "3",
+ "5"
+ ],
+ "resolutions": [
+ "1920*1080",
+ "1280*720",
+ "640*360"
+ ]
+ }
+ }
+ },
+ "getVideoQualities": {
+ "video": {
+ "main": {
+ ".name": "main",
+ ".type": "stream",
+ "bitrate": "1024",
+ "bitrate_type": "vbr",
+ "encode_type": "H264",
+ "frame_rate": "65551",
+ "gop_factor": "2",
+ "name": "VideoEncoder_1",
+ "quality": "3",
+ "resolution": "1280*720",
+ "stream_type": "general"
+ }
+ }
+ },
+ "getWhitelampConfig": {
+ "image": {
+ "switch": {
+ ".name": "switch",
+ ".type": "switch_type",
+ "flip_type": "off",
+ "ldc": "off",
+ "night_vision_mode": "inf_night_vision",
+ "rotate_type": "off",
+ "schedule_end_time": "64800",
+ "schedule_start_time": "21600",
+ "switch_mode": "common",
+ "wtl_intensity_level": "5"
+ }
+ }
+ },
+ "getWhitelampStatus": {
+ "rest_time": 0,
+ "status": 0
+ },
+ "get_audio_capability": {
+ "get": {
+ "audio_capability": {
+ "device_microphone": {
+ ".name": "device_microphone",
+ ".type": "capability",
+ "aec": "1",
+ "channels": "1",
+ "echo_cancelling": "0",
+ "encode_type": [
+ "G711alaw"
+ ],
+ "half_duplex": "1",
+ "mute": "1",
+ "noise_cancelling": "1",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ },
+ "device_speaker": {
+ ".name": "device_speaker",
+ ".type": "capability",
+ "channels": "1",
+ "decode_type": [
+ "G711"
+ ],
+ "mute": "0",
+ "sampling_rate": [
+ "8"
+ ],
+ "volume": "1"
+ }
+ }
+ }
+ },
+ "get_audio_config": {
+ "get": {
+ "audio_config": {
+ "microphone": {
+ ".name": "microphone",
+ ".type": "audio_config",
+ "channels": "1",
+ "encode_type": "G711alaw",
+ "mute": "off",
+ "noise_cancelling": "on",
+ "sampling_rate": "8",
+ "volume": "100"
+ },
+ "speaker": {
+ ".name": "speaker",
+ ".type": "audio_config",
+ "volume": "100"
+ }
+ }
+ }
+ },
+ "get_cet": {
+ "get": {
+ "cet": {
+ "vhttpd": {
+ ".name": "vhttpd",
+ ".type": "server",
+ "port": "8800"
+ }
+ }
+ }
+ },
+ "get_function": {
+ "get": {
+ "function": {
+ "module_spec": {
+ ".name": "module_spec",
+ ".type": "module-spec",
+ "ae_weighting_table_resolution": "5*5",
+ "ai_enhance_capability": "1",
+ "app_version": "1.0.0",
+ "audio": [
+ "speaker",
+ "microphone"
+ ],
+ "audioexception_detection": "0",
+ "auth_encrypt": "1",
+ "backlight_coexistence": "1",
+ "change_password": "1",
+ "client_info": "1",
+ "cloud_storage_version": "1.0",
+ "custom_area_compensation": "1",
+ "custom_auto_mode_exposure_level": "0",
+ "device_share": [
+ "preview",
+ "playback",
+ "voice",
+ "motor",
+ "cloud_storage"
+ ],
+ "download": [
+ "video"
+ ],
+ "events": [
+ "motion",
+ "tamper"
+ ],
+ "greeter": "1.0",
+ "http_system_state_audio_support": "1",
+ "intrusion_detection": "1",
+ "led": "1",
+ "lens_mask": "1",
+ "linecrossing_detection": "1",
+ "linkage_capability": "1",
+ "local_storage": "1",
+ "media_encrypt": "1",
+ "msg_alarm": "1",
+ "msg_alarm_list": [
+ "sound",
+ "light"
+ ],
+ "msg_alarm_separate_list": [
+ "light",
+ "sound"
+ ],
+ "msg_push": "1",
+ "multi_user": "0",
+ "multicast": "0",
+ "network": [
+ "wifi"
+ ],
+ "ota_upgrade": "1",
+ "p2p_support_versions": [
+ "1.1"
+ ],
+ "playback": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "playback_scale": "1",
+ "preview": [
+ "local",
+ "p2p",
+ "relay"
+ ],
+ "privacy_mask_api_version": "1.0",
+ "ptz": "1",
+ "record_max_slot_cnt": "10",
+ "record_type": [
+ "timing",
+ "motion"
+ ],
+ "relay_support_versions": [
+ "1.3"
+ ],
+ "reonboarding": "1",
+ "smart_detection": "1",
+ "smart_msg_push_capability": "1",
+ "ssl_cer_version": "1.0",
+ "storage_api_version": "2.2",
+ "stream_max_sessions": "10",
+ "streaming_support_versions": [
+ "1.0"
+ ],
+ "target_track": "1.0",
+ "timing_reboot": "1",
+ "verification_change_password": "1",
+ "video_codec": [
+ "h264"
+ ],
+ "video_detection_digital_sensitivity": "1",
+ "wifi_cascade_connection": "1",
+ "wifi_connection_info": "1",
+ "wireless_hotspot": "1"
+ }
+ }
+ }
+ },
+ "get_motor": {
+ "get": {
+ "motor": {
+ "capability": {
+ ".name": "capability",
+ ".type": "ptz",
+ "absolute_move_supported": "1",
+ "calibrate_supported": "1",
+ "continuous_move_supported": "1",
+ "eflip_mode": [
+ "off",
+ "on"
+ ],
+ "home_position_mode": "none",
+ "limit_supported": "0",
+ "manual_control_level": [
+ "low",
+ "normal",
+ "high"
+ ],
+ "manual_control_mode": [
+ "compatible",
+ "pedestrian",
+ "motor_vehicle",
+ "non_motor_vehicle",
+ "self_adaptive"
+ ],
+ "park_supported": "0",
+ "pattern_supported": "0",
+ "plan_supported": "0",
+ "position_pan_range": [
+ "-1.000000",
+ "1.000000"
+ ],
+ "position_tilt_range": [
+ "-1.000000",
+ "1.000000"
+ ],
+ "poweroff_save_supported": "1",
+ "poweroff_save_time_range": [
+ "10",
+ "600"
+ ],
+ "preset_number_max": "8",
+ "preset_supported": "1",
+ "relative_move_supported": "1",
+ "reverse_mode": [
+ "off",
+ "on",
+ "auto"
+ ],
+ "scan_supported": "0",
+ "speed_pan_max": "1.00000",
+ "speed_tilt_max": "1.000000",
+ "tour_supported": "0"
+ }
+ }
+ }
+ }
+}
diff --git a/tests/iot/test_iotbulb.py b/tests/iot/test_iotbulb.py
index b573a545..5b759c58 100644
--- a/tests/iot/test_iotbulb.py
+++ b/tests/iot/test_iotbulb.py
@@ -91,7 +91,9 @@ async def test_unknown_temp_range(dev: IotBulb, monkeypatch, caplog):
monkeypatch.setitem(dev._sys_info, "model", "unknown bulb")
light = dev.modules.get(Module.Light)
assert light
- assert light.valid_temperature_range == (2700, 5000)
+ color_temp_feat = light.get_feature("color_temp")
+ assert color_temp_feat
+ assert color_temp_feat.range == (2700, 5000)
assert "Unknown color temperature range, fallback to 2700-5000" in caplog.text
diff --git a/tests/iot/test_iotdevice.py b/tests/iot/test_iotdevice.py
index 124910b7..858c5fbc 100644
--- a/tests/iot/test_iotdevice.py
+++ b/tests/iot/test_iotdevice.py
@@ -99,7 +99,7 @@ async def test_invalid_connection(mocker, dev):
@has_emeter_iot
async def test_initial_update_emeter(dev, mocker):
"""Test that the initial update performs second query if emeter is available."""
- dev._last_update = None
+ dev._last_update = {}
dev._legacy_features = set()
spy = mocker.spy(dev.protocol, "query")
await dev.update()
@@ -111,7 +111,7 @@ async def test_initial_update_emeter(dev, mocker):
@no_emeter_iot
async def test_initial_update_no_emeter(dev, mocker):
"""Test that the initial update performs second query if emeter is available."""
- dev._last_update = None
+ dev._last_update = {}
dev._legacy_features = set()
spy = mocker.spy(dev.protocol, "query")
await dev.update()
diff --git a/tests/protocols/test_smartprotocol.py b/tests/protocols/test_smartprotocol.py
index 988c95eb..7961df68 100644
--- a/tests/protocols/test_smartprotocol.py
+++ b/tests/protocols/test_smartprotocol.py
@@ -2,6 +2,7 @@ import logging
import pytest
import pytest_mock
+from pytest_mock import MockerFixture
from kasa.exceptions import (
SMART_RETRYABLE_ERRORS,
@@ -14,6 +15,7 @@ from kasa.smart import SmartDevice
from ..conftest import device_smart
from ..fakeprotocol_smart import FakeSmartTransport
+from ..fakeprotocol_smartcam import FakeSmartCamTransport
DUMMY_QUERY = {"foobar": {"foo": "bar", "bar": "foo"}}
DUMMY_MULTIPLE_QUERY = {
@@ -448,3 +450,81 @@ async def test_smart_queries_redaction(
await dev.update()
assert device_id not in caplog.text
assert "REDACTED_" + device_id[9::] in caplog.text
+
+
+async def test_no_method_returned_multiple(
+ mocker: MockerFixture, caplog: pytest.LogCaptureFixture
+):
+ """Test protocol handles multiple requests that don't return the method."""
+ req = {
+ "getDeviceInfo": {"device_info": {"name": ["basic_info", "info"]}},
+ "getAppComponentList": {"app_component": {"name": "app_component_list"}},
+ }
+ res = {
+ "result": {
+ "responses": [
+ {
+ "method": "getDeviceInfo",
+ "result": {
+ "device_info": {
+ "basic_info": {
+ "device_model": "C210",
+ },
+ }
+ },
+ "error_code": 0,
+ },
+ {
+ "result": {"app_component": {"app_component_list": []}},
+ "error_code": 0,
+ },
+ ]
+ },
+ "error_code": 0,
+ }
+
+ transport = FakeSmartCamTransport(
+ {},
+ "dummy-name",
+ components_not_included=True,
+ )
+ protocol = SmartProtocol(transport=transport)
+ mocker.patch.object(protocol._transport, "send", return_value=res)
+ await protocol.query(req)
+ assert "No method key in response" in caplog.text
+ caplog.clear()
+ await protocol.query(req)
+ assert "No method key in response" not in caplog.text
+
+
+async def test_no_multiple_methods(
+ mocker: MockerFixture, caplog: pytest.LogCaptureFixture
+):
+ """Test protocol sends NO_MULTI methods as single call."""
+ req = {
+ "getDeviceInfo": {"device_info": {"name": ["basic_info", "info"]}},
+ "getConnectStatus": {"onboarding": {"get_connect_status": {}}},
+ }
+ info = {
+ "getDeviceInfo": {
+ "device_info": {
+ "basic_info": {
+ "avatar": "Home",
+ }
+ }
+ },
+ "getConnectStatus": {
+ "onboarding": {
+ "get_connect_status": {"current_ssid": "", "err_code": 0, "status": 0}
+ }
+ },
+ }
+ transport = FakeSmartCamTransport(
+ info,
+ "dummy-name",
+ components_not_included=True,
+ )
+ protocol = SmartProtocol(transport=transport)
+ send_spy = mocker.spy(protocol._transport, "send")
+ await protocol.query(req)
+ assert send_spy.call_count == 2
diff --git a/tests/smart/modules/test_energy.py b/tests/smart/modules/test_energy.py
index fdbea88b..7b31d74b 100644
--- a/tests/smart/modules/test_energy.py
+++ b/tests/smart/modules/test_energy.py
@@ -1,7 +1,14 @@
+import copy
+import logging
+from contextlib import nullcontext as does_not_raise
+from unittest.mock import patch
+
import pytest
-from kasa import Module, SmartDevice
+from kasa import DeviceError, Module
+from kasa.exceptions import SmartErrorCode
from kasa.interfaces.energy import Energy
+from kasa.smart import SmartDevice
from kasa.smart.modules import Energy as SmartEnergyModule
from tests.conftest import has_emeter_smart
@@ -19,3 +26,84 @@ async def test_supported(dev: SmartDevice):
assert energy_module.supports(Energy.ModuleFeature.VOLTAGE_CURRENT) is False
else:
assert energy_module.supports(Energy.ModuleFeature.VOLTAGE_CURRENT) is True
+
+
+@has_emeter_smart
+async def test_get_energy_usage_error(
+ dev: SmartDevice, caplog: pytest.LogCaptureFixture
+):
+ """Test errors on get_energy_usage."""
+ caplog.set_level(logging.DEBUG)
+
+ energy_module = dev.modules.get(Module.Energy)
+ if not energy_module:
+ pytest.skip(f"Energy module not supported for {dev}.")
+
+ version = dev._components["energy_monitoring"]
+
+ expected_raise = does_not_raise() if version > 1 else pytest.raises(DeviceError)
+ if version > 1:
+ expected = "get_energy_usage"
+ expected_current_consumption = 2.002
+ else:
+ expected = "current_power"
+ expected_current_consumption = None
+
+ assert expected in energy_module.data
+ assert energy_module.current_consumption is not None
+ assert energy_module.consumption_today is not None
+ assert energy_module.consumption_this_month is not None
+
+ last_update = copy.deepcopy(dev._last_update)
+ resp = copy.deepcopy(last_update)
+
+ if ed := resp.get("get_emeter_data"):
+ ed["power_mw"] = 2002
+ if cp := resp.get("get_current_power"):
+ cp["current_power"] = 2.002
+ resp["get_energy_usage"] = SmartErrorCode.JSON_DECODE_FAIL_ERROR
+
+ # version 1 only has get_energy_usage so module should raise an error if
+ # version 1 and get_energy_usage is in error
+ with patch.object(dev.protocol, "query", return_value=resp):
+ await dev.update()
+
+ with expected_raise:
+ assert "get_energy_usage" not in energy_module.data
+
+ assert energy_module.current_consumption == expected_current_consumption
+ assert energy_module.consumption_today is None
+ assert energy_module.consumption_this_month is None
+
+ msg = (
+ f"Removed key get_energy_usage from response for device {dev.host}"
+ " as it returned error: JSON_DECODE_FAIL_ERROR"
+ )
+ if version > 1:
+ assert msg in caplog.text
+
+ # Now test with no get_emeter_data
+ # This may not be valid scenario but we have a fallback to get_current_power
+ # just in case that should be tested.
+ caplog.clear()
+ resp = copy.deepcopy(last_update)
+
+ if cp := resp.get("get_current_power"):
+ cp["current_power"] = 2.002
+ resp["get_energy_usage"] = SmartErrorCode.JSON_DECODE_FAIL_ERROR
+
+ # Remove get_emeter_data from the response and from the device which will
+ # remember it otherwise.
+ resp.pop("get_emeter_data", None)
+ dev._last_update.pop("get_emeter_data", None)
+
+ with patch.object(dev.protocol, "query", return_value=resp):
+ await dev.update()
+
+ with expected_raise:
+ assert "get_energy_usage" not in energy_module.data
+
+ assert energy_module.current_consumption == expected_current_consumption
+
+ # message should only be logged once
+ assert msg not in caplog.text
diff --git a/tests/smart/modules/test_homekit.py b/tests/smart/modules/test_homekit.py
new file mode 100644
index 00000000..81992398
--- /dev/null
+++ b/tests/smart/modules/test_homekit.py
@@ -0,0 +1,16 @@
+from kasa import Module
+from kasa.smart import SmartDevice
+
+from ...device_fixtures import parametrize
+
+homekit = parametrize(
+ "has homekit", component_filter="homekit", protocol_filter={"SMART"}
+)
+
+
+@homekit
+async def test_info(dev: SmartDevice):
+ """Test homekit info."""
+ homekit = dev.modules.get(Module.HomeKit)
+ assert homekit
+ assert homekit.info
diff --git a/tests/smart/modules/test_matter.py b/tests/smart/modules/test_matter.py
new file mode 100644
index 00000000..d3ff8073
--- /dev/null
+++ b/tests/smart/modules/test_matter.py
@@ -0,0 +1,20 @@
+from kasa import Module
+from kasa.smart import SmartDevice
+
+from ...device_fixtures import parametrize
+
+matter = parametrize(
+ "has matter", component_filter="matter", protocol_filter={"SMART", "SMARTCAM"}
+)
+
+
+@matter
+async def test_info(dev: SmartDevice):
+ """Test matter info."""
+ matter = dev.modules.get(Module.Matter)
+ assert matter
+ assert matter.info
+ setup_code = dev.features.get("matter_setup_code")
+ assert setup_code
+ setup_payload = dev.features.get("matter_setup_payload")
+ assert setup_payload
diff --git a/tests/smart/test_smartdevice.py b/tests/smart/test_smartdevice.py
index 25addcfc..549eb8ad 100644
--- a/tests/smart/test_smartdevice.py
+++ b/tests/smart/test_smartdevice.py
@@ -62,11 +62,14 @@ async def test_device_type_no_update(discovery_mock, caplog: pytest.LogCaptureFi
assert repr(dev) == f""
discovery_result = copy.deepcopy(discovery_mock.discovery_data["result"])
+
+ disco_model = discovery_result["device_model"]
+ short_model, _, _ = disco_model.partition("(")
dev.update_from_discover_info(discovery_result)
assert dev.device_type is DeviceType.Unknown
assert (
repr(dev)
- == f""
+ == f""
)
discovery_result["device_type"] = "SMART.FOOBAR"
dev.update_from_discover_info(discovery_result)
@@ -74,7 +77,7 @@ async def test_device_type_no_update(discovery_mock, caplog: pytest.LogCaptureFi
assert dev.device_type is DeviceType.Plug
assert (
repr(dev)
- == f""
+ == f""
)
assert "Unknown device type, falling back to plug" in caplog.text
@@ -352,7 +355,7 @@ async def test_update_module_query_errors(
if mod.name == "Energy":
emod = cast(Energy, mod)
with pytest.raises(KasaException, match="Module update error"):
- assert emod.current_consumption is not None
+ assert emod.status is not None
else:
assert mod.disabled is False
assert mod._error_count == 0
@@ -360,7 +363,7 @@ async def test_update_module_query_errors(
# Test one of the raise_if_update_error doesn't raise
if mod.name == "Energy":
emod = cast(Energy, mod)
- assert emod.current_consumption is not None
+ assert emod.status is not None
async def test_get_modules():
@@ -469,7 +472,9 @@ async def test_smartdevice_cloud_connection(dev: SmartDevice, mocker: MockerFixt
async def test_smart_temp_range(dev: Device):
light = dev.modules.get(Module.Light)
assert light
- assert light.valid_temperature_range
+ color_temp_feat = light.get_feature("color_temp")
+ assert color_temp_feat
+ assert color_temp_feat.range
@device_smart
@@ -528,3 +533,16 @@ async def test_initialize_modules_required_component(
assert "AvailableComponent" in dev.modules
assert "NonExistingComponent" not in dev.modules
+
+
+async def test_smartmodule_query():
+ """Test that a module that doesn't set QUERY_GETTER_NAME has empty query."""
+
+ class DummyModule(SmartModule):
+ pass
+
+ dummy_device = await get_device_for_fixture_protocol(
+ "KS240(US)_1.0_1.0.5.json", "SMART"
+ )
+ mod = DummyModule(dummy_device, "dummy")
+ assert mod.query() == {}
diff --git a/tests/smartcam/modules/test_babycrydetection.py b/tests/smartcam/modules/test_babycrydetection.py
new file mode 100644
index 00000000..89ff5ac4
--- /dev/null
+++ b/tests/smartcam/modules/test_babycrydetection.py
@@ -0,0 +1,45 @@
+"""Tests for smartcam baby cry detection module."""
+
+from __future__ import annotations
+
+from kasa import Device
+from kasa.smartcam.smartcammodule import SmartCamModule
+
+from ...device_fixtures import parametrize
+
+babycrydetection = parametrize(
+ "has babycry detection",
+ component_filter="babyCryDetection",
+ protocol_filter={"SMARTCAM"},
+)
+
+
+@babycrydetection
+async def test_babycrydetection(dev: Device):
+ """Test device babycry detection."""
+ babycry = dev.modules.get(SmartCamModule.SmartCamBabyCryDetection)
+ assert babycry
+
+ bcde_feat = dev.features.get("baby_cry_detection")
+ assert bcde_feat
+
+ original_enabled = babycry.enabled
+
+ try:
+ await babycry.set_enabled(not original_enabled)
+ await dev.update()
+ assert babycry.enabled is not original_enabled
+ assert bcde_feat.value is not original_enabled
+
+ await babycry.set_enabled(original_enabled)
+ await dev.update()
+ assert babycry.enabled is original_enabled
+ assert bcde_feat.value is original_enabled
+
+ await bcde_feat.set_value(not original_enabled)
+ await dev.update()
+ assert babycry.enabled is not original_enabled
+ assert bcde_feat.value is not original_enabled
+
+ finally:
+ await babycry.set_enabled(original_enabled)
diff --git a/tests/smartcam/modules/test_motiondetection.py b/tests/smartcam/modules/test_motiondetection.py
new file mode 100644
index 00000000..c4ff9807
--- /dev/null
+++ b/tests/smartcam/modules/test_motiondetection.py
@@ -0,0 +1,43 @@
+"""Tests for smartcam motion detection module."""
+
+from __future__ import annotations
+
+from kasa import Device
+from kasa.smartcam.smartcammodule import SmartCamModule
+
+from ...device_fixtures import parametrize
+
+motiondetection = parametrize(
+ "has motion detection", component_filter="detection", protocol_filter={"SMARTCAM"}
+)
+
+
+@motiondetection
+async def test_motiondetection(dev: Device):
+ """Test device motion detection."""
+ motion = dev.modules.get(SmartCamModule.SmartCamMotionDetection)
+ assert motion
+
+ mde_feat = dev.features.get("motion_detection")
+ assert mde_feat
+
+ original_enabled = motion.enabled
+
+ try:
+ await motion.set_enabled(not original_enabled)
+ await dev.update()
+ assert motion.enabled is not original_enabled
+ assert mde_feat.value is not original_enabled
+
+ await motion.set_enabled(original_enabled)
+ await dev.update()
+ assert motion.enabled is original_enabled
+ assert mde_feat.value is original_enabled
+
+ await mde_feat.set_value(not original_enabled)
+ await dev.update()
+ assert motion.enabled is not original_enabled
+ assert mde_feat.value is not original_enabled
+
+ finally:
+ await motion.set_enabled(original_enabled)
diff --git a/tests/smartcam/modules/test_persondetection.py b/tests/smartcam/modules/test_persondetection.py
new file mode 100644
index 00000000..34137587
--- /dev/null
+++ b/tests/smartcam/modules/test_persondetection.py
@@ -0,0 +1,45 @@
+"""Tests for smartcam person detection module."""
+
+from __future__ import annotations
+
+from kasa import Device
+from kasa.smartcam.smartcammodule import SmartCamModule
+
+from ...device_fixtures import parametrize
+
+persondetection = parametrize(
+ "has person detection",
+ component_filter="personDetection",
+ protocol_filter={"SMARTCAM"},
+)
+
+
+@persondetection
+async def test_persondetection(dev: Device):
+ """Test device person detection."""
+ person = dev.modules.get(SmartCamModule.SmartCamPersonDetection)
+ assert person
+
+ pde_feat = dev.features.get("person_detection")
+ assert pde_feat
+
+ original_enabled = person.enabled
+
+ try:
+ await person.set_enabled(not original_enabled)
+ await dev.update()
+ assert person.enabled is not original_enabled
+ assert pde_feat.value is not original_enabled
+
+ await person.set_enabled(original_enabled)
+ await dev.update()
+ assert person.enabled is original_enabled
+ assert pde_feat.value is original_enabled
+
+ await pde_feat.set_value(not original_enabled)
+ await dev.update()
+ assert person.enabled is not original_enabled
+ assert pde_feat.value is not original_enabled
+
+ finally:
+ await person.set_enabled(original_enabled)
diff --git a/tests/smartcam/modules/test_tamperdetection.py b/tests/smartcam/modules/test_tamperdetection.py
new file mode 100644
index 00000000..ab2f851d
--- /dev/null
+++ b/tests/smartcam/modules/test_tamperdetection.py
@@ -0,0 +1,45 @@
+"""Tests for smartcam tamper detection module."""
+
+from __future__ import annotations
+
+from kasa import Device
+from kasa.smartcam.smartcammodule import SmartCamModule
+
+from ...device_fixtures import parametrize
+
+tamperdetection = parametrize(
+ "has tamper detection",
+ component_filter="tamperDetection",
+ protocol_filter={"SMARTCAM"},
+)
+
+
+@tamperdetection
+async def test_tamperdetection(dev: Device):
+ """Test device tamper detection."""
+ tamper = dev.modules.get(SmartCamModule.SmartCamTamperDetection)
+ assert tamper
+
+ tde_feat = dev.features.get("tamper_detection")
+ assert tde_feat
+
+ original_enabled = tamper.enabled
+
+ try:
+ await tamper.set_enabled(not original_enabled)
+ await dev.update()
+ assert tamper.enabled is not original_enabled
+ assert tde_feat.value is not original_enabled
+
+ await tamper.set_enabled(original_enabled)
+ await dev.update()
+ assert tamper.enabled is original_enabled
+ assert tde_feat.value is original_enabled
+
+ await tde_feat.set_value(not original_enabled)
+ await dev.update()
+ assert tamper.enabled is not original_enabled
+ assert tde_feat.value is not original_enabled
+
+ finally:
+ await tamper.set_enabled(original_enabled)
diff --git a/tests/smartcam/test_smartcamdevice.py b/tests/smartcam/test_smartcamdevice.py
index 438737eb..3355d2f0 100644
--- a/tests/smartcam/test_smartcamdevice.py
+++ b/tests/smartcam/test_smartcamdevice.py
@@ -17,10 +17,20 @@ async def test_state(dev: Device):
if dev.device_type is DeviceType.Hub:
pytest.skip("Hubs cannot be switched on and off")
- state = dev.is_on
- await dev.set_state(not state)
+ if Module.LensMask in dev.modules:
+ state = dev.is_on
+ await dev.set_state(not state)
+ await dev.update()
+ assert dev.is_on is not state
+
+ dev.modules.pop(Module.LensMask) # type: ignore[attr-defined]
+
+ # Test with no lens mask module. Device is always on.
+ assert dev.is_on is True
+ res = await dev.set_state(False)
+ assert res == {}
await dev.update()
- assert dev.is_on is not state
+ assert dev.is_on is True
@device_smartcam
diff --git a/tests/test_bulb.py b/tests/test_bulb.py
index 6956c4e8..f7a77a8d 100644
--- a/tests/test_bulb.py
+++ b/tests/test_bulb.py
@@ -25,7 +25,7 @@ async def test_hsv(dev: Device, turn_on):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
- assert light.is_color
+ assert light.has_feature("hsv")
hue, saturation, brightness = light.hsv
assert 0 <= hue <= 360
@@ -106,7 +106,7 @@ async def test_invalid_hsv(
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
- assert light.is_color
+ assert light.has_feature("hsv")
with pytest.raises(exception_cls, match=error):
await light.set_hsv(hue, sat, brightness)
@@ -124,7 +124,7 @@ async def test_color_state_information(dev: Device):
async def test_hsv_on_non_color(dev: Device):
light = dev.modules.get(Module.Light)
assert light
- assert not light.is_color
+ assert not light.has_feature("hsv")
with pytest.raises(KasaException):
await light.set_hsv(0, 0, 0)
@@ -173,9 +173,6 @@ async def test_non_variable_temp(dev: Device):
with pytest.raises(KasaException):
await light.set_color_temp(2700)
- with pytest.raises(KasaException):
- print(light.valid_temperature_range)
-
with pytest.raises(KasaException):
print(light.color_temp)
diff --git a/tests/test_childdevice.py b/tests/test_childdevice.py
index 1e525efb..8bcc05db 100644
--- a/tests/test_childdevice.py
+++ b/tests/test_childdevice.py
@@ -145,7 +145,9 @@ async def test_child_device_type_unknown(caplog):
super().__init__(
SmartDevice("127.0.0.1"),
{"device_id": "1", "category": "foobar"},
- {"device", 1},
+ {
+ "component_list": [{"id": "device", "ver_code": 1}],
+ },
)
assert DummyDevice().device_type is DeviceType.Unknown
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 4391b998..1b589f5c 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -12,6 +12,7 @@ from pytest_mock import MockerFixture
from kasa import (
AuthenticationError,
+ ColorTempRange,
Credentials,
Device,
DeviceError,
@@ -121,8 +122,15 @@ async def test_list_devices(discovery_mock, runner):
catch_exceptions=False,
)
assert res.exit_code == 0
- header = f"{'HOST':<15} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} {'ALIAS'}"
- row = f"{discovery_mock.ip:<15} {discovery_mock.device_type:<20} {discovery_mock.encrypt_type:<7}"
+ header = (
+ f"{'HOST':<15} {'MODEL':<9} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} "
+ f"{'HTTPS':<5} {'LV':<3} {'ALIAS'}"
+ )
+ row = (
+ f"{discovery_mock.ip:<15} {discovery_mock.model:<9} {discovery_mock.device_type:<20} "
+ f"{discovery_mock.encrypt_type:<7} {discovery_mock.https:<5} "
+ f"{discovery_mock.login_version or '-':<3}"
+ )
assert header in res.output
assert row in res.output
@@ -157,14 +165,26 @@ async def test_discover_raw(discovery_mock, runner, mocker):
redact_spy.assert_called()
+@pytest.mark.parametrize(
+ ("exception", "expected"),
+ [
+ pytest.param(
+ AuthenticationError("Failed to authenticate"),
+ "Authentication failed",
+ id="auth",
+ ),
+ pytest.param(TimeoutError(), "Timed out", id="timeout"),
+ pytest.param(Exception("Foobar"), "Error: Foobar", id="other-error"),
+ ],
+)
@new_discovery
-async def test_list_auth_failed(discovery_mock, mocker, runner):
+async def test_list_update_failed(discovery_mock, mocker, runner, exception, expected):
"""Test that device update is called on main."""
device_class = Discover._get_device_class(discovery_mock.discovery_data)
mocker.patch.object(
device_class,
"update",
- side_effect=AuthenticationError("Failed to authenticate"),
+ side_effect=exception,
)
res = await runner.invoke(
cli,
@@ -172,10 +192,17 @@ async def test_list_auth_failed(discovery_mock, mocker, runner):
catch_exceptions=False,
)
assert res.exit_code == 0
- header = f"{'HOST':<15} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} {'ALIAS'}"
- row = f"{discovery_mock.ip:<15} {discovery_mock.device_type:<20} {discovery_mock.encrypt_type:<7} - Authentication failed"
- assert header in res.output
- assert row in res.output
+ header = (
+ f"{'HOST':<15} {'MODEL':<9} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} "
+ f"{'HTTPS':<5} {'LV':<3} {'ALIAS'}"
+ )
+ row = (
+ f"{discovery_mock.ip:<15} {discovery_mock.model:<9} {discovery_mock.device_type:<20} "
+ f"{discovery_mock.encrypt_type:<7} {discovery_mock.https:<5} "
+ f"{discovery_mock.login_version or '-':<3} - {expected}"
+ )
+ assert header in res.output.replace("\n", "")
+ assert row in res.output.replace("\n", "")
async def test_list_unsupported(unsupported_device_info, runner):
@@ -186,7 +213,10 @@ async def test_list_unsupported(unsupported_device_info, runner):
catch_exceptions=False,
)
assert res.exit_code == 0
- header = f"{'HOST':<15} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} {'ALIAS'}"
+ header = (
+ f"{'HOST':<15} {'MODEL':<9} {'DEVICE FAMILY':<20} {'ENCRYPT':<7} "
+ f"{'HTTPS':<5} {'LV':<3} {'ALIAS'}"
+ )
row = f"{'127.0.0.1':<15} UNSUPPORTED DEVICE"
assert header in res.output
assert row in res.output
@@ -238,7 +268,8 @@ async def test_alias(dev, runner):
res = await runner.invoke(alias, obj=dev)
assert f"Alias: {new_alias}" in res.output
- await dev.set_alias(old_alias)
+ # If alias is None set it back to empty string
+ await dev.set_alias(old_alias or "")
async def test_raw_command(dev, mocker, runner):
@@ -523,7 +554,9 @@ async def test_emeter(dev: Device, mocker, runner):
async def test_brightness(dev: Device, runner):
res = await runner.invoke(brightness, obj=dev)
- if not (light := dev.modules.get(Module.Light)) or not light.is_dimmable:
+ if not (light := dev.modules.get(Module.Light)) or not light.has_feature(
+ "brightness"
+ ):
assert "This device does not support brightness." in res.output
return
@@ -540,13 +573,16 @@ async def test_brightness(dev: Device, runner):
async def test_color_temperature(dev: Device, runner):
res = await runner.invoke(temperature, obj=dev)
- if not (light := dev.modules.get(Module.Light)) or not light.is_variable_color_temp:
+ if not (light := dev.modules.get(Module.Light)) or not (
+ color_temp_feat := light.get_feature("color_temp")
+ ):
assert "Device does not support color temperature" in res.output
return
res = await runner.invoke(temperature, obj=dev)
assert f"Color temperature: {light.color_temp}" in res.output
- valid_range = light.valid_temperature_range
+ valid_range = color_temp_feat.range
+ assert isinstance(valid_range, ColorTempRange)
assert f"(min: {valid_range.min}, max: {valid_range.max})" in res.output
val = int((valid_range.min + valid_range.max) / 2)
@@ -572,7 +608,7 @@ async def test_color_temperature(dev: Device, runner):
async def test_color_hsv(dev: Device, runner: CliRunner):
res = await runner.invoke(hsv, obj=dev)
- if not (light := dev.modules.get(Module.Light)) or not light.is_color:
+ if not (light := dev.modules.get(Module.Light)) or not light.has_feature("hsv"):
assert "Device does not support colors" in res.output
return
@@ -1126,7 +1162,7 @@ async def test_feature_set_child(mocker, runner):
mocker.patch("kasa.discover.Discover.discover_single", return_value=dummy_device)
get_child_device = mocker.spy(dummy_device, "get_child_device")
- child_id = "000000000000000000000000000000000000000001"
+ child_id = "SCRUBBED_CHILD_DEVICE_ID_1"
res = await runner.invoke(
cli,
diff --git a/tests/test_common_modules.py b/tests/test_common_modules.py
index 32863604..cba1ef87 100644
--- a/tests/test_common_modules.py
+++ b/tests/test_common_modules.py
@@ -198,7 +198,7 @@ async def test_light_color_temp(dev: Device):
light = next(get_parent_and_child_modules(dev, Module.Light))
assert light
- if not light.is_variable_color_temp:
+ if not light.has_feature("color_temp"):
pytest.skip(
"Some smart light strips have color_temperature"
" component but min and max are the same"
diff --git a/tests/test_device.py b/tests/test_device.py
index 0764acfb..20e5bef8 100644
--- a/tests/test_device.py
+++ b/tests/test_device.py
@@ -65,12 +65,13 @@ async def test_alias(dev):
test_alias = "TEST1234"
original = dev.alias
- assert isinstance(original, str)
+ assert isinstance(original, str | None)
await dev.set_alias(test_alias)
await dev.update()
assert dev.alias == test_alias
- await dev.set_alias(original)
+ # If alias is None set it back to empty string
+ await dev.set_alias(original or "")
await dev.update()
assert dev.alias == original
@@ -86,7 +87,11 @@ async def test_device_class_ctors(device_class_name_obj):
if issubclass(klass, SmartChildDevice):
parent = SmartDevice(host, config=config)
dev = klass(
- parent, {"dummy": "info", "device_id": "dummy"}, {"dummy": "components"}
+ parent,
+ {"dummy": "info", "device_id": "dummy"},
+ {
+ "component_list": [{"id": "device", "ver_code": 1}],
+ },
)
else:
dev = klass(host, config=config)
@@ -106,7 +111,11 @@ async def test_device_class_repr(device_class_name_obj):
if issubclass(klass, SmartChildDevice):
parent = SmartDevice(host, config=config)
dev = klass(
- parent, {"dummy": "info", "device_id": "dummy"}, {"dummy": "components"}
+ parent,
+ {"dummy": "info", "device_id": "dummy"},
+ {
+ "component_list": [{"id": "device", "ver_code": 1}],
+ },
)
else:
dev = klass(host, config=config)
@@ -272,19 +281,19 @@ async def test_deprecated_light_attributes(dev: Device):
await _test_attribute(dev, "is_color", bool(light), "Light")
await _test_attribute(dev, "is_variable_color_temp", bool(light), "Light")
- exc = KasaException if light and not light.is_dimmable else None
+ exc = KasaException if light and not light.has_feature("brightness") else None
await _test_attribute(dev, "brightness", bool(light), "Light", will_raise=exc)
await _test_attribute(
dev, "set_brightness", bool(light), "Light", 50, will_raise=exc
)
- exc = KasaException if light and not light.is_color else None
+ exc = KasaException if light and not light.has_feature("hsv") else None
await _test_attribute(dev, "hsv", bool(light), "Light", will_raise=exc)
await _test_attribute(
dev, "set_hsv", bool(light), "Light", 50, 50, 50, will_raise=exc
)
- exc = KasaException if light and not light.is_variable_color_temp else None
+ exc = KasaException if light and not light.has_feature("color_temp") else None
await _test_attribute(dev, "color_temp", bool(light), "Light", will_raise=exc)
await _test_attribute(
dev, "set_color_temp", bool(light), "Light", 2700, will_raise=exc
diff --git a/tests/test_device_factory.py b/tests/test_device_factory.py
index ed73b3a3..66e24324 100644
--- a/tests/test_device_factory.py
+++ b/tests/test_device_factory.py
@@ -13,9 +13,13 @@ import aiohttp
import pytest # type: ignore # https://github.com/pytest-dev/pytest/issues/3342
from kasa import (
+ BaseProtocol,
Credentials,
Discover,
+ IotProtocol,
KasaException,
+ SmartCamProtocol,
+ SmartProtocol,
)
from kasa.device_factory import (
Device,
@@ -33,6 +37,16 @@ from kasa.deviceconfig import (
DeviceFamily,
)
from kasa.discover import DiscoveryResult
+from kasa.transports import (
+ AesTransport,
+ BaseTransport,
+ KlapTransport,
+ KlapTransportV2,
+ LinkieTransportV2,
+ SslAesTransport,
+ SslTransport,
+ XorTransport,
+)
from .conftest import DISCOVERY_MOCK_IP
@@ -203,3 +217,74 @@ async def test_device_class_from_unknown_family(caplog):
with caplog.at_level(logging.DEBUG):
assert get_device_class_from_family(dummy_name, https=False) == SmartDevice
assert f"Unknown SMART device with {dummy_name}" in caplog.text
+
+
+# Aliases to make the test params more readable
+CP = DeviceConnectionParameters
+DF = DeviceFamily
+ET = DeviceEncryptionType
+
+
+@pytest.mark.parametrize(
+ ("conn_params", "expected_protocol", "expected_transport"),
+ [
+ pytest.param(
+ CP(DF.SmartIpCamera, ET.Aes, https=True),
+ SmartCamProtocol,
+ SslAesTransport,
+ id="smartcam",
+ ),
+ pytest.param(
+ CP(DF.SmartTapoHub, ET.Aes, https=True),
+ SmartCamProtocol,
+ SslAesTransport,
+ id="smartcam-hub",
+ ),
+ pytest.param(
+ CP(DF.IotIpCamera, ET.Aes, https=True),
+ IotProtocol,
+ LinkieTransportV2,
+ id="kasacam",
+ ),
+ pytest.param(
+ CP(DF.SmartTapoRobovac, ET.Aes, https=True),
+ SmartProtocol,
+ SslTransport,
+ id="robovac",
+ ),
+ pytest.param(
+ CP(DF.IotSmartPlugSwitch, ET.Klap, https=False),
+ IotProtocol,
+ KlapTransport,
+ id="iot-klap",
+ ),
+ pytest.param(
+ CP(DF.IotSmartPlugSwitch, ET.Xor, https=False),
+ IotProtocol,
+ XorTransport,
+ id="iot-xor",
+ ),
+ pytest.param(
+ CP(DF.SmartTapoPlug, ET.Aes, https=False),
+ SmartProtocol,
+ AesTransport,
+ id="smart-aes",
+ ),
+ pytest.param(
+ CP(DF.SmartTapoPlug, ET.Klap, https=False),
+ SmartProtocol,
+ KlapTransportV2,
+ id="smart-klap",
+ ),
+ ],
+)
+async def test_get_protocol(
+ conn_params: DeviceConnectionParameters,
+ expected_protocol: type[BaseProtocol],
+ expected_transport: type[BaseTransport],
+):
+ """Test get_protocol returns the right protocol."""
+ config = DeviceConfig("127.0.0.1", connection_type=conn_params)
+ protocol = get_protocol(config)
+ assert isinstance(protocol, expected_protocol)
+ assert isinstance(protocol._transport, expected_transport)
diff --git a/tests/test_devtools.py b/tests/test_devtools.py
index e18243af..8bdd5746 100644
--- a/tests/test_devtools.py
+++ b/tests/test_devtools.py
@@ -29,11 +29,13 @@ async def test_fixture_names(fixture_info: FixtureInfo):
"""Test that device info gets the right fixture names."""
if fixture_info.protocol in {"SMARTCAM"}:
device_info = SmartCamDevice._get_device_info(
- fixture_info.data, fixture_info.data.get("discovery_result")
+ fixture_info.data,
+ fixture_info.data.get("discovery_result", {}).get("result"),
)
elif fixture_info.protocol in {"SMART"}:
device_info = SmartDevice._get_device_info(
- fixture_info.data, fixture_info.data.get("discovery_result")
+ fixture_info.data,
+ fixture_info.data.get("discovery_result", {}).get("result"),
)
elif fixture_info.protocol in {"SMART.CHILD"}:
device_info = SmartDevice._get_device_info(fixture_info.data, None)
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
index 7069e32f..59a337d2 100644
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -390,13 +390,12 @@ async def test_device_update_from_new_discovery_info(discovery_mock):
device_class = Discover._get_device_class(discovery_data)
device = device_class("127.0.0.1")
discover_info = DiscoveryResult.from_dict(discovery_data["result"])
- discover_dump = discover_info.to_dict()
- model, _, _ = discover_dump["device_model"].partition("(")
- discover_dump["model"] = model
- device.update_from_discover_info(discover_dump)
- assert device.mac == discover_dump["mac"].replace("-", ":")
- assert device.model == model
+ device.update_from_discover_info(discovery_data["result"])
+
+ assert device.mac == discover_info.mac.replace("-", ":")
+ no_region_model, _, _ = discover_info.device_model.partition("(")
+ assert device.model == no_region_model
# TODO implement requires_update for SmartDevice
if isinstance(device, IotDevice):
diff --git a/tests/test_readme_examples.py b/tests/test_readme_examples.py
index 394a3aff..b6513476 100644
--- a/tests/test_readme_examples.py
+++ b/tests/test_readme_examples.py
@@ -19,9 +19,12 @@ def test_bulb_examples(mocker):
assert not res["failed"]
-def test_smartdevice_examples(mocker):
+def test_iotdevice_examples(mocker):
"""Use HS110 for emeter examples."""
p = asyncio.run(get_device_for_fixture_protocol("HS110(EU)_1.0_1.2.5.json", "IOT"))
+ asyncio.run(p.set_alias("Bedroom Lamp Plug"))
+ asyncio.run(p.update())
+
mocker.patch("kasa.iot.iotdevice.IotDevice", return_value=p)
mocker.patch("kasa.iot.iotdevice.IotDevice.update")
res = xdoctest.doctest_module("kasa.iot.iotdevice", "all")
@@ -31,18 +34,16 @@ def test_smartdevice_examples(mocker):
def test_plug_examples(mocker):
"""Test plug examples."""
p = asyncio.run(get_device_for_fixture_protocol("HS110(EU)_1.0_1.2.5.json", "IOT"))
- # p = await get_device_for_fixture_protocol("HS110(EU)_1.0_1.2.5.json", "IOT")
+ asyncio.run(p.set_alias("Bedroom Lamp Plug"))
+ asyncio.run(p.update())
mocker.patch("kasa.iot.iotplug.IotPlug", return_value=p)
mocker.patch("kasa.iot.iotplug.IotPlug.update")
res = xdoctest.doctest_module("kasa.iot.iotplug", "all")
assert not res["failed"]
-def test_strip_examples(mocker):
+def test_strip_examples(readmes_mock):
"""Test strip examples."""
- p = asyncio.run(get_device_for_fixture_protocol("KP303(UK)_1.0_1.0.3.json", "IOT"))
- mocker.patch("kasa.iot.iotstrip.IotStrip", return_value=p)
- mocker.patch("kasa.iot.iotstrip.IotStrip.update")
res = xdoctest.doctest_module("kasa.iot.iotstrip", "all")
assert not res["failed"]
@@ -59,6 +60,8 @@ def test_dimmer_examples(mocker):
def test_lightstrip_examples(mocker):
"""Test lightstrip examples."""
p = asyncio.run(get_device_for_fixture_protocol("KL430(US)_1.0_1.0.10.json", "IOT"))
+ asyncio.run(p.set_alias("Bedroom Lightstrip"))
+ asyncio.run(p.update())
mocker.patch("kasa.iot.iotlightstrip.IotLightStrip", return_value=p)
mocker.patch("kasa.iot.iotlightstrip.IotLightStrip.update")
res = xdoctest.doctest_module("kasa.iot.iotlightstrip", "all")
@@ -154,4 +157,23 @@ async def readmes_mock(mocker):
"127.0.0.4": get_fixture_info("KL430(US)_1.0_1.0.10.json", "IOT"), # Lightstrip
"127.0.0.5": get_fixture_info("HS220(US)_1.0_1.5.7.json", "IOT"), # Dimmer
}
+ fixture_infos["127.0.0.1"].data["system"]["get_sysinfo"]["alias"] = (
+ "Bedroom Power Strip"
+ )
+ for index, child in enumerate(
+ fixture_infos["127.0.0.1"].data["system"]["get_sysinfo"]["children"]
+ ):
+ child["alias"] = f"Plug {index + 1}"
+ fixture_infos["127.0.0.2"].data["system"]["get_sysinfo"]["alias"] = (
+ "Bedroom Lamp Plug"
+ )
+ fixture_infos["127.0.0.3"].data["get_device_info"]["nickname"] = (
+ "TGl2aW5nIFJvb20gQnVsYg==" # Living Room Bulb
+ )
+ fixture_infos["127.0.0.4"].data["system"]["get_sysinfo"]["alias"] = (
+ "Bedroom Lightstrip"
+ )
+ fixture_infos["127.0.0.5"].data["system"]["get_sysinfo"]["alias"] = (
+ "Living Room Dimmer Switch"
+ )
return patch_discovery(fixture_infos, mocker)
diff --git a/tests/transports/test_sslaestransport.py b/tests/transports/test_sslaestransport.py
index 6816fa35..39469967 100644
--- a/tests/transports/test_sslaestransport.py
+++ b/tests/transports/test_sslaestransport.py
@@ -15,8 +15,10 @@ from kasa.credentials import DEFAULT_CREDENTIALS, Credentials, get_default_crede
from kasa.deviceconfig import DeviceConfig
from kasa.exceptions import (
AuthenticationError,
+ DeviceError,
KasaException,
SmartErrorCode,
+ _RetryableError,
)
from kasa.httpclient import HttpClient
from kasa.transports.aestransport import AesEncyptionSession
@@ -200,6 +202,64 @@ async def test_unencrypted_response(mocker, caplog):
)
+async def test_device_blocked_response(mocker):
+ host = "127.0.0.1"
+ mock_ssl_aes_device = MockSslAesDevice(host, device_blocked=True)
+ mocker.patch.object(
+ aiohttp.ClientSession, "post", side_effect=mock_ssl_aes_device.post
+ )
+
+ transport = SslAesTransport(
+ config=DeviceConfig(host, credentials=Credentials(MOCK_USER, MOCK_PWD))
+ )
+ msg = "Device blocked for 1685 seconds"
+
+ with pytest.raises(DeviceError, match=msg):
+ await transport.perform_handshake()
+
+
+@pytest.mark.parametrize(
+ ("response", "expected_msg"),
+ [
+ pytest.param(
+ {"error_code": -1, "msg": "Check tapo tag failed"},
+ '{"error_code": -1, "msg": "Check tapo tag failed"}',
+ id="can-decrypt",
+ ),
+ pytest.param(
+ b"12345678",
+ str({"result": {"response": "12345678"}, "error_code": 0}),
+ id="cannot-decrypt",
+ ),
+ ],
+)
+async def test_device_500_error(mocker, response, expected_msg):
+ """Test 500 error raises retryable exception."""
+ host = "127.0.0.1"
+ mock_ssl_aes_device = MockSslAesDevice(host)
+ mocker.patch.object(
+ aiohttp.ClientSession, "post", side_effect=mock_ssl_aes_device.post
+ )
+
+ transport = SslAesTransport(
+ config=DeviceConfig(host, credentials=Credentials(MOCK_USER, MOCK_PWD))
+ )
+
+ request = {
+ "method": "getDeviceInfo",
+ "params": None,
+ }
+
+ await transport.perform_handshake()
+
+ mock_ssl_aes_device.put_next_response(response)
+ mock_ssl_aes_device.status_code = 500
+
+ msg = f"Device 127.0.0.1 replied with status 500 after handshake, response: {expected_msg}"
+ with pytest.raises(_RetryableError, match=msg):
+ await transport.send(json_dumps(request))
+
+
async def test_port_override():
"""Test that port override sets the app_url."""
host = "127.0.0.1"
@@ -235,6 +295,11 @@ class MockSslAesDevice:
},
}
+ DEVICE_BLOCKED_RESP = {
+ "data": {"code": SmartErrorCode.DEVICE_BLOCKED.value, "sec_left": 1685},
+ "error_code": SmartErrorCode.SESSION_EXPIRED.value,
+ }
+
class _mock_response:
def __init__(self, status, request: dict):
self.status = status
@@ -263,6 +328,7 @@ class MockSslAesDevice:
send_error_code=0,
secure_passthrough_error_code=0,
digest_password_fail=False,
+ device_blocked=False,
):
self.host = host
self.http_client = HttpClient(DeviceConfig(self.host))
@@ -277,6 +343,9 @@ class MockSslAesDevice:
self.do_not_encrypt_response = do_not_encrypt_response
self.want_default_username = want_default_username
self.digest_password_fail = digest_password_fail
+ self.device_blocked = device_blocked
+
+ self._next_responses: list[dict | bytes] = []
async def post(self, url: URL, params=None, json=None, data=None, *_, **__):
if data:
@@ -303,6 +372,9 @@ class MockSslAesDevice:
request_nonce = request["params"].get("cnonce")
request_username = request["params"].get("username")
+ if self.device_blocked:
+ return self._mock_response(self.status_code, self.DEVICE_BLOCKED_RESP)
+
if (self.want_default_username and request_username != MOCK_ADMIN_USER) or (
not self.want_default_username and request_username != MOCK_USER
):
@@ -359,11 +431,24 @@ class MockSslAesDevice:
assert self.encryption_session
decrypted_request = self.encryption_session.decrypt(encrypted_request.encode())
decrypted_request_dict = json_loads(decrypted_request)
- decrypted_response = await self._post(url, decrypted_request_dict)
- async with decrypted_response:
- decrypted_response_data = await decrypted_response.read()
- encrypted_response = self.encryption_session.encrypt(decrypted_response_data)
+ if self._next_responses:
+ next_response = self._next_responses.pop(0)
+ if isinstance(next_response, dict):
+ decrypted_response_data = json_dumps(next_response).encode()
+ encrypted_response = self.encryption_session.encrypt(
+ decrypted_response_data
+ )
+ else:
+ encrypted_response = next_response
+ else:
+ decrypted_response = await self._post(url, decrypted_request_dict)
+ async with decrypted_response:
+ decrypted_response_data = await decrypted_response.read()
+ encrypted_response = self.encryption_session.encrypt(
+ decrypted_response_data
+ )
+
response = (
decrypted_response_data
if self.do_not_encrypt_response
@@ -378,3 +463,6 @@ class MockSslAesDevice:
async def _return_send_response(self, url: URL, json: dict[str, Any]):
result = {"result": {"method": None}, "error_code": self.send_error_code}
return self._mock_response(self.status_code, result)
+
+ def put_next_response(self, request: dict | bytes) -> None:
+ self._next_responses.append(request)
diff --git a/uv.lock b/uv.lock
index c6802330..e8ca1c4b 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,16 +3,16 @@ requires-python = ">=3.11, <4.0"
[[package]]
name = "aiohappyeyeballs"
-version = "2.4.3"
+version = "2.4.4"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 }
+sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 },
+ { url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756 },
]
[[package]]
name = "aiohttp"
-version = "3.11.7"
+version = "3.11.11"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
@@ -23,65 +23,65 @@ dependencies = [
{ name = "propcache" },
{ name = "yarl" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/4b/cb/f9bb10e0cf6f01730b27d370b10cc15822bea4395acd687abc8cc5fed3ed/aiohttp-3.11.7.tar.gz", hash = "sha256:01a8aca4af3da85cea5c90141d23f4b0eee3cbecfd33b029a45a80f28c66c668", size = 7666482 }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/ed/f26db39d29cd3cb2f5a3374304c713fe5ab5a0e4c8ee25a0c45cc6adf844/aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e", size = 7669618 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/13/7f/272fa1adf68fe2fbebfe686a67b50cfb40d86dfe47d0441aff6f0b7c4c0e/aiohttp-3.11.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cea52d11e02123f125f9055dfe0ccf1c3857225fb879e4a944fae12989e2aef2", size = 706820 },
- { url = "https://files.pythonhosted.org/packages/79/3c/6d612ef77cdba75364393f04c5c577481e3b5123a774eea447ada1ddd14f/aiohttp-3.11.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ce18f703b7298e7f7633efd6a90138d99a3f9a656cb52c1201e76cb5d79cf08", size = 466654 },
- { url = "https://files.pythonhosted.org/packages/4f/b8/1052667d4800cd49bb4f869f1ed42f5e9d5acd4676275e64ccc244c9c040/aiohttp-3.11.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:670847ee6aeb3a569cd7cdfbe0c3bec1d44828bbfbe78c5d305f7f804870ef9e", size = 454041 },
- { url = "https://files.pythonhosted.org/packages/9f/07/80fa7302314a6ee1c9278550e9d95b77a4c895999bfbc5364ed0ee28dc7c/aiohttp-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dda726f89bfa5c465ba45b76515135a3ece0088dfa2da49b8bb278f3bdeea12", size = 1684778 },
- { url = "https://files.pythonhosted.org/packages/2e/30/a71eb45197ad6bb6af87dfb39be8b56417d24d916047d35ef3f164af87f4/aiohttp-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25b74a811dba37c7ea6a14d99eb9402d89c8d739d50748a75f3cf994cf19c43", size = 1740992 },
- { url = "https://files.pythonhosted.org/packages/22/74/0f9394429f3c4197129333a150a85cb2a642df30097a39dd41257f0b3bdc/aiohttp-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5522ee72f95661e79db691310290c4618b86dff2d9b90baedf343fd7a08bf79", size = 1781816 },
- { url = "https://files.pythonhosted.org/packages/7f/1a/1e256b39179c98d16d53ac62f64bfcfe7c5b2c1e68b83cddd4165854524f/aiohttp-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fbf41a6bbc319a7816ae0f0177c265b62f2a59ad301a0e49b395746eb2a9884", size = 1676692 },
- { url = "https://files.pythonhosted.org/packages/9b/37/f19d2e00efcabb9183b16bd91244de1d9c4ff7bf0fb5b8302e29a78f3286/aiohttp-3.11.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59ee1925b5a5efdf6c4e7be51deee93984d0ac14a6897bd521b498b9916f1544", size = 1619523 },
- { url = "https://files.pythonhosted.org/packages/ae/3c/af50cf5e06b98783fd776f17077f7b7e755d461114af5d6744dc037fc3b0/aiohttp-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24054fce8c6d6f33a3e35d1c603ef1b91bbcba73e3f04a22b4f2f27dac59b347", size = 1644084 },
- { url = "https://files.pythonhosted.org/packages/c0/a6/4e0233b085cbf2b6de573515c1eddde82f1c1f17e69347e32a5a5f2617ff/aiohttp-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:351849aca2c6f814575c1a485c01c17a4240413f960df1bf9f5deb0003c61a53", size = 1648332 },
- { url = "https://files.pythonhosted.org/packages/06/20/7062e76e7817318c421c0f9d7b650fb81aaecf6d2f3a9833805b45ec2ea8/aiohttp-3.11.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:12724f3a211fa243570e601f65a8831372caf1a149d2f1859f68479f07efec3d", size = 1730912 },
- { url = "https://files.pythonhosted.org/packages/6c/1c/ff6ae4b1789894e6faf8a4e260cd3861cad618dc80ad15326789a7765750/aiohttp-3.11.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7ea4490360b605804bea8173d2d086b6c379d6bb22ac434de605a9cbce006e7d", size = 1752619 },
- { url = "https://files.pythonhosted.org/packages/33/58/ddd5cba5ca245c00b04e9d28a7988b0f0eda02de494f8e62ecd2780655c2/aiohttp-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0bf378db07df0a713a1e32381a1b277e62ad106d0dbe17b5479e76ec706d720", size = 1692801 },
- { url = "https://files.pythonhosted.org/packages/b2/fc/32d5e2070b43d3722b7ea65ddc6b03ffa39bcc4b5ab6395a825cde0872ad/aiohttp-3.11.7-cp311-cp311-win32.whl", hash = "sha256:cd8d62cab363dfe713067027a5adb4907515861f1e4ce63e7be810b83668b847", size = 414899 },
- { url = "https://files.pythonhosted.org/packages/ec/7e/50324c6d3df4540f5963def810b9927f220c99864065849a1dfcae77a6ce/aiohttp-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:bf0e6cce113596377cadda4e3ac5fb89f095bd492226e46d91b4baef1dd16f60", size = 440938 },
- { url = "https://files.pythonhosted.org/packages/bf/1e/2e96b2526c590dcb99db0b94ac4f9b927ecc07f94735a8a941dee143d48b/aiohttp-3.11.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4bb7493c3e3a36d3012b8564bd0e2783259ddd7ef3a81a74f0dbfa000fce48b7", size = 702326 },
- { url = "https://files.pythonhosted.org/packages/b5/ce/b5d7f3e68849f1f5e0b85af4ac9080b9d3c0a600857140024603653c2209/aiohttp-3.11.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e143b0ef9cb1a2b4f74f56d4fbe50caa7c2bb93390aff52f9398d21d89bc73ea", size = 461944 },
- { url = "https://files.pythonhosted.org/packages/28/fa/f4d98db1b7f8f0c3f74bdbd6d0d98cfc89984205cd33f1b8ee3f588ee5ad/aiohttp-3.11.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7c58a240260822dc07f6ae32a0293dd5bccd618bb2d0f36d51c5dbd526f89c0", size = 454348 },
- { url = "https://files.pythonhosted.org/packages/04/f0/c238dda5dc9a3d12b76636e2cf0ea475890ac3a1c7e4ff0fd6c3cea2fc2d/aiohttp-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d20cfe63a1c135d26bde8c1d0ea46fd1200884afbc523466d2f1cf517d1fe33", size = 1678795 },
- { url = "https://files.pythonhosted.org/packages/79/ee/3a18f792247e6d95dba13aaedc9dc317c3c6e75f4b88c2dd4b960d20ad2f/aiohttp-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12e4d45847a174f77b2b9919719203769f220058f642b08504cf8b1cf185dacf", size = 1734411 },
- { url = "https://files.pythonhosted.org/packages/f5/79/3eb84243087a9a32cae821622c935107b4b55a5b21b76772e8e6c41092e9/aiohttp-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf4efa2d01f697a7dbd0509891a286a4af0d86902fc594e20e3b1712c28c0106", size = 1788959 },
- { url = "https://files.pythonhosted.org/packages/91/93/ad77782c5edfa17aafc070bef978fbfb8459b2f150595ffb01b559c136f9/aiohttp-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee6a4cdcbf54b8083dc9723cdf5f41f722c00db40ccf9ec2616e27869151129", size = 1687463 },
- { url = "https://files.pythonhosted.org/packages/ba/48/db35bd21b7877efa0be5f28385d8978c55323c5ce7685712e53f3f6c0bd9/aiohttp-3.11.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6095aaf852c34f42e1bd0cf0dc32d1e4b48a90bfb5054abdbb9d64b36acadcb", size = 1618374 },
- { url = "https://files.pythonhosted.org/packages/ba/77/30f87db55c79fd145ed5fd15b92f2e820ce81065d41ae437797aaa550e3b/aiohttp-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1cf03d27885f8c5ebf3993a220cc84fc66375e1e6e812731f51aab2b2748f4a6", size = 1637021 },
- { url = "https://files.pythonhosted.org/packages/af/76/10b188b78ee18d0595af156d6a238bc60f9d8571f0f546027eb7eaf65b25/aiohttp-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1a17f6a230f81eb53282503823f59d61dff14fb2a93847bf0399dc8e87817307", size = 1650792 },
- { url = "https://files.pythonhosted.org/packages/fa/33/4411bbb8ad04c47d0f4c7bd53332aaf350e49469cf6b65b132d4becafe27/aiohttp-3.11.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:481f10a1a45c5f4c4a578bbd74cff22eb64460a6549819242a87a80788461fba", size = 1696248 },
- { url = "https://files.pythonhosted.org/packages/fe/2d/6135d0dc1851a33d3faa937b20fef81340bc95e8310536d4c7f1f8ecc026/aiohttp-3.11.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:db37248535d1ae40735d15bdf26ad43be19e3d93ab3f3dad8507eb0f85bb8124", size = 1729188 },
- { url = "https://files.pythonhosted.org/packages/f5/76/a57ceff577ae26fe9a6f31ac799bc638ecf26e4acdf04295290b9929b349/aiohttp-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d18a8b44ec8502a7fde91446cd9c9b95ce7c49f1eacc1fb2358b8907d4369fd", size = 1690038 },
- { url = "https://files.pythonhosted.org/packages/4b/81/b20e09003b6989a7f23a721692137a6143420a151063c750ab2a04878e3c/aiohttp-3.11.7-cp312-cp312-win32.whl", hash = "sha256:3d1c9c15d3999107cbb9b2d76ca6172e6710a12fda22434ee8bd3f432b7b17e8", size = 409887 },
- { url = "https://files.pythonhosted.org/packages/b7/0b/607c98bff1d07bb21e0c39e7711108ef9ff4f2a361a3ec1ce8dce93623a5/aiohttp-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:018f1b04883a12e77e7fc161934c0f298865d3a484aea536a6a2ca8d909f0ba0", size = 436462 },
- { url = "https://files.pythonhosted.org/packages/7a/53/8d77186c6a33bd087714df18274cdcf6e36fd69a9e841c85b7e81a20b18e/aiohttp-3.11.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:241a6ca732d2766836d62c58c49ca7a93d08251daef0c1e3c850df1d1ca0cbc4", size = 695811 },
- { url = "https://files.pythonhosted.org/packages/62/b6/4c3d107a5406aa6f99f618afea82783f54ce2d9644020f50b9c88f6e823d/aiohttp-3.11.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa3705a8d14de39898da0fbad920b2a37b7547c3afd2a18b9b81f0223b7d0f68", size = 458530 },
- { url = "https://files.pythonhosted.org/packages/d9/05/dbf0bd3966be8ebed3beb4007a2d1356d79af4fe7c93e54f984df6385193/aiohttp-3.11.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9acfc7f652b31853eed3b92095b0acf06fd5597eeea42e939bd23a17137679d5", size = 451371 },
- { url = "https://files.pythonhosted.org/packages/19/6a/2198580314617b6cf9c4b813b84df5832b5f8efedcb8a7e8b321a187233c/aiohttp-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcefcf2915a2dbdbce37e2fc1622129a1918abfe3d06721ce9f6cdac9b6d2eaa", size = 1662905 },
- { url = "https://files.pythonhosted.org/packages/2b/65/08696fd7503f6a6f9f782bd012bf47f36d4ed179a7d8c95dba4726d5cc67/aiohttp-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1f6490dd1862af5aae6cfcf2a274bffa9a5b32a8f5acb519a7ecf5a99a88866", size = 1713794 },
- { url = "https://files.pythonhosted.org/packages/c8/a3/b9a72dce6f15e2efbc09fa67c1067c4f3a3bb05661c0ae7b40799cde02b7/aiohttp-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac5462582d6561c1c1708853a9faf612ff4e5ea5e679e99be36143d6eabd8e", size = 1770757 },
- { url = "https://files.pythonhosted.org/packages/78/7e/8fb371b5f8c4c1eaa0d0a50750c0dd68059f86794aeb36919644815486f5/aiohttp-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a6309005acc4b2bcc577ba3b9169fea52638709ffacbd071f3503264620da", size = 1673136 },
- { url = "https://files.pythonhosted.org/packages/2f/0f/09685d13d2c7634cb808868ea29c170d4dcde4215a4a90fb86491cd3ae25/aiohttp-3.11.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b973cce96793725ef63eb449adfb74f99c043c718acb76e0d2a447ae369962", size = 1600370 },
- { url = "https://files.pythonhosted.org/packages/00/2e/18fd38b117f9b3a375166ccb70ed43cf7e3dfe2cc947139acc15feefc5a2/aiohttp-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ce91a24aac80de6be8512fb1c4838a9881aa713f44f4e91dd7bb3b34061b497d", size = 1613459 },
- { url = "https://files.pythonhosted.org/packages/2c/94/10a82abc680d753be33506be699aaa330152ecc4f316eaf081f996ee56c2/aiohttp-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:875f7100ce0e74af51d4139495eec4025affa1a605280f23990b6434b81df1bd", size = 1613924 },
- { url = "https://files.pythonhosted.org/packages/e9/58/897c0561f5c522dda6e173192f1e4f10144e1a7126096f17a3f12b7aa168/aiohttp-3.11.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c171fc35d3174bbf4787381716564042a4cbc008824d8195eede3d9b938e29a8", size = 1681164 },
- { url = "https://files.pythonhosted.org/packages/8b/8b/3a48b1cdafa612679d976274355f6a822de90b85d7dba55654ecfb01c979/aiohttp-3.11.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ee9afa1b0d2293c46954f47f33e150798ad68b78925e3710044e0d67a9487791", size = 1712139 },
- { url = "https://files.pythonhosted.org/packages/aa/9d/70ab5b4dd7900db04af72840e033aee06e472b1343e372ea256ed675511c/aiohttp-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8360c7cc620abb320e1b8d603c39095101391a82b1d0be05fb2225471c9c5c52", size = 1667446 },
- { url = "https://files.pythonhosted.org/packages/cb/98/b5fbcc8f6056f0c56001c75227e6b7ca9ee4f2e5572feca82ff3d65d485d/aiohttp-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7a9318da4b4ada9a67c1dd84d1c0834123081e746bee311a16bb449f363d965e", size = 408689 },
- { url = "https://files.pythonhosted.org/packages/ef/07/4d1504577fa6349dd2e3839e89fb56e5dee38d64efe3d4366e9fcfda0cdb/aiohttp-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:fc6da202068e0a268e298d7cd09b6e9f3997736cd9b060e2750963754552a0a9", size = 434809 },
+ { url = "https://files.pythonhosted.org/packages/34/ae/e8806a9f054e15f1d18b04db75c23ec38ec954a10c0a68d3bd275d7e8be3/aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76", size = 708624 },
+ { url = "https://files.pythonhosted.org/packages/c7/e0/313ef1a333fb4d58d0c55a6acb3cd772f5d7756604b455181049e222c020/aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538", size = 468507 },
+ { url = "https://files.pythonhosted.org/packages/a9/60/03455476bf1f467e5b4a32a465c450548b2ce724eec39d69f737191f936a/aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204", size = 455571 },
+ { url = "https://files.pythonhosted.org/packages/be/f9/469588603bd75bf02c8ffb8c8a0d4b217eed446b49d4a767684685aa33fd/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9", size = 1685694 },
+ { url = "https://files.pythonhosted.org/packages/88/b9/1b7fa43faf6c8616fa94c568dc1309ffee2b6b68b04ac268e5d64b738688/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03", size = 1743660 },
+ { url = "https://files.pythonhosted.org/packages/2a/8b/0248d19dbb16b67222e75f6aecedd014656225733157e5afaf6a6a07e2e8/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287", size = 1785421 },
+ { url = "https://files.pythonhosted.org/packages/c4/11/f478e071815a46ca0a5ae974651ff0c7a35898c55063305a896e58aa1247/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e", size = 1675145 },
+ { url = "https://files.pythonhosted.org/packages/26/5d/284d182fecbb5075ae10153ff7374f57314c93a8681666600e3a9e09c505/aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665", size = 1619804 },
+ { url = "https://files.pythonhosted.org/packages/1b/78/980064c2ad685c64ce0e8aeeb7ef1e53f43c5b005edcd7d32e60809c4992/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b", size = 1654007 },
+ { url = "https://files.pythonhosted.org/packages/21/8d/9e658d63b1438ad42b96f94da227f2e2c1d5c6001c9e8ffcc0bfb22e9105/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34", size = 1650022 },
+ { url = "https://files.pythonhosted.org/packages/85/fd/a032bf7f2755c2df4f87f9effa34ccc1ef5cea465377dbaeef93bb56bbd6/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d", size = 1732899 },
+ { url = "https://files.pythonhosted.org/packages/c5/0c/c2b85fde167dd440c7ba50af2aac20b5a5666392b174df54c00f888c5a75/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2", size = 1755142 },
+ { url = "https://files.pythonhosted.org/packages/bc/78/91ae1a3b3b3bed8b893c5d69c07023e151b1c95d79544ad04cf68f596c2f/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773", size = 1692736 },
+ { url = "https://files.pythonhosted.org/packages/77/89/a7ef9c4b4cdb546fcc650ca7f7395aaffbd267f0e1f648a436bec33c9b95/aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62", size = 416418 },
+ { url = "https://files.pythonhosted.org/packages/fc/db/2192489a8a51b52e06627506f8ac8df69ee221de88ab9bdea77aa793aa6a/aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac", size = 442509 },
+ { url = "https://files.pythonhosted.org/packages/69/cf/4bda538c502f9738d6b95ada11603c05ec260807246e15e869fc3ec5de97/aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886", size = 704666 },
+ { url = "https://files.pythonhosted.org/packages/46/7b/87fcef2cad2fad420ca77bef981e815df6904047d0a1bd6aeded1b0d1d66/aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2", size = 464057 },
+ { url = "https://files.pythonhosted.org/packages/5a/a6/789e1f17a1b6f4a38939fbc39d29e1d960d5f89f73d0629a939410171bc0/aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c", size = 455996 },
+ { url = "https://files.pythonhosted.org/packages/b7/dd/485061fbfef33165ce7320db36e530cd7116ee1098e9c3774d15a732b3fd/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a", size = 1682367 },
+ { url = "https://files.pythonhosted.org/packages/e9/d7/9ec5b3ea9ae215c311d88b2093e8da17e67b8856673e4166c994e117ee3e/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231", size = 1736989 },
+ { url = "https://files.pythonhosted.org/packages/d6/fb/ea94927f7bfe1d86178c9d3e0a8c54f651a0a655214cce930b3c679b8f64/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e", size = 1793265 },
+ { url = "https://files.pythonhosted.org/packages/40/7f/6de218084f9b653026bd7063cd8045123a7ba90c25176465f266976d8c82/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8", size = 1691841 },
+ { url = "https://files.pythonhosted.org/packages/77/e2/992f43d87831cbddb6b09c57ab55499332f60ad6fdbf438ff4419c2925fc/aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8", size = 1619317 },
+ { url = "https://files.pythonhosted.org/packages/96/74/879b23cdd816db4133325a201287c95bef4ce669acde37f8f1b8669e1755/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c", size = 1641416 },
+ { url = "https://files.pythonhosted.org/packages/30/98/b123f6b15d87c54e58fd7ae3558ff594f898d7f30a90899718f3215ad328/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab", size = 1646514 },
+ { url = "https://files.pythonhosted.org/packages/d7/38/257fda3dc99d6978ab943141d5165ec74fd4b4164baa15e9c66fa21da86b/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da", size = 1702095 },
+ { url = "https://files.pythonhosted.org/packages/0c/f4/ddab089053f9fb96654df5505c0a69bde093214b3c3454f6bfdb1845f558/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853", size = 1734611 },
+ { url = "https://files.pythonhosted.org/packages/c3/d6/f30b2bc520c38c8aa4657ed953186e535ae84abe55c08d0f70acd72ff577/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e", size = 1694576 },
+ { url = "https://files.pythonhosted.org/packages/bc/97/b0a88c3f4c6d0020b34045ee6d954058abc870814f6e310c4c9b74254116/aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600", size = 411363 },
+ { url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666 },
+ { url = "https://files.pythonhosted.org/packages/49/d1/d8af164f400bad432b63e1ac857d74a09311a8334b0481f2f64b158b50eb/aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9", size = 697982 },
+ { url = "https://files.pythonhosted.org/packages/92/d1/faad3bf9fa4bfd26b95c69fc2e98937d52b1ff44f7e28131855a98d23a17/aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194", size = 460662 },
+ { url = "https://files.pythonhosted.org/packages/db/61/0d71cc66d63909dabc4590f74eba71f91873a77ea52424401c2498d47536/aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f", size = 452950 },
+ { url = "https://files.pythonhosted.org/packages/07/db/6d04bc7fd92784900704e16b745484ef45b77bd04e25f58f6febaadf7983/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104", size = 1665178 },
+ { url = "https://files.pythonhosted.org/packages/54/5c/e95ade9ae29f375411884d9fd98e50535bf9fe316c9feb0f30cd2ac8f508/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff", size = 1717939 },
+ { url = "https://files.pythonhosted.org/packages/6f/1c/1e7d5c5daea9e409ed70f7986001b8c9e3a49a50b28404498d30860edab6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3", size = 1775125 },
+ { url = "https://files.pythonhosted.org/packages/5d/66/890987e44f7d2f33a130e37e01a164168e6aff06fce15217b6eaf14df4f6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1", size = 1677176 },
+ { url = "https://files.pythonhosted.org/packages/8f/dc/e2ba57d7a52df6cdf1072fd5fa9c6301a68e1cd67415f189805d3eeb031d/aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4", size = 1603192 },
+ { url = "https://files.pythonhosted.org/packages/6c/9e/8d08a57de79ca3a358da449405555e668f2c8871a7777ecd2f0e3912c272/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d", size = 1618296 },
+ { url = "https://files.pythonhosted.org/packages/56/51/89822e3ec72db352c32e7fc1c690370e24e231837d9abd056490f3a49886/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87", size = 1616524 },
+ { url = "https://files.pythonhosted.org/packages/2c/fa/e2e6d9398f462ffaa095e84717c1732916a57f1814502929ed67dd7568ef/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2", size = 1685471 },
+ { url = "https://files.pythonhosted.org/packages/ae/5f/6bb976e619ca28a052e2c0ca7b0251ccd893f93d7c24a96abea38e332bf6/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12", size = 1715312 },
+ { url = "https://files.pythonhosted.org/packages/79/c1/756a7e65aa087c7fac724d6c4c038f2faaa2a42fe56dbc1dd62a33ca7213/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5", size = 1672783 },
+ { url = "https://files.pythonhosted.org/packages/73/ba/a6190ebb02176c7f75e6308da31f5d49f6477b651a3dcfaaaca865a298e2/aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d", size = 410229 },
+ { url = "https://files.pythonhosted.org/packages/b8/62/c9fa5bafe03186a0e4699150a7fed9b1e73240996d0d2f0e5f70f3fdf471/aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99", size = 436081 },
]
[[package]]
name = "aiosignal"
-version = "1.3.1"
+version = "1.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 },
+ { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
]
[[package]]
@@ -95,15 +95,16 @@ wheels = [
[[package]]
name = "anyio"
-version = "4.6.2.post1"
+version = "4.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "sniffio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
+sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
+ { url = "https://files.pythonhosted.org/packages/a0/7a/4daaf3b6c08ad7ceffea4634ec206faeff697526421c20f07628c7372156/anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352", size = 93052 },
]
[[package]]
@@ -130,11 +131,11 @@ wheels = [
[[package]]
name = "attrs"
-version = "24.2.0"
+version = "24.3.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 }
+sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 },
+ { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 },
]
[[package]]
@@ -148,11 +149,11 @@ wheels = [
[[package]]
name = "certifi"
-version = "2024.8.30"
+version = "2024.12.14"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 },
+ { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 },
]
[[package]]
@@ -287,50 +288,50 @@ wheels = [
[[package]]
name = "coverage"
-version = "7.6.8"
+version = "7.6.9"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ab/75/aecfd0a3adbec6e45753976bc2a9fed62b42cea9a206d10fd29244a77953/coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc", size = 801425 }
+sdist = { url = "https://files.pythonhosted.org/packages/5b/d2/c25011f4d036cf7e8acbbee07a8e09e9018390aee25ba085596c4b83d510/coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", size = 801710 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ab/9f/e98211980f6e2f439e251737482aa77906c9b9c507824c71a2ce7eea0402/coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4", size = 207093 },
- { url = "https://files.pythonhosted.org/packages/fd/c7/8bab83fb9c20f7f8163c5a20dcb62d591b906a214a6dc6b07413074afc80/coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94", size = 207536 },
- { url = "https://files.pythonhosted.org/packages/1e/d6/00243df625f1b282bb25c83ce153ae2c06f8e7a796a8d833e7235337b4d9/coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4", size = 239482 },
- { url = "https://files.pythonhosted.org/packages/1e/07/faf04b3eeb55ffc2a6f24b65dffe6e0359ec3b283e6efb5050ea0707446f/coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1", size = 236886 },
- { url = "https://files.pythonhosted.org/packages/43/23/c79e497bf4d8fcacd316bebe1d559c765485b8ec23ac4e23025be6bfce09/coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb", size = 238749 },
- { url = "https://files.pythonhosted.org/packages/b5/e5/791bae13be3c6451e32ef7af1192e711c6a319f3c597e9b218d148fd0633/coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8", size = 237679 },
- { url = "https://files.pythonhosted.org/packages/05/c6/bbfdfb03aada601fb8993ced17468c8c8e0b4aafb3097026e680fabb7ce1/coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a", size = 236317 },
- { url = "https://files.pythonhosted.org/packages/67/f9/f8e5a4b2ce96d1b0e83ae6246369eb8437001dc80ec03bb51c87ff557cd8/coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0", size = 237084 },
- { url = "https://files.pythonhosted.org/packages/f0/70/b05328901e4debe76e033717e1452d00246c458c44e9dbd893e7619c2967/coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801", size = 209638 },
- { url = "https://files.pythonhosted.org/packages/70/55/1efa24f960a2fa9fbc44a9523d3f3c50ceb94dd1e8cd732168ab2dc41b07/coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9", size = 210506 },
- { url = "https://files.pythonhosted.org/packages/76/ce/3edf581c8fe429ed8ced6e6d9ac693c25975ef9093413276dab6ed68a80a/coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee", size = 207285 },
- { url = "https://files.pythonhosted.org/packages/09/9c/cf102ab046c9cf8895c3f7aadcde6f489a4b2ec326757e8c6e6581829b5e/coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a", size = 207522 },
- { url = "https://files.pythonhosted.org/packages/39/06/42aa6dd13dbfca72e1fd8ffccadbc921b6e75db34545ebab4d955d1e7ad3/coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d", size = 240543 },
- { url = "https://files.pythonhosted.org/packages/a0/20/2932971dc215adeca8eeff446266a7fef17a0c238e881ffedebe7bfa0669/coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb", size = 237577 },
- { url = "https://files.pythonhosted.org/packages/ac/85/4323ece0cd5452c9522f4b6e5cc461e6c7149a4b1887c9e7a8b1f4e51146/coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649", size = 239646 },
- { url = "https://files.pythonhosted.org/packages/77/52/b2537487d8f36241e518e84db6f79e26bc3343b14844366e35b090fae0d4/coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787", size = 239128 },
- { url = "https://files.pythonhosted.org/packages/7c/99/7f007762012186547d0ecc3d328da6b6f31a8c99f05dc1e13dcd929918cd/coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c", size = 237434 },
- { url = "https://files.pythonhosted.org/packages/97/53/e9b5cf0682a1cab9352adfac73caae0d77ae1d65abc88975d510f7816389/coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443", size = 239095 },
- { url = "https://files.pythonhosted.org/packages/0c/50/054f0b464fbae0483217186478eefa2e7df3a79917ed7f1d430b6da2cf0d/coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad", size = 209895 },
- { url = "https://files.pythonhosted.org/packages/df/d0/09ba870360a27ecf09e177ca2ff59d4337fc7197b456f22ceff85cffcfa5/coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4", size = 210684 },
- { url = "https://files.pythonhosted.org/packages/9a/84/6f0ccf94a098ac3d6d6f236bd3905eeac049a9e0efcd9a63d4feca37ac4b/coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb", size = 207313 },
- { url = "https://files.pythonhosted.org/packages/db/2b/e3b3a3a12ebec738c545897ac9f314620470fcbc368cdac88cf14974ba20/coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63", size = 207574 },
- { url = "https://files.pythonhosted.org/packages/db/c0/5bf95d42b6a8d21dfce5025ce187f15db57d6460a59b67a95fe8728162f1/coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365", size = 240090 },
- { url = "https://files.pythonhosted.org/packages/57/b8/d6fd17d1a8e2b0e1a4e8b9cb1f0f261afd422570735899759c0584236916/coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002", size = 237237 },
- { url = "https://files.pythonhosted.org/packages/d4/e4/a91e9bb46809c8b63e68fc5db5c4d567d3423b6691d049a4f950e38fbe9d/coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3", size = 239225 },
- { url = "https://files.pythonhosted.org/packages/31/9c/9b99b0591ec4555b7292d271e005f27b465388ce166056c435b288db6a69/coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022", size = 238888 },
- { url = "https://files.pythonhosted.org/packages/a6/85/285c2df9a04bc7c31f21fd9d4a24d19e040ec5e2ff06e572af1f6514c9e7/coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e", size = 236974 },
- { url = "https://files.pythonhosted.org/packages/cb/a1/95ec8522206f76cdca033bf8bb61fff56429fb414835fc4d34651dfd29fc/coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b", size = 238815 },
- { url = "https://files.pythonhosted.org/packages/8d/ac/687e9ba5e6d0979e9dab5c02e01c4f24ac58260ef82d88d3b433b3f84f1e/coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146", size = 209957 },
- { url = "https://files.pythonhosted.org/packages/2f/a3/b61cc8e3fcf075293fb0f3dee405748453c5ba28ac02ceb4a87f52bdb105/coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28", size = 210711 },
- { url = "https://files.pythonhosted.org/packages/ee/4b/891c8b9acf1b62c85e4a71dac142ab9284e8347409b7355de02e3f38306f/coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d", size = 208053 },
- { url = "https://files.pythonhosted.org/packages/18/a9/9e330409b291cc002723d339346452800e78df1ce50774ca439ade1d374f/coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451", size = 208329 },
- { url = "https://files.pythonhosted.org/packages/9c/0d/33635fd429f6589c6e1cdfc7bf581aefe4c1792fbff06383f9d37f59db60/coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764", size = 251052 },
- { url = "https://files.pythonhosted.org/packages/23/32/8a08da0e46f3830bbb9a5b40614241b2e700f27a9c2889f53122486443ed/coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf", size = 246765 },
- { url = "https://files.pythonhosted.org/packages/56/3f/3b86303d2c14350fdb1c6c4dbf9bc76000af2382f42ca1d4d99c6317666e/coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5", size = 249125 },
- { url = "https://files.pythonhosted.org/packages/36/cb/c4f081b9023f9fd8646dbc4ef77be0df090263e8f66f4ea47681e0dc2cff/coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4", size = 248615 },
- { url = "https://files.pythonhosted.org/packages/32/ee/53bdbf67760928c44b57b2c28a8c0a4bf544f85a9ee129a63ba5c78fdee4/coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83", size = 246507 },
- { url = "https://files.pythonhosted.org/packages/57/49/5a57910bd0af6d8e802b4ca65292576d19b54b49f81577fd898505dee075/coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b", size = 247785 },
- { url = "https://files.pythonhosted.org/packages/bd/37/e450c9f6b297c79bb9858407396ed3e084dcc22990dd110ab01d5ceb9770/coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71", size = 210605 },
- { url = "https://files.pythonhosted.org/packages/44/79/7d0c7dd237c6905018e2936cd1055fe1d42e7eba2ebab3c00f4aad2a27d7/coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc", size = 211777 },
+ { url = "https://files.pythonhosted.org/packages/b1/91/b3dc2f7f38b5cca1236ab6bbb03e84046dd887707b4ec1db2baa47493b3b/coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", size = 207133 },
+ { url = "https://files.pythonhosted.org/packages/0d/2b/53fd6cb34d443429a92b3ec737f4953627e38b3bee2a67a3c03425ba8573/coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", size = 207577 },
+ { url = "https://files.pythonhosted.org/packages/74/f2/68edb1e6826f980a124f21ea5be0d324180bf11de6fd1defcf9604f76df0/coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", size = 239524 },
+ { url = "https://files.pythonhosted.org/packages/d3/83/8fec0ee68c2c4a5ab5f0f8527277f84ed6f2bd1310ae8a19d0c5532253ab/coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", size = 236925 },
+ { url = "https://files.pythonhosted.org/packages/8b/20/8f50e7c7ad271144afbc2c1c6ec5541a8c81773f59352f8db544cad1a0ec/coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", size = 238792 },
+ { url = "https://files.pythonhosted.org/packages/6f/62/4ac2e5ad9e7a5c9ec351f38947528e11541f1f00e8a0cdce56f1ba7ae301/coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", size = 237682 },
+ { url = "https://files.pythonhosted.org/packages/58/2f/9d2203f012f3b0533c73336c74134b608742be1ce475a5c72012573cfbb4/coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", size = 236310 },
+ { url = "https://files.pythonhosted.org/packages/33/6d/31f6ab0b4f0f781636075f757eb02141ea1b34466d9d1526dbc586ed7078/coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", size = 237096 },
+ { url = "https://files.pythonhosted.org/packages/7d/fb/e14c38adebbda9ed8b5f7f8e03340ac05d68d27b24397f8d47478927a333/coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", size = 209682 },
+ { url = "https://files.pythonhosted.org/packages/a4/11/a782af39b019066af83fdc0e8825faaccbe9d7b19a803ddb753114b429cc/coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", size = 210542 },
+ { url = "https://files.pythonhosted.org/packages/60/52/b16af8989a2daf0f80a88522bd8e8eed90b5fcbdecf02a6888f3e80f6ba7/coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", size = 207325 },
+ { url = "https://files.pythonhosted.org/packages/0f/79/6b7826fca8846c1216a113227b9f114ac3e6eacf168b4adcad0cb974aaca/coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", size = 207563 },
+ { url = "https://files.pythonhosted.org/packages/a7/07/0bc73da0ccaf45d0d64ef86d33b7d7fdeef84b4c44bf6b85fb12c215c5a6/coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", size = 240580 },
+ { url = "https://files.pythonhosted.org/packages/71/8a/9761f409910961647d892454687cedbaccb99aae828f49486734a82ede6e/coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3", size = 237613 },
+ { url = "https://files.pythonhosted.org/packages/8b/10/ee7d696a17ac94f32f2dbda1e17e730bf798ae9931aec1fc01c1944cd4de/coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", size = 239684 },
+ { url = "https://files.pythonhosted.org/packages/16/60/aa1066040d3c52fff051243c2d6ccda264da72dc6d199d047624d395b2b2/coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", size = 239112 },
+ { url = "https://files.pythonhosted.org/packages/4e/e5/69f35344c6f932ba9028bf168d14a79fedb0dd4849b796d43c81ce75a3c9/coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", size = 237428 },
+ { url = "https://files.pythonhosted.org/packages/32/20/adc895523c4a28f63441b8ac645abd74f9bdd499d2d175bef5b41fc7f92d/coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", size = 239098 },
+ { url = "https://files.pythonhosted.org/packages/a9/a6/e0e74230c9bb3549ec8ffc137cfd16ea5d56e993d6bffed2218bff6187e3/coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", size = 209940 },
+ { url = "https://files.pythonhosted.org/packages/3e/18/cb5b88349d4aa2f41ec78d65f92ea32572b30b3f55bc2b70e87578b8f434/coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", size = 210726 },
+ { url = "https://files.pythonhosted.org/packages/35/26/9abab6539d2191dbda2ce8c97b67d74cbfc966cc5b25abb880ffc7c459bc/coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", size = 207356 },
+ { url = "https://files.pythonhosted.org/packages/44/da/d49f19402240c93453f606e660a6676a2a1fbbaa6870cc23207790aa9697/coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", size = 207614 },
+ { url = "https://files.pythonhosted.org/packages/da/e6/93bb9bf85497816082ec8da6124c25efa2052bd4c887dd3b317b91990c9e/coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", size = 240129 },
+ { url = "https://files.pythonhosted.org/packages/df/65/6a824b9406fe066835c1274a9949e06f084d3e605eb1a602727a27ec2fe3/coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", size = 237276 },
+ { url = "https://files.pythonhosted.org/packages/9f/79/6c7a800913a9dd23ac8c8da133ebb556771a5a3d4df36b46767b1baffd35/coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", size = 239267 },
+ { url = "https://files.pythonhosted.org/packages/57/e7/834d530293fdc8a63ba8ff70033d5182022e569eceb9aec7fc716b678a39/coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", size = 238887 },
+ { url = "https://files.pythonhosted.org/packages/15/05/ec9d6080852984f7163c96984444e7cd98b338fd045b191064f943ee1c08/coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", size = 236970 },
+ { url = "https://files.pythonhosted.org/packages/0a/d8/775937670b93156aec29f694ce37f56214ed7597e1a75b4083ee4c32121c/coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", size = 238831 },
+ { url = "https://files.pythonhosted.org/packages/f4/58/88551cb7fdd5ec98cb6044e8814e38583436b14040a5ece15349c44c8f7c/coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", size = 210000 },
+ { url = "https://files.pythonhosted.org/packages/b7/12/cfbf49b95120872785ff8d56ab1c7fe3970a65e35010c311d7dd35c5fd00/coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", size = 210753 },
+ { url = "https://files.pythonhosted.org/packages/7c/68/c1cb31445599b04bde21cbbaa6d21b47c5823cdfef99eae470dfce49c35a/coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", size = 208091 },
+ { url = "https://files.pythonhosted.org/packages/11/73/84b02c6b19c4a11eb2d5b5eabe926fb26c21c080e0852f5e5a4f01165f9e/coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", size = 208369 },
+ { url = "https://files.pythonhosted.org/packages/de/e0/ae5d878b72ff26df2e994a5c5b1c1f6a7507d976b23beecb1ed4c85411ef/coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", size = 251089 },
+ { url = "https://files.pythonhosted.org/packages/ab/9c/0aaac011aef95a93ef3cb2fba3fde30bc7e68a6635199ed469b1f5ea355a/coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", size = 246806 },
+ { url = "https://files.pythonhosted.org/packages/f8/19/4d5d3ae66938a7dcb2f58cef3fa5386f838f469575b0bb568c8cc9e3a33d/coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", size = 249164 },
+ { url = "https://files.pythonhosted.org/packages/b3/0b/4ee8a7821f682af9ad440ae3c1e379da89a998883271f088102d7ca2473d/coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", size = 248642 },
+ { url = "https://files.pythonhosted.org/packages/8a/12/36ff1d52be18a16b4700f561852e7afd8df56363a5edcfb04cf26a0e19e0/coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", size = 246516 },
+ { url = "https://files.pythonhosted.org/packages/43/d0/8e258f6c3a527c1655602f4f576215e055ac704de2d101710a71a2affac2/coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", size = 247783 },
+ { url = "https://files.pythonhosted.org/packages/a9/0d/1e4a48d289429d38aae3babdfcadbf35ca36bdcf3efc8f09b550a845bdb5/coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", size = 210646 },
+ { url = "https://files.pythonhosted.org/packages/26/74/b0729f196f328ac55e42b1e22ec2f16d8bcafe4b8158a26ec9f1cdd1d93e/coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", size = 211815 },
]
[package.optional-dependencies]
@@ -340,31 +341,33 @@ toml = [
[[package]]
name = "cryptography"
-version = "43.0.3"
+version = "44.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 }
+sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 },
- { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 },
- { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 },
- { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 },
- { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 },
- { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 },
- { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 },
- { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 },
- { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 },
- { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 },
- { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 },
- { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 },
- { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 },
- { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 },
- { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 },
- { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 },
- { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 },
- { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 },
+ { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 },
+ { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 },
+ { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 },
+ { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 },
+ { url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 },
+ { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 },
+ { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 },
+ { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 },
+ { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 },
+ { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 },
+ { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 },
+ { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 },
+ { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 },
+ { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 },
+ { url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 },
+ { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 },
+ { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 },
+ { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 },
+ { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 },
+ { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 },
]
[[package]]
@@ -700,30 +703,30 @@ wheels = [
[[package]]
name = "mypy"
-version = "1.13.0"
+version = "1.14.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
+sdist = { url = "https://files.pythonhosted.org/packages/8c/7b/08046ef9330735f536a09a2e31b00f42bccdb2795dcd979636ba43bb2d63/mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6", size = 3215684 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 },
- { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 },
- { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 },
- { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 },
- { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 },
- { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
- { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
- { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
- { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
- { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
- { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 },
- { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 },
- { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 },
- { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 },
- { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 },
- { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
+ { url = "https://files.pythonhosted.org/packages/34/c1/b9dd3e955953aec1c728992545b7877c9f6fa742a623ce4c200da0f62540/mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a", size = 11121032 },
+ { url = "https://files.pythonhosted.org/packages/ee/96/c52d5d516819ab95bf41f4a1ada828a3decc302f8c152ff4fc5feb0e4529/mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc", size = 10286294 },
+ { url = "https://files.pythonhosted.org/packages/69/2c/3dbe51877a24daa467f8d8631f9ffd1aabbf0f6d9367a01c44a59df81fe0/mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015", size = 12746528 },
+ { url = "https://files.pythonhosted.org/packages/a1/a8/eb20cde4ba9c4c3e20d958918a7c5d92210f4d1a0200c27de9a641f70996/mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb", size = 12883489 },
+ { url = "https://files.pythonhosted.org/packages/91/17/a1fc6c70f31d52c99299320cf81c3cb2c6b91ec7269414e0718a6d138e34/mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc", size = 9780113 },
+ { url = "https://files.pythonhosted.org/packages/fe/d8/0e72175ee0253217f5c44524f5e95251c02e95ba9749fb87b0e2074d203a/mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd", size = 11269011 },
+ { url = "https://files.pythonhosted.org/packages/e9/6d/4ea13839dabe5db588dc6a1b766da16f420d33cf118a7b7172cdf6c7fcb2/mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1", size = 10253076 },
+ { url = "https://files.pythonhosted.org/packages/3e/38/7db2c5d0f4d290e998f7a52b2e2616c7bbad96b8e04278ab09d11978a29e/mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63", size = 12862786 },
+ { url = "https://files.pythonhosted.org/packages/bf/4b/62d59c801b34141040989949c2b5c157d0408b45357335d3ec5b2845b0f6/mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d", size = 12971568 },
+ { url = "https://files.pythonhosted.org/packages/f1/9c/e0f281b32d70c87b9e4d2939e302b1ff77ada4d7b0f2fb32890c144bc1d6/mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba", size = 9879477 },
+ { url = "https://files.pythonhosted.org/packages/13/33/8380efd0ebdfdfac7fc0bf065f03a049800ca1e6c296ec1afc634340d992/mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741", size = 11251509 },
+ { url = "https://files.pythonhosted.org/packages/15/6d/4e1c21c60fee11af7d8e4f2902a29886d1387d6a836be16229eb3982a963/mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7", size = 10244282 },
+ { url = "https://files.pythonhosted.org/packages/8b/cf/7a8ae5c0161edae15d25c2c67c68ce8b150cbdc45aefc13a8be271ee80b2/mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8", size = 12867676 },
+ { url = "https://files.pythonhosted.org/packages/9c/d0/71f7bbdcc7cfd0f2892db5b13b1e8857673f2cc9e0c30e3e4340523dc186/mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc", size = 12964189 },
+ { url = "https://files.pythonhosted.org/packages/a7/40/fb4ad65d6d5f8c51396ecf6305ec0269b66013a5bf02d0e9528053640b4a/mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f", size = 9888247 },
+ { url = "https://files.pythonhosted.org/packages/39/32/0214608af400cdf8f5102144bb8af10d880675c65ed0b58f7e0e77175d50/mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab", size = 2752803 },
]
[[package]]
@@ -870,59 +873,59 @@ wheels = [
[[package]]
name = "propcache"
-version = "0.2.0"
+version = "0.2.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 }
+sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e0/1c/71eec730e12aec6511e702ad0cd73c2872eccb7cad39de8ba3ba9de693ef/propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", size = 80811 },
- { url = "https://files.pythonhosted.org/packages/89/c3/7e94009f9a4934c48a371632197406a8860b9f08e3f7f7d922ab69e57a41/propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", size = 46365 },
- { url = "https://files.pythonhosted.org/packages/c0/1d/c700d16d1d6903aeab28372fe9999762f074b80b96a0ccc953175b858743/propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", size = 45602 },
- { url = "https://files.pythonhosted.org/packages/2e/5e/4a3e96380805bf742712e39a4534689f4cddf5fa2d3a93f22e9fd8001b23/propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", size = 236161 },
- { url = "https://files.pythonhosted.org/packages/a5/85/90132481183d1436dff6e29f4fa81b891afb6cb89a7306f32ac500a25932/propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", size = 244938 },
- { url = "https://files.pythonhosted.org/packages/4a/89/c893533cb45c79c970834274e2d0f6d64383ec740be631b6a0a1d2b4ddc0/propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", size = 243576 },
- { url = "https://files.pythonhosted.org/packages/8c/56/98c2054c8526331a05f205bf45cbb2cda4e58e56df70e76d6a509e5d6ec6/propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", size = 236011 },
- { url = "https://files.pythonhosted.org/packages/2d/0c/8b8b9f8a6e1abd869c0fa79b907228e7abb966919047d294ef5df0d136cf/propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504", size = 224834 },
- { url = "https://files.pythonhosted.org/packages/18/bb/397d05a7298b7711b90e13108db697732325cafdcd8484c894885c1bf109/propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", size = 224946 },
- { url = "https://files.pythonhosted.org/packages/25/19/4fc08dac19297ac58135c03770b42377be211622fd0147f015f78d47cd31/propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", size = 217280 },
- { url = "https://files.pythonhosted.org/packages/7e/76/c79276a43df2096ce2aba07ce47576832b1174c0c480fe6b04bd70120e59/propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", size = 220088 },
- { url = "https://files.pythonhosted.org/packages/c3/9a/8a8cf428a91b1336b883f09c8b884e1734c87f724d74b917129a24fe2093/propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", size = 233008 },
- { url = "https://files.pythonhosted.org/packages/25/7b/768a8969abd447d5f0f3333df85c6a5d94982a1bc9a89c53c154bf7a8b11/propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", size = 237719 },
- { url = "https://files.pythonhosted.org/packages/ed/0d/e5d68ccc7976ef8b57d80613ac07bbaf0614d43f4750cf953f0168ef114f/propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", size = 227729 },
- { url = "https://files.pythonhosted.org/packages/05/64/17eb2796e2d1c3d0c431dc5f40078d7282f4645af0bb4da9097fbb628c6c/propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", size = 40473 },
- { url = "https://files.pythonhosted.org/packages/83/c5/e89fc428ccdc897ade08cd7605f174c69390147526627a7650fb883e0cd0/propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", size = 44921 },
- { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 },
- { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 },
- { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 },
- { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 },
- { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 },
- { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 },
- { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 },
- { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 },
- { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 },
- { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 },
- { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 },
- { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 },
- { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 },
- { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 },
- { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 },
- { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 },
- { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 },
- { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 },
- { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 },
- { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 },
- { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 },
- { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 },
- { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 },
- { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 },
- { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 },
- { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 },
- { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 },
- { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 },
- { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 },
- { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 },
- { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 },
- { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 },
- { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 },
+ { url = "https://files.pythonhosted.org/packages/bc/0f/2913b6791ebefb2b25b4efd4bb2299c985e09786b9f5b19184a88e5778dd/propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", size = 79297 },
+ { url = "https://files.pythonhosted.org/packages/cf/73/af2053aeccd40b05d6e19058419ac77674daecdd32478088b79375b9ab54/propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", size = 45611 },
+ { url = "https://files.pythonhosted.org/packages/3c/09/8386115ba7775ea3b9537730e8cf718d83bbf95bffe30757ccf37ec4e5da/propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", size = 45146 },
+ { url = "https://files.pythonhosted.org/packages/03/7a/793aa12f0537b2e520bf09f4c6833706b63170a211ad042ca71cbf79d9cb/propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", size = 232136 },
+ { url = "https://files.pythonhosted.org/packages/f1/38/b921b3168d72111769f648314100558c2ea1d52eb3d1ba7ea5c4aa6f9848/propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", size = 239706 },
+ { url = "https://files.pythonhosted.org/packages/14/29/4636f500c69b5edea7786db3c34eb6166f3384b905665ce312a6e42c720c/propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", size = 238531 },
+ { url = "https://files.pythonhosted.org/packages/85/14/01fe53580a8e1734ebb704a3482b7829a0ef4ea68d356141cf0994d9659b/propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", size = 231063 },
+ { url = "https://files.pythonhosted.org/packages/33/5c/1d961299f3c3b8438301ccfbff0143b69afcc30c05fa28673cface692305/propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", size = 220134 },
+ { url = "https://files.pythonhosted.org/packages/00/d0/ed735e76db279ba67a7d3b45ba4c654e7b02bc2f8050671ec365d8665e21/propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", size = 220009 },
+ { url = "https://files.pythonhosted.org/packages/75/90/ee8fab7304ad6533872fee982cfff5a53b63d095d78140827d93de22e2d4/propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", size = 212199 },
+ { url = "https://files.pythonhosted.org/packages/eb/ec/977ffaf1664f82e90737275873461695d4c9407d52abc2f3c3e24716da13/propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", size = 214827 },
+ { url = "https://files.pythonhosted.org/packages/57/48/031fb87ab6081764054821a71b71942161619549396224cbb242922525e8/propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", size = 228009 },
+ { url = "https://files.pythonhosted.org/packages/1a/06/ef1390f2524850838f2390421b23a8b298f6ce3396a7cc6d39dedd4047b0/propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", size = 231638 },
+ { url = "https://files.pythonhosted.org/packages/38/2a/101e6386d5a93358395da1d41642b79c1ee0f3b12e31727932b069282b1d/propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", size = 222788 },
+ { url = "https://files.pythonhosted.org/packages/db/81/786f687951d0979007e05ad9346cd357e50e3d0b0f1a1d6074df334b1bbb/propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", size = 40170 },
+ { url = "https://files.pythonhosted.org/packages/cf/59/7cc7037b295d5772eceb426358bb1b86e6cab4616d971bd74275395d100d/propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", size = 44404 },
+ { url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 },
+ { url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 },
+ { url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 },
+ { url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 },
+ { url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 },
+ { url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 },
+ { url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 },
+ { url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 },
+ { url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 },
+ { url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 },
+ { url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 },
+ { url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 },
+ { url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 },
+ { url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 },
+ { url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 },
+ { url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 },
+ { url = "https://files.pythonhosted.org/packages/0f/2a/329e0547cf2def8857157f9477669043e75524cc3e6251cef332b3ff256f/propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", size = 77002 },
+ { url = "https://files.pythonhosted.org/packages/12/2d/c4df5415e2382f840dc2ecbca0eeb2293024bc28e57a80392f2012b4708c/propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", size = 44639 },
+ { url = "https://files.pythonhosted.org/packages/d0/5a/21aaa4ea2f326edaa4e240959ac8b8386ea31dedfdaa636a3544d9e7a408/propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", size = 44049 },
+ { url = "https://files.pythonhosted.org/packages/4e/3e/021b6cd86c0acc90d74784ccbb66808b0bd36067a1bf3e2deb0f3845f618/propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", size = 224819 },
+ { url = "https://files.pythonhosted.org/packages/3c/57/c2fdeed1b3b8918b1770a133ba5c43ad3d78e18285b0c06364861ef5cc38/propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", size = 229625 },
+ { url = "https://files.pythonhosted.org/packages/9d/81/70d4ff57bf2877b5780b466471bebf5892f851a7e2ca0ae7ffd728220281/propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", size = 232934 },
+ { url = "https://files.pythonhosted.org/packages/3c/b9/bb51ea95d73b3fb4100cb95adbd4e1acaf2cbb1fd1083f5468eeb4a099a8/propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", size = 227361 },
+ { url = "https://files.pythonhosted.org/packages/f1/20/3c6d696cd6fd70b29445960cc803b1851a1131e7a2e4ee261ee48e002bcd/propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", size = 213904 },
+ { url = "https://files.pythonhosted.org/packages/a1/cb/1593bfc5ac6d40c010fa823f128056d6bc25b667f5393781e37d62f12005/propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", size = 212632 },
+ { url = "https://files.pythonhosted.org/packages/6d/5c/e95617e222be14a34c709442a0ec179f3207f8a2b900273720501a70ec5e/propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", size = 207897 },
+ { url = "https://files.pythonhosted.org/packages/8e/3b/56c5ab3dc00f6375fbcdeefdede5adf9bee94f1fab04adc8db118f0f9e25/propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", size = 208118 },
+ { url = "https://files.pythonhosted.org/packages/86/25/d7ef738323fbc6ebcbce33eb2a19c5e07a89a3df2fded206065bd5e868a9/propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", size = 217851 },
+ { url = "https://files.pythonhosted.org/packages/b3/77/763e6cef1852cf1ba740590364ec50309b89d1c818e3256d3929eb92fabf/propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", size = 222630 },
+ { url = "https://files.pythonhosted.org/packages/4f/e9/0f86be33602089c701696fbed8d8c4c07b6ee9605c5b7536fd27ed540c5b/propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", size = 216269 },
+ { url = "https://files.pythonhosted.org/packages/cc/02/5ac83217d522394b6a2e81a2e888167e7ca629ef6569a3f09852d6dcb01a/propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", size = 39472 },
+ { url = "https://files.pythonhosted.org/packages/f4/33/d6f5420252a36034bc8a3a01171bc55b4bff5df50d1c63d9caa50693662f/propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", size = 43363 },
+ { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 },
]
[[package]]
@@ -960,7 +963,7 @@ wheels = [
[[package]]
name = "pytest"
-version = "8.3.3"
+version = "8.3.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
@@ -968,21 +971,21 @@ dependencies = [
{ name = "packaging" },
{ name = "pluggy" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 }
+sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 },
+ { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
]
[[package]]
name = "pytest-asyncio"
-version = "0.24.0"
+version = "0.25.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 }
+sdist = { url = "https://files.pythonhosted.org/packages/94/18/82fcb4ee47d66d99f6cd1efc0b11b2a25029f303c599a5afda7c1bca4254/pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609", size = 53298 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 },
+ { url = "https://files.pythonhosted.org/packages/88/56/2ee0cab25c11d4e38738a2a98c645a8f002e2ecf7b5ed774c70d53b92bb1/pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3", size = 19245 },
]
[[package]]
@@ -1000,15 +1003,15 @@ wheels = [
[[package]]
name = "pytest-freezer"
-version = "0.4.8"
+version = "0.4.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "freezegun" },
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/69/fa/a93d40dd50f712c276a5a15f9c075bee932cc4d28c376e60b4a35904976d/pytest_freezer-0.4.8.tar.gz", hash = "sha256:8ee2f724b3ff3540523fa355958a22e6f4c1c819928b78a7a183ae4248ce6ee6", size = 3212 }
+sdist = { url = "https://files.pythonhosted.org/packages/81/f0/98dcbc5324064360b19850b14c84cea9ca50785d921741dbfc442346e925/pytest_freezer-0.4.9.tar.gz", hash = "sha256:21bf16bc9cc46bf98f94382c4b5c3c389be7056ff0be33029111ae11b3f1c82a", size = 3177 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d8/4e/ba488639516a341810aeaeb4b32b70abb0923e53f7c4d14d673dc114d35a/pytest_freezer-0.4.8-py3-none-any.whl", hash = "sha256:644ce7ddb8ba52b92a1df0a80a699bad2b93514c55cf92e9f2517b68ebe74814", size = 3228 },
+ { url = "https://files.pythonhosted.org/packages/c1/e9/30252bc05bcf67200a17f4f0b4cc7598f0a68df4fa9fa356193aa899f145/pytest_freezer-0.4.9-py3-none-any.whl", hash = "sha256:8b6c50523b7d4aec4590b52bfa5ff766d772ce506e2bf4846c88041ea9ccae59", size = 3192 },
]
[[package]]
@@ -1088,7 +1091,7 @@ wheels = [
[[package]]
name = "python-kasa"
-version = "0.8.1"
+version = "0.9.0"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
@@ -1265,11 +1268,11 @@ wheels = [
[[package]]
name = "six"
-version = "1.16.0"
+version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 },
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
]
[[package]]
@@ -1381,14 +1384,14 @@ wheels = [
[[package]]
name = "sphinxcontrib-programoutput"
-version = "0.17"
+version = "0.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "sphinx" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/49/fe/8a6d8763674b3d3814a6008a83eb8002b6da188710dd7f4654ec77b4a8ac/sphinxcontrib-programoutput-0.17.tar.gz", hash = "sha256:300ee9b8caee8355d25cc74b4d1c7efd12e608d2ad165e3141d31e6fbc152b7f", size = 24067 }
+sdist = { url = "https://files.pythonhosted.org/packages/3f/c0/834af2290f8477213ec0dd60e90104f5644aa0c37b1a0d6f0a2b5efe03c4/sphinxcontrib_programoutput-0.18.tar.gz", hash = "sha256:09e68b6411d937a80b6085f4fdeaa42e0dc5555480385938465f410589d2eed8", size = 26333 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/30/ee/b7be4b3f45f4e36bfa6c444cd234098e0d09880379c67a43e6bb9ab99a86/sphinxcontrib_programoutput-0.17-py2.py3-none-any.whl", hash = "sha256:0ef1c1d9159dbe7103077748214305eb4e0138e861feb71c0c346afc5fe97f84", size = 22131 },
+ { url = "https://files.pythonhosted.org/packages/04/2c/7aec6e0580f666d4f61474a50c4995a98abfff27d827f0e7bc8c4fa528f5/sphinxcontrib_programoutput-0.18-py3-none-any.whl", hash = "sha256:8a651bc85de69a808a064ff0e48d06c12b9347da4fe5fdb1e94914b01e1b0c36", size = 20346 },
]
[[package]]
@@ -1429,11 +1432,41 @@ wheels = [
[[package]]
name = "tomli"
-version = "2.1.0"
+version = "2.2.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1e/e4/1b6cbcc82d8832dd0ce34767d5c560df8a3547ad8cbc427f34601415930a/tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", size = 16622 }
+sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/de/f7/4da0ffe1892122c9ea096c57f64c2753ae5dd3ce85488802d11b0992cc6d/tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391", size = 13750 },
+ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 },
+ { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 },
+ { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 },
+ { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 },
+ { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 },
+ { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 },
+ { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 },
+ { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 },
+ { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 },
+ { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 },
+ { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 },
+ { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 },
+ { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 },
+ { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 },
+ { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 },
+ { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 },
+ { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 },
+ { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 },
+ { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 },
+ { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 },
+ { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 },
+ { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 },
+ { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 },
+ { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 },
+ { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 },
+ { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 },
+ { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 },
+ { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 },
+ { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 },
+ { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 },
+ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
]
[[package]]
@@ -1506,62 +1539,62 @@ wheels = [
[[package]]
name = "yarl"
-version = "1.18.0"
+version = "1.18.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "multidict" },
{ name = "propcache" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/5e/4b/53db4ecad4d54535aff3dfda1f00d6363d79455f62b11b8ca97b82746bd2/yarl-1.18.0.tar.gz", hash = "sha256:20d95535e7d833889982bfe7cc321b7f63bf8879788fee982c76ae2b24cfb715", size = 180098 }
+sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/06/45/6ad7135d1c4ad3a6a49e2c37dc78a1805a7871879c03c3495d64c9605d49/yarl-1.18.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b8e8c516dc4e1a51d86ac975b0350735007e554c962281c432eaa5822aa9765c", size = 141283 },
- { url = "https://files.pythonhosted.org/packages/45/6d/24b70ae33107d6eba303ed0ebfdf1164fe2219656e7594ca58628ebc0f1d/yarl-1.18.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e6b4466714a73f5251d84b471475850954f1fa6acce4d3f404da1d55d644c34", size = 94082 },
- { url = "https://files.pythonhosted.org/packages/8a/0e/da720989be11b662ca847ace58f468b52310a9b03e52ac62c144755f9d75/yarl-1.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c893f8c1a6d48b25961e00922724732d00b39de8bb0b451307482dc87bddcd74", size = 92017 },
- { url = "https://files.pythonhosted.org/packages/f5/76/e5c91681fa54658943cb88673fb19b3355c3a8ae911a33a2621b6320990d/yarl-1.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13aaf2bdbc8c86ddce48626b15f4987f22e80d898818d735b20bd58f17292ee8", size = 340359 },
- { url = "https://files.pythonhosted.org/packages/cf/77/02cf72f09dea20980dea4ebe40dfb2c24916b864aec869a19f715428e0f0/yarl-1.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd21c0128e301851de51bc607b0a6da50e82dc34e9601f4b508d08cc89ee7929", size = 356336 },
- { url = "https://files.pythonhosted.org/packages/17/66/83a88d04e4fc243dd26109f3e3d6412f67819ab1142dadbce49706ef4df4/yarl-1.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205de377bd23365cd85562c9c6c33844050a93661640fda38e0567d2826b50df", size = 353730 },
- { url = "https://files.pythonhosted.org/packages/76/77/0b205a532d22756ab250ab21924d362f910a23d641c82faec1c4ad7f6077/yarl-1.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed69af4fe2a0949b1ea1d012bf065c77b4c7822bad4737f17807af2adb15a73c", size = 343882 },
- { url = "https://files.pythonhosted.org/packages/0b/47/2081ddce3da6096889c3947bdc21907d0fa15939909b10219254fe116841/yarl-1.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e1c18890091aa3cc8a77967943476b729dc2016f4cfe11e45d89b12519d4a93", size = 335873 },
- { url = "https://files.pythonhosted.org/packages/25/3c/437304394494e757ae927c9a81bacc4bcdf7351a1d4e811d95b02cb6dbae/yarl-1.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91b8fb9427e33f83ca2ba9501221ffaac1ecf0407f758c4d2f283c523da185ee", size = 347725 },
- { url = "https://files.pythonhosted.org/packages/c6/fb/fa6c642bc052fbe6370ed5da765579650510157dea354fe9e8177c3bc34a/yarl-1.18.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:536a7a8a53b75b2e98ff96edb2dfb91a26b81c4fed82782035767db5a465be46", size = 346161 },
- { url = "https://files.pythonhosted.org/packages/b0/09/8c0cf68a0fcfe3b060c9e5857bb35735bc72a4cf4075043632c636d007e9/yarl-1.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a64619a9c47c25582190af38e9eb382279ad42e1f06034f14d794670796016c0", size = 349924 },
- { url = "https://files.pythonhosted.org/packages/bf/4b/1efe10fd51e2cedf53195d688fa270efbcd64a015c61d029d49c20bf0af7/yarl-1.18.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c73a6bbc97ba1b5a0c3c992ae93d721c395bdbb120492759b94cc1ac71bc6350", size = 361865 },
- { url = "https://files.pythonhosted.org/packages/0b/1b/2b5efd6df06bf938f7e154dee8e2ab22d148f3311a92bf4da642aaaf2fc5/yarl-1.18.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a173401d7821a2a81c7b47d4e7d5c4021375a1441af0c58611c1957445055056", size = 366030 },
- { url = "https://files.pythonhosted.org/packages/f8/db/786a5684f79278e62271038a698f56a51960f9e643be5d3eff82712f0b1c/yarl-1.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7520e799b1f84e095cce919bd6c23c9d49472deeef25fe1ef960b04cca51c3fc", size = 358902 },
- { url = "https://files.pythonhosted.org/packages/91/2f/437d0de062f1a3e3cb17573971b3832232443241133580c2ba3da5001d06/yarl-1.18.0-cp311-cp311-win32.whl", hash = "sha256:c4cb992d8090d5ae5f7afa6754d7211c578be0c45f54d3d94f7781c495d56716", size = 84138 },
- { url = "https://files.pythonhosted.org/packages/9d/85/035719a9266bce85ecde820aa3f8c46f3b18c3d7ba9ff51367b2fa4ae2a2/yarl-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:52c136f348605974c9b1c878addd6b7a60e3bf2245833e370862009b86fa4689", size = 90765 },
- { url = "https://files.pythonhosted.org/packages/23/36/c579b80a5c76c0d41c8e08baddb3e6940dfc20569db579a5691392c52afa/yarl-1.18.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1ece25e2251c28bab737bdf0519c88189b3dd9492dc086a1d77336d940c28ced", size = 142376 },
- { url = "https://files.pythonhosted.org/packages/0c/5f/e247dc7c0607a0c505fea6c839721844bee55686dfb183c7d7b8ef8a9cb1/yarl-1.18.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:454902dc1830d935c90b5b53c863ba2a98dcde0fbaa31ca2ed1ad33b2a7171c6", size = 94692 },
- { url = "https://files.pythonhosted.org/packages/eb/e1/3081b578a6f21961711b9a1c49c2947abb3b0d0dd9537378fb06777ce8ee/yarl-1.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01be8688fc211dc237e628fcc209dda412d35de7642453059a0553747018d075", size = 92527 },
- { url = "https://files.pythonhosted.org/packages/2f/fa/d9e1b9fbafa4cc82cd3980b5314741b33c2fe16308d725449a23aed32021/yarl-1.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d26f1fa9fa2167bb238f6f4b20218eb4e88dd3ef21bb8f97439fa6b5313e30d", size = 332096 },
- { url = "https://files.pythonhosted.org/packages/93/b6/dd27165114317875838e216214fb86338dc63d2e50855a8f2a12de2a7fe5/yarl-1.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b234a4a9248a9f000b7a5dfe84b8cb6210ee5120ae70eb72a4dcbdb4c528f72f", size = 342047 },
- { url = "https://files.pythonhosted.org/packages/fc/9f/bad434b5279ae7a356844e14dc771c3d29eb928140bbc01621af811c8a27/yarl-1.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe94d1de77c4cd8caff1bd5480e22342dbd54c93929f5943495d9c1e8abe9f42", size = 341712 },
- { url = "https://files.pythonhosted.org/packages/9a/9f/63864f43d131ba8c8cdf1bde5dd3f02f0eff8a7c883a5d7fad32f204fda5/yarl-1.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4c90c5363c6b0a54188122b61edb919c2cd1119684999d08cd5e538813a28e", size = 336654 },
- { url = "https://files.pythonhosted.org/packages/20/30/b4542bbd9be73de155213207eec019f6fe6495885f7dd59aa1ff705a041b/yarl-1.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a98ecadc5a241c9ba06de08127ee4796e1009555efd791bac514207862b43d", size = 325484 },
- { url = "https://files.pythonhosted.org/packages/69/bc/e2a9808ec26989cf0d1b98fe7b3cc45c1c6506b5ea4fe43ece5991f28f34/yarl-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9106025c7f261f9f5144f9aa7681d43867eed06349a7cfb297a1bc804de2f0d1", size = 344213 },
- { url = "https://files.pythonhosted.org/packages/e2/17/0ee5a68886aca1a8071b0d24a1e1c0fd9970dead2ef2d5e26e027fb7ce88/yarl-1.18.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f275ede6199d0f1ed4ea5d55a7b7573ccd40d97aee7808559e1298fe6efc8dbd", size = 340517 },
- { url = "https://files.pythonhosted.org/packages/fd/db/1fe4ef38ee852bff5ec8f5367d718b3a7dac7520f344b8e50306f68a2940/yarl-1.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f7edeb1dcc7f50a2c8e08b9dc13a413903b7817e72273f00878cb70e766bdb3b", size = 346234 },
- { url = "https://files.pythonhosted.org/packages/b4/ee/5e5bccdb821eb9949ba66abb4d19e3299eee00282e37b42f65236120e892/yarl-1.18.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c083f6dd6951b86e484ebfc9c3524b49bcaa9c420cb4b2a78ef9f7a512bfcc85", size = 359625 },
- { url = "https://files.pythonhosted.org/packages/3f/43/95a64d9e7ab4aa1c34fc5ea0edb35b581bc6ad33fd960a8ae34c2040b319/yarl-1.18.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:80741ec5b471fbdfb997821b2842c59660a1c930ceb42f8a84ba8ca0f25a66aa", size = 364239 },
- { url = "https://files.pythonhosted.org/packages/40/19/09ce976c624c9d3cc898f0be5035ddef0c0759d85b2313321cfe77b69915/yarl-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1a3297b9cad594e1ff0c040d2881d7d3a74124a3c73e00c3c71526a1234a9f7", size = 357599 },
- { url = "https://files.pythonhosted.org/packages/7d/35/6f33fd29791af2ec161aebe8abe63e788c2b74a6c7e8f29c92e5f5e96849/yarl-1.18.0-cp312-cp312-win32.whl", hash = "sha256:cd6ab7d6776c186f544f893b45ee0c883542b35e8a493db74665d2e594d3ca75", size = 83832 },
- { url = "https://files.pythonhosted.org/packages/4e/8e/cdb40ef98597be107de67b11e2f1f23f911e0f1416b938885d17a338e304/yarl-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:039c299a0864d1f43c3e31570045635034ea7021db41bf4842693a72aca8df3a", size = 90132 },
- { url = "https://files.pythonhosted.org/packages/2b/77/2196b657c66f97adaef0244e9e015f30eac0df59c31ad540f79ce328feed/yarl-1.18.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6fb64dd45453225f57d82c4764818d7a205ee31ce193e9f0086e493916bd4f72", size = 140512 },
- { url = "https://files.pythonhosted.org/packages/0e/d8/2bb6e26fddba5c01bad284e4571178c651b97e8e06318efcaa16e07eb9fd/yarl-1.18.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3adaaf9c6b1b4fc258584f4443f24d775a2086aee82d1387e48a8b4f3d6aecf6", size = 93875 },
- { url = "https://files.pythonhosted.org/packages/54/e4/99fbb884dd9f814fb0037dc1783766bb9edcd57b32a76f3ec5ac5c5772d7/yarl-1.18.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da206d1ec78438a563c5429ab808a2b23ad7bc025c8adbf08540dde202be37d5", size = 91705 },
- { url = "https://files.pythonhosted.org/packages/3b/a2/5bd86eca9449e6b15d3b08005cf4e58e3da972240c2bee427b358c311549/yarl-1.18.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:576d258b21c1db4c6449b1c572c75d03f16a482eb380be8003682bdbe7db2f28", size = 333325 },
- { url = "https://files.pythonhosted.org/packages/94/50/a218da5f159cd985685bc72c500bb1a7fd2d60035d2339b8a9d9e1f99194/yarl-1.18.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e547c0a375c4bfcdd60eef82e7e0e8698bf84c239d715f5c1278a73050393", size = 344121 },
- { url = "https://files.pythonhosted.org/packages/a4/e3/830ae465811198b4b5ebecd674b5b3dca4d222af2155eb2144bfe190bbb8/yarl-1.18.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3818eabaefb90adeb5e0f62f047310079d426387991106d4fbf3519eec7d90a", size = 345163 },
- { url = "https://files.pythonhosted.org/packages/7a/74/05c4326877ca541eee77b1ef74b7ac8081343d3957af8f9291ca6eca6fec/yarl-1.18.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f72421246c21af6a92fbc8c13b6d4c5427dfd949049b937c3b731f2f9076bd", size = 339130 },
- { url = "https://files.pythonhosted.org/packages/29/42/842f35aa1dae25d132119ee92185e8c75d8b9b7c83346506bd31e9fa217f/yarl-1.18.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fa7d37f2ada0f42e0723632993ed422f2a679af0e200874d9d861720a54f53e", size = 326418 },
- { url = "https://files.pythonhosted.org/packages/f9/ed/65c0514f2d1e8b92a61f564c914381d078766cab38b5fbde355b3b3af1fb/yarl-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:42ba84e2ac26a3f252715f8ec17e6fdc0cbf95b9617c5367579fafcd7fba50eb", size = 345204 },
- { url = "https://files.pythonhosted.org/packages/23/31/351f64f0530c372fa01160f38330f44478e7bf3092f5ce2bfcb91605561d/yarl-1.18.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6a49ad0102c0f0ba839628d0bf45973c86ce7b590cdedf7540d5b1833ddc6f00", size = 341652 },
- { url = "https://files.pythonhosted.org/packages/49/aa/0c6e666c218d567727c1d040d01575685e7f9b18052fd68a59c9f61fe5d9/yarl-1.18.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96404e8d5e1bbe36bdaa84ef89dc36f0e75939e060ca5cd45451aba01db02902", size = 347257 },
- { url = "https://files.pythonhosted.org/packages/36/0b/33a093b0e13bb8cd0f27301779661ff325270b6644929001f8f33307357d/yarl-1.18.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a0509475d714df8f6d498935b3f307cd122c4ca76f7d426c7e1bb791bcd87eda", size = 359735 },
- { url = "https://files.pythonhosted.org/packages/a8/92/dcc0b37c48632e71ffc2b5f8b0509347a0bde55ab5862ff755dce9dd56c4/yarl-1.18.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ff116f0285b5c8b3b9a2680aeca29a858b3b9e0402fc79fd850b32c2bcb9f8b", size = 365982 },
- { url = "https://files.pythonhosted.org/packages/0e/39/30e2a24a7a6c628dccb13eb6c4a03db5f6cd1eb2c6cda56a61ddef764c11/yarl-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2580c1d7e66e6d29d6e11855e3b1c6381971e0edd9a5066e6c14d79bc8967af", size = 360128 },
- { url = "https://files.pythonhosted.org/packages/76/13/12b65dca23b1fb8ae44269a4d24048fd32ac90b445c985b0a46fdfa30cfe/yarl-1.18.0-cp313-cp313-win32.whl", hash = "sha256:14408cc4d34e202caba7b5ac9cc84700e3421a9e2d1b157d744d101b061a4a88", size = 309888 },
- { url = "https://files.pythonhosted.org/packages/f6/60/478d3d41a4bf0b9e7dca74d870d114e775d1ff7156b7d1e0e9972e8f97fd/yarl-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db1537e9cb846eb0ff206eac667f627794be8b71368c1ab3207ec7b6f8c5afc", size = 315459 },
- { url = "https://files.pythonhosted.org/packages/30/9c/3f7ab894a37b1520291247cbc9ea6756228d098dae5b37eec848d404a204/yarl-1.18.0-py3-none-any.whl", hash = "sha256:dbf53db46f7cf176ee01d8d98c39381440776fcda13779d269a8ba664f69bec0", size = 44840 },
+ { url = "https://files.pythonhosted.org/packages/40/93/282b5f4898d8e8efaf0790ba6d10e2245d2c9f30e199d1a85cae9356098c/yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", size = 141555 },
+ { url = "https://files.pythonhosted.org/packages/6d/9c/0a49af78df099c283ca3444560f10718fadb8a18dc8b3edf8c7bd9fd7d89/yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", size = 94351 },
+ { url = "https://files.pythonhosted.org/packages/5a/a1/205ab51e148fdcedad189ca8dd587794c6f119882437d04c33c01a75dece/yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", size = 92286 },
+ { url = "https://files.pythonhosted.org/packages/ed/fe/88b690b30f3f59275fb674f5f93ddd4a3ae796c2b62e5bb9ece8a4914b83/yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", size = 340649 },
+ { url = "https://files.pythonhosted.org/packages/07/eb/3b65499b568e01f36e847cebdc8d7ccb51fff716dbda1ae83c3cbb8ca1c9/yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", size = 356623 },
+ { url = "https://files.pythonhosted.org/packages/33/46/f559dc184280b745fc76ec6b1954de2c55595f0ec0a7614238b9ebf69618/yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", size = 354007 },
+ { url = "https://files.pythonhosted.org/packages/af/ba/1865d85212351ad160f19fb99808acf23aab9a0f8ff31c8c9f1b4d671fc9/yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", size = 344145 },
+ { url = "https://files.pythonhosted.org/packages/94/cb/5c3e975d77755d7b3d5193e92056b19d83752ea2da7ab394e22260a7b824/yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", size = 336133 },
+ { url = "https://files.pythonhosted.org/packages/19/89/b77d3fd249ab52a5c40859815765d35c91425b6bb82e7427ab2f78f5ff55/yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", size = 347967 },
+ { url = "https://files.pythonhosted.org/packages/35/bd/f6b7630ba2cc06c319c3235634c582a6ab014d52311e7d7c22f9518189b5/yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", size = 346397 },
+ { url = "https://files.pythonhosted.org/packages/18/1a/0b4e367d5a72d1f095318344848e93ea70da728118221f84f1bf6c1e39e7/yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", size = 350206 },
+ { url = "https://files.pythonhosted.org/packages/b5/cf/320fff4367341fb77809a2d8d7fe75b5d323a8e1b35710aafe41fdbf327b/yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", size = 362089 },
+ { url = "https://files.pythonhosted.org/packages/57/cf/aadba261d8b920253204085268bad5e8cdd86b50162fcb1b10c10834885a/yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", size = 366267 },
+ { url = "https://files.pythonhosted.org/packages/54/58/fb4cadd81acdee6dafe14abeb258f876e4dd410518099ae9a35c88d8097c/yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", size = 359141 },
+ { url = "https://files.pythonhosted.org/packages/9a/7a/4c571597589da4cd5c14ed2a0b17ac56ec9ee7ee615013f74653169e702d/yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", size = 84402 },
+ { url = "https://files.pythonhosted.org/packages/ae/7b/8600250b3d89b625f1121d897062f629883c2f45339623b69b1747ec65fa/yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", size = 91030 },
+ { url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 },
+ { url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 },
+ { url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 },
+ { url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 },
+ { url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 },
+ { url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 },
+ { url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 },
+ { url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 },
+ { url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 },
+ { url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 },
+ { url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 },
+ { url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 },
+ { url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 },
+ { url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 },
+ { url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 },
+ { url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 },
+ { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789 },
+ { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144 },
+ { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974 },
+ { url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587 },
+ { url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386 },
+ { url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421 },
+ { url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384 },
+ { url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689 },
+ { url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453 },
+ { url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872 },
+ { url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497 },
+ { url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981 },
+ { url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229 },
+ { url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383 },
+ { url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152 },
+ { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723 },
+ { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 },
]