Add temperature control module for smart (#848)

This commit is contained in:
Teemu R 2024-04-22 13:39:07 +02:00 committed by GitHub
parent 890900daf3
commit 72db5c6447
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 125 additions and 0 deletions

View File

@ -19,6 +19,7 @@ class DeviceType(Enum):
Sensor = "sensor"
Hub = "hub"
Fan = "fan"
Thermostat = "thermostat"
Unknown = "unknown"
@staticmethod

View File

@ -17,6 +17,7 @@ from .ledmodule import LedModule
from .lighttransitionmodule import LightTransitionModule
from .reportmodule import ReportModule
from .temperature import TemperatureSensor
from .temperaturecontrol import TemperatureControl
from .timemodule import TimeModule
__all__ = [
@ -28,6 +29,7 @@ __all__ = [
"BatterySensor",
"HumiditySensor",
"TemperatureSensor",
"TemperatureControl",
"ReportModule",
"AutoOffModule",
"LedModule",

View File

@ -0,0 +1,87 @@
"""Implementation of temperature control module."""
from __future__ import annotations
from typing import TYPE_CHECKING
from ...feature import Feature
from ..smartmodule import SmartModule
if TYPE_CHECKING:
from ..smartdevice import SmartDevice
class TemperatureControl(SmartModule):
"""Implementation of temperature module."""
REQUIRED_COMPONENT = "temperature_control"
def __init__(self, device: SmartDevice, module: str):
super().__init__(device, module)
self._add_feature(
Feature(
device,
"Target temperature",
container=self,
attribute_getter="target_temperature",
attribute_setter="set_target_temperature",
icon="mdi:thermometer",
)
)
# TODO: this might belong into its own module, temperature_correction?
self._add_feature(
Feature(
device,
"Temperature offset",
container=self,
attribute_getter="temperature_offset",
attribute_setter="set_temperature_offset",
minimum_value=-10,
maximum_value=10,
)
)
def query(self) -> dict:
"""Query to execute during the update cycle."""
# Target temperature is contained in the main device info response.
return {}
@property
def minimum_target_temperature(self) -> int:
"""Minimum available target temperature."""
return self._device.sys_info["min_control_temp"]
@property
def maximum_target_temperature(self) -> int:
"""Minimum available target temperature."""
return self._device.sys_info["max_control_temp"]
@property
def target_temperature(self) -> int:
"""Return target temperature."""
return self._device.sys_info["target_temperature"]
async def set_target_temperature(self, target: int):
"""Set target temperature."""
if (
target < self.minimum_target_temperature
or target > self.maximum_target_temperature
):
raise ValueError(
f"Invalid target temperature {target}, must be in range "
f"[{self.minimum_target_temperature},{self.maximum_target_temperature}]"
)
return await self.call("set_device_info", {"target_temp": target})
@property
def temperature_offset(self) -> int:
"""Return temperature offset."""
return self._device.sys_info["temp_offset"]
async def set_temperature_offset(self, offset: int):
"""Set temperature offset."""
if offset < -10 or offset > 10:
raise ValueError("Temperature offset must be [-10, 10]")
return await self.call("set_device_info", {"temp_offset": offset})

View File

@ -52,6 +52,7 @@ class SmartChildDevice(SmartDevice):
"subg.trigger.temp-hmdt-sensor": DeviceType.Sensor,
"kasa.switch.outlet.sub-fan": DeviceType.Fan,
"kasa.switch.outlet.sub-dimmer": DeviceType.Dimmer,
"subg.trv": DeviceType.Thermostat,
}
dev_type = child_device_map.get(self.sys_info["category"])
if dev_type is None:

View File

@ -0,0 +1,34 @@
import pytest
from kasa.smart.modules import TemperatureSensor
from kasa.tests.device_fixtures import parametrize
temperature = parametrize(
"has temperature control",
component_filter="temperature_control",
protocol_filter={"SMART.CHILD"},
)
@temperature
@pytest.mark.parametrize(
"feature, type",
[
("target_temperature", int),
("temperature_offset", int),
],
)
async def test_temperature_control_features(dev, feature, type):
"""Test that features are registered and work as expected."""
temp_module: TemperatureSensor = dev.modules["TemperatureControl"]
prop = getattr(temp_module, feature)
assert isinstance(prop, type)
feat = temp_module._module_features[feature]
assert feat.value == prop
assert isinstance(feat.value, type)
await feat.set_value(10)
await dev.update()
assert feat.value == 10