Remove SmartPlug in favor of SmartDevice (#781)

With the move towards autodetecting available features, there is no reason to keep SmartPlug around.

kasa.smart.SmartPlug is removed in favor of kasa.smart.SmartDevice which offers the same functionality.
Information about auto_off can be accessed using Features of the AutoOffModule on supported devices.

Co-authored-by: Steven B. <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
Teemu R 2024-02-22 14:34:55 +01:00 committed by GitHub
parent 8c39e81a40
commit d9d2f1a430
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 70 additions and 61 deletions

View File

@ -134,7 +134,6 @@ if TYPE_CHECKING:
from . import smart
smart.SmartDevice("127.0.0.1")
smart.SmartPlug("127.0.0.1")
smart.SmartBulb("127.0.0.1")
iot.IotDevice("127.0.0.1")
iot.IotPlug("127.0.0.1")

View File

@ -27,7 +27,7 @@ from kasa import (
)
from kasa.discover import DiscoveryResult
from kasa.iot import IotBulb, IotDevice, IotDimmer, IotLightStrip, IotPlug, IotStrip
from kasa.smart import SmartBulb, SmartDevice, SmartPlug
from kasa.smart import SmartBulb, SmartDevice
try:
from pydantic.v1 import ValidationError
@ -72,7 +72,7 @@ TYPE_TO_CLASS = {
"iot.dimmer": IotDimmer,
"iot.strip": IotStrip,
"iot.lightstrip": IotLightStrip,
"smart.plug": SmartPlug,
"smart.plug": SmartDevice,
"smart.bulb": SmartBulb,
}

View File

@ -194,32 +194,32 @@ class Device(ABC):
@property
def is_bulb(self) -> bool:
"""Return True if the device is a bulb."""
return self._device_type == DeviceType.Bulb
return self.device_type == DeviceType.Bulb
@property
def is_light_strip(self) -> bool:
"""Return True if the device is a led strip."""
return self._device_type == DeviceType.LightStrip
return self.device_type == DeviceType.LightStrip
@property
def is_plug(self) -> bool:
"""Return True if the device is a plug."""
return self._device_type == DeviceType.Plug
return self.device_type == DeviceType.Plug
@property
def is_strip(self) -> bool:
"""Return True if the device is a strip."""
return self._device_type == DeviceType.Strip
return self.device_type == DeviceType.Strip
@property
def is_strip_socket(self) -> bool:
"""Return True if the device is a strip socket."""
return self._device_type == DeviceType.StripSocket
return self.device_type == DeviceType.StripSocket
@property
def is_dimmer(self) -> bool:
"""Return True if the device is a dimmer."""
return self._device_type == DeviceType.Dimmer
return self.device_type == DeviceType.Dimmer
@property
def is_dimmable(self) -> bool:
@ -354,9 +354,9 @@ class Device(ABC):
def __repr__(self):
if self._last_update is None:
return f"<{self._device_type} at {self.host} - update() needed>"
return f"<{self.device_type} at {self.host} - update() needed>"
return (
f"<{self._device_type} model {self.model} at {self.host}"
f"<{self.device_type} model {self.model} at {self.host}"
f" ({self.alias}), is_on: {self.is_on}"
f" - dev specific: {self.state_information}>"
)

View File

@ -14,7 +14,7 @@ from .protocol import (
BaseProtocol,
BaseTransport,
)
from .smart import SmartBulb, SmartPlug
from .smart import SmartBulb, SmartDevice
from .smartprotocol import SmartProtocol
from .xortransport import XorTransport
@ -135,10 +135,10 @@ def get_device_class_from_sys_info(info: Dict[str, Any]) -> Type[IotDevice]:
def get_device_class_from_family(device_type: str) -> Optional[Type[Device]]:
"""Return the device class from the type name."""
supported_device_types: Dict[str, Type[Device]] = {
"SMART.TAPOPLUG": SmartPlug,
"SMART.TAPOPLUG": SmartDevice,
"SMART.TAPOBULB": SmartBulb,
"SMART.TAPOSWITCH": SmartBulb,
"SMART.KASAPLUG": SmartPlug,
"SMART.KASAPLUG": SmartDevice,
"SMART.KASASWITCH": SmartBulb,
"IOT.SMARTPLUGSWITCH": IotPlug,
"IOT.SMARTBULB": IotBulb,

View File

@ -2,6 +2,5 @@
from .smartbulb import SmartBulb
from .smartchilddevice import SmartChildDevice
from .smartdevice import SmartDevice
from .smartplug import SmartPlug
__all__ = ["SmartDevice", "SmartPlug", "SmartBulb", "SmartChildDevice"]
__all__ = ["SmartDevice", "SmartBulb", "SmartChildDevice"]

View File

@ -485,3 +485,28 @@ class SmartDevice(Device):
Note, this does not downgrade the firmware.
"""
await self.protocol.query("device_reset")
@property
def device_type(self) -> DeviceType:
"""Return the device type."""
if self._device_type is not DeviceType.Unknown:
return self._device_type
if self.children:
if "SMART.TAPOHUB" in self.sys_info["type"]:
pass # TODO: placeholder for future hub PR
else:
self._device_type = DeviceType.Strip
elif "light_strip" in self._components:
self._device_type = DeviceType.LightStrip
elif "dimmer_calibration" in self._components:
self._device_type = DeviceType.Dimmer
elif "brightness" in self._components:
self._device_type = DeviceType.Bulb
elif "PLUG" in self.sys_info["type"]:
self._device_type = DeviceType.Plug
else:
_LOGGER.warning("Unknown device type, falling back to plug")
self._device_type = DeviceType.Plug
return self._device_type

View File

@ -1,37 +0,0 @@
"""Module for a TAPO Plug."""
import logging
from typing import Any, Dict, Optional
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..plug import Plug
from ..smartprotocol import SmartProtocol
from .smartdevice import SmartDevice
_LOGGER = logging.getLogger(__name__)
class SmartPlug(SmartDevice, Plug):
"""Class to represent a TAPO Plug."""
def __init__(
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[SmartProtocol] = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.Plug
@property
def state_information(self) -> Dict[str, Any]:
"""Return the key state information."""
return {
**super().state_information,
**{
"On since": self.on_since,
"auto_off_status": self._info.get("auto_off_status"),
"auto_off_remain_time": self._info.get("auto_off_remain_time"),
},
}

View File

@ -20,7 +20,7 @@ from kasa import (
)
from kasa.iot import IotBulb, IotDimmer, IotLightStrip, IotPlug, IotStrip
from kasa.protocol import BaseTransport
from kasa.smart import SmartBulb, SmartPlug
from kasa.smart import SmartBulb, SmartDevice
from kasa.xortransport import XorEncryption
from .fakeprotocol_iot import FakeIotProtocol
@ -108,7 +108,6 @@ PLUGS_SMART = {
"EP25",
"KS205",
"P125M",
"P135",
"S505",
"TP15",
}
@ -121,7 +120,7 @@ STRIPS_SMART = {"P300", "TP25"}
STRIPS = {*STRIPS_IOT, *STRIPS_SMART}
DIMMERS_IOT = {"ES20M", "HS220", "KS220M", "KS230", "KP405"}
DIMMERS_SMART = {"S500D"}
DIMMERS_SMART = {"S500D", "P135"}
DIMMERS = {
*DIMMERS_IOT,
*DIMMERS_SMART,
@ -346,7 +345,7 @@ def device_for_file(model, protocol):
if protocol == "SMART":
for d in PLUGS_SMART:
if d in model:
return SmartPlug
return SmartDevice
for d in BULBS_SMART:
if d in model:
return SmartBulb
@ -355,7 +354,7 @@ def device_for_file(model, protocol):
return SmartBulb
for d in STRIPS_SMART:
if d in model:
return SmartPlug
return SmartDevice
else:
for d in STRIPS_IOT:
if d in model:

View File

@ -37,9 +37,6 @@ async def test_led(dev):
@plug_smart
async def test_plug_device_info(dev):
assert dev._info is not None
# PLUG_SCHEMA(dev.sys_info)
assert dev.model is not None
assert dev.device_type == DeviceType.Plug or dev.device_type == DeviceType.Strip
# assert dev.is_plug or dev.is_strip

View File

@ -22,16 +22,21 @@ from voluptuous import (
import kasa
from kasa import Credentials, Device, DeviceConfig, KasaException
from kasa.device_type import DeviceType
from kasa.exceptions import SmartErrorCode
from kasa.iot import IotDevice
from kasa.smart import SmartChildDevice, SmartDevice
from .conftest import (
bulb,
device_iot,
device_smart,
dimmer,
handle_turn_on,
has_emeter_iot,
lightstrip,
no_emeter_iot,
plug,
turn_on,
)
from .fakeprotocol_iot import FakeIotProtocol
@ -416,3 +421,25 @@ SYSINFO_SCHEMA = Schema(
},
extra=REMOVE_EXTRA,
)
@dimmer
def test_device_type_dimmer(dev):
assert dev.device_type == DeviceType.Dimmer
@bulb
def test_device_type_bulb(dev):
if dev.is_light_strip:
pytest.skip("bulb has also lightstrips to test the api")
assert dev.device_type == DeviceType.Bulb
@plug
def test_device_type_plug(dev):
assert dev.device_type == DeviceType.Plug
@lightstrip
def test_device_type_lightstrip(dev):
assert dev.device_type == DeviceType.LightStrip