Skip to content

Move TAPO smartcamera out of experimental package #1255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion devtools/dump_devinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from kasa.deviceconfig import DeviceEncryptionType, DeviceFamily
from kasa.discover import DiscoveryResult
from kasa.exceptions import SmartErrorCode
from kasa.experimental.smartcameraprotocol import (
from kasa.protocols.smartcameraprotocol import (
SmartCameraProtocol,
_ChildCameraProtocolWrapper,
)
Expand Down
17 changes: 7 additions & 10 deletions kasa/device_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
from .device_type import DeviceType
from .deviceconfig import DeviceConfig
from .exceptions import KasaException, UnsupportedDeviceError
from .experimental.smartcamera import SmartCamera
from .experimental.smartcameraprotocol import SmartCameraProtocol
from .experimental.sslaestransport import SslAesTransport
from .iot import (
IotBulb,
IotDevice,
Expand All @@ -27,14 +24,17 @@
IotProtocol,
SmartProtocol,
)
from .protocols.smartcameraprotocol import SmartCameraProtocol
from .smart import SmartDevice
from .smartcamera.smartcamera import SmartCamera
from .transports import (
AesTransport,
BaseTransport,
KlapTransport,
KlapTransportV2,
XorTransport,
)
from .transports.sslaestransport import SslAesTransport

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -217,12 +217,9 @@ def get_protocol(
"IOT.KLAP": (IotProtocol, KlapTransport),
"SMART.AES": (SmartProtocol, AesTransport),
"SMART.KLAP": (SmartProtocol, KlapTransportV2),
"SMART.AES.HTTPS": (SmartCameraProtocol, SslAesTransport),
}
if not (prot_tran_cls := supported_device_protocols.get(protocol_transport_key)):
from .experimental import Experimental

if Experimental.enabled() and protocol_transport_key == "SMART.AES.HTTPS":
prot_tran_cls = (SmartCameraProtocol, SslAesTransport)
else:
return None
return prot_tran_cls[0](transport=prot_tran_cls[1](config=config))
return None
protocol_cls, transport_cls = prot_tran_cls
return protocol_cls(transport=transport_cls(config=config))
4 changes: 2 additions & 2 deletions kasa/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
if TYPE_CHECKING:
from . import interfaces
from .device import Device
from .experimental import modules as experimental
from .iot import modules as iot
from .smart import modules as smart
from .smartcamera import modules as smartcamera

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -133,7 +133,7 @@ class Module(ABC):
TriggerLogs: Final[ModuleName[smart.TriggerLogs]] = ModuleName("TriggerLogs")

# SMARTCAMERA only modules
Camera: Final[ModuleName[experimental.Camera]] = ModuleName("Camera")
Camera: Final[ModuleName[smartcamera.Camera]] = ModuleName("Camera")

def __init__(self, device: Device, module: str) -> None:
self._device = device
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
_RetryableError,
)
from ..json import dumps as json_dumps
from ..protocols import SmartProtocol
from .sslaestransport import (
from ..transports.sslaestransport import (
SMART_AUTHENTICATION_ERRORS,
SMART_RETRYABLE_ERRORS,
SmartErrorCode,
)
from . import SmartProtocol

_LOGGER = logging.getLogger(__name__)

Expand Down
5 changes: 5 additions & 0 deletions kasa/smartcamera/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Package for supporting tapo-branded cameras."""

from .smartcamera import SmartCamera

__all__ = ["SmartCamera"]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@

from ..device_type import DeviceType
from ..module import Module
from ..protocols.smartcameraprotocol import _ChildCameraProtocolWrapper
from ..smart import SmartChildDevice, SmartDevice
from .modules.childdevice import ChildDevice
from .modules.device import DeviceModule
from .modules import ChildDevice, DeviceModule
from .smartcameramodule import SmartCameraModule
from .smartcameraprotocol import _ChildCameraProtocolWrapper

_LOGGER = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ..httpclient import HttpClient
from ..json import dumps as json_dumps
from ..json import loads as json_loads
from ..transports import AesEncyptionSession, BaseTransport
from . import AesEncyptionSession, BaseTransport

_LOGGER = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion tests/device_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
DeviceType,
Discover,
)
from kasa.experimental.smartcamera import SmartCamera
from kasa.iot import IotBulb, IotDimmer, IotLightStrip, IotPlug, IotStrip, IotWallSwitch
from kasa.smart import SmartDevice
from kasa.smartcamera.smartcamera import SmartCamera

from .fakeprotocol_iot import FakeIotProtocol
from .fakeprotocol_smart import FakeSmartProtocol
Expand Down
23 changes: 15 additions & 8 deletions tests/discovery_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from .fakeprotocol_iot import FakeIotProtocol
from .fakeprotocol_smart import FakeSmartProtocol, FakeSmartTransport
from .fakeprotocol_smartcamera import FakeSmartCameraProtocol
from .fixtureinfo import FixtureInfo, filter_fixtures, idgenerator

DISCOVERY_MOCK_IP = "127.0.0.123"
Expand Down Expand Up @@ -126,12 +127,14 @@ def _datagram(self) -> bytes:

if "discovery_result" in fixture_data:
discovery_data = {"result": fixture_data["discovery_result"].copy()}
device_type = fixture_data["discovery_result"]["device_type"]
encrypt_type = fixture_data["discovery_result"]["mgt_encrypt_schm"][
"encrypt_type"
]
login_version = fixture_data["discovery_result"]["mgt_encrypt_schm"].get("lv")
https = fixture_data["discovery_result"]["mgt_encrypt_schm"]["is_support_https"]
discovery_result = fixture_data["discovery_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")
https = discovery_result["mgt_encrypt_schm"]["is_support_https"]
dm = _DiscoveryMock(
ip,
80,
Expand Down Expand Up @@ -172,7 +175,9 @@ def patch_discovery(fixture_infos: dict[str, FixtureInfo], mocker):
}
protos = {
ip: FakeSmartProtocol(fixture_info.data, fixture_info.name)
if "SMART" in fixture_info.protocol
if fixture_info.protocol in {"SMART", "SMART.CHILD"}
else FakeSmartCameraProtocol(fixture_info.data, fixture_info.name)
if fixture_info.protocol in {"SMARTCAMERA", "SMARTCAMERA.CHILD"}
else FakeIotProtocol(fixture_info.data, fixture_info.name)
for ip, fixture_info in fixture_infos.items()
}
Expand All @@ -197,7 +202,9 @@ async def mock_discover(self):
# update the protos for any host testing or the test overriding the first ip
protos[host] = (
FakeSmartProtocol(fixture_info.data, fixture_info.name)
if "SMART" in fixture_info.protocol
if fixture_info.protocol in {"SMART", "SMART.CHILD"}
else FakeSmartCameraProtocol(fixture_info.data, fixture_info.name)
if fixture_info.protocol in {"SMARTCAMERA", "SMARTCAMERA.CHILD"}
else FakeIotProtocol(fixture_info.data, fixture_info.name)
)
port = (
Expand Down
8 changes: 7 additions & 1 deletion tests/fakeprotocol_smartcamera.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from json import loads as json_loads

from kasa import Credentials, DeviceConfig, SmartProtocol
from kasa.experimental.smartcameraprotocol import SmartCameraProtocol
from kasa.protocols.smartcameraprotocol import SmartCameraProtocol
from kasa.transports.basetransport import BaseTransport

from .fakeprotocol_smart import FakeSmartTransport
Expand Down Expand Up @@ -136,6 +136,12 @@ def _get_param_set_value(info: dict, set_keys: list[str], value):
"basic",
"zone_id",
],
("led", "config", "enabled"): [
"getLedStatus",
"led",
"config",
"enabled",
],
}

async def _send_request(self, request_dict: dict):
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtureinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

from kasa.device_factory import _get_device_type_from_sys_info
from kasa.device_type import DeviceType
from kasa.experimental.smartcamera import SmartCamera
from kasa.smart.smartdevice import SmartDevice
from kasa.smartcamera.smartcamera import SmartCamera


class FixtureInfo(NamedTuple):
Expand Down Expand Up @@ -179,7 +179,7 @@ def _device_type_match(fixture_data: FixtureInfo, device_type):

filtered = []
if protocol_filter is None:
protocol_filter = {"IOT", "SMART"}
protocol_filter = {"IOT", "SMART", "SMARTCAMERA"}
for fixture_data in fixture_list:
if data_root_filter and data_root_filter not in fixture_data.data:
continue
Expand Down
8 changes: 7 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from kasa.discover import Discover, DiscoveryResult
from kasa.iot import IotDevice
from kasa.smart import SmartDevice
from kasa.smartcamera import SmartCamera

from .conftest import (
device_smart,
Expand Down Expand Up @@ -178,6 +179,9 @@ async def test_state(dev, turn_on, runner):

@turn_on
async def test_toggle(dev, turn_on, runner):
if isinstance(dev, SmartCamera) and dev.device_type == DeviceType.Hub:
pytest.skip(reason="Hub cannot toggle state")

await handle_turn_on(dev, turn_on)
await dev.update()
assert dev.is_on == turn_on
Expand Down Expand Up @@ -208,7 +212,9 @@ async def test_raw_command(dev, mocker, runner):
update = mocker.patch.object(dev, "update")
from kasa.smart import SmartDevice

if isinstance(dev, SmartDevice):
if isinstance(dev, SmartCamera):
params = ["na", "getDeviceInfo"]
elif isinstance(dev, SmartDevice):
params = ["na", "get_device_info"]
else:
params = ["system", "get_sysinfo"]
Expand Down
5 changes: 4 additions & 1 deletion tests/test_device_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
)
from kasa.device_factory import (
Device,
SmartCamera,
SmartDevice,
_get_device_type_from_sys_info,
connect,
Expand Down Expand Up @@ -177,7 +178,9 @@ async def test_connect_http_client(discovery_mock, mocker):

async def test_device_types(dev: Device):
await dev.update()
if isinstance(dev, SmartDevice):
if isinstance(dev, SmartCamera):
res = SmartCamera._get_device_type_from_sysinfo(dev.sys_info)
elif isinstance(dev, SmartDevice):
assert dev._discovery_info
device_type = cast(str, dev._discovery_info["result"]["device_type"])
res = SmartDevice._get_device_type_from_components(
Expand Down
6 changes: 3 additions & 3 deletions tests/test_sslaestransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
KasaException,
SmartErrorCode,
)
from kasa.experimental.sslaestransport import (
from kasa.httpclient import HttpClient
from kasa.transports.aestransport import AesEncyptionSession
from kasa.transports.sslaestransport import (
SslAesTransport,
TransportState,
_sha256_hash,
)
from kasa.httpclient import HttpClient
from kasa.transports.aestransport import AesEncyptionSession

# Transport tests are not designed for real devices
pytestmark = [pytest.mark.requires_dummy]
Expand Down
Loading