mirror of
https://github.com/home-assistant/core
synced 2024-09-28 03:04:04 +02:00
Support for more features on smartthings AC (#99424)
* ability to set swing mode on samsung AC * support for windFree mode on samsung AC * Apply suggestions from code review Co-authored-by: G Johansson <goran.johansson@shiftit.se> * suggestion from code reviews * Apply suggestions from code review --------- Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
parent
7a727dc3ad
commit
41626ed500
@ -13,6 +13,10 @@ from homeassistant.components.climate import (
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
DOMAIN as CLIMATE_DOMAIN,
|
||||
SWING_BOTH,
|
||||
SWING_HORIZONTAL,
|
||||
SWING_OFF,
|
||||
SWING_VERTICAL,
|
||||
ClimateEntity,
|
||||
ClimateEntityFeature,
|
||||
HVACAction,
|
||||
@ -71,6 +75,20 @@ STATE_TO_AC_MODE = {
|
||||
HVACMode.FAN_ONLY: "fanOnly",
|
||||
}
|
||||
|
||||
SWING_TO_FAN_OSCILLATION = {
|
||||
SWING_BOTH: "all",
|
||||
SWING_HORIZONTAL: "horizontal",
|
||||
SWING_VERTICAL: "vertical",
|
||||
SWING_OFF: "fixed",
|
||||
}
|
||||
|
||||
FAN_OSCILLATION_TO_SWING = {
|
||||
value: key for key, value in SWING_TO_FAN_OSCILLATION.items()
|
||||
}
|
||||
|
||||
|
||||
WINDFREE = "windFree"
|
||||
|
||||
UNIT_MAP = {"C": UnitOfTemperature.CELSIUS, "F": UnitOfTemperature.FAHRENHEIT}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -322,18 +340,34 @@ class SmartThingsThermostat(SmartThingsEntity, ClimateEntity):
|
||||
class SmartThingsAirConditioner(SmartThingsEntity, ClimateEntity):
|
||||
"""Define a SmartThings Air Conditioner."""
|
||||
|
||||
_attr_supported_features = (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
||||
)
|
||||
_hvac_modes: list[HVACMode]
|
||||
|
||||
def __init__(self, device):
|
||||
def __init__(self, device) -> None:
|
||||
"""Init the class."""
|
||||
super().__init__(device)
|
||||
self._hvac_modes = None
|
||||
self._hvac_modes = []
|
||||
self._attr_preset_mode = None
|
||||
self._attr_preset_modes = self._determine_preset_modes()
|
||||
self._attr_swing_modes = self._determine_swing_modes()
|
||||
self._attr_supported_features = self._determine_supported_features()
|
||||
|
||||
def _determine_supported_features(self) -> ClimateEntityFeature:
|
||||
features = (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
||||
)
|
||||
if self._device.get_capability(Capability.fan_oscillation_mode):
|
||||
features |= ClimateEntityFeature.SWING_MODE
|
||||
if (self._attr_preset_modes is not None) and len(self._attr_preset_modes) > 0:
|
||||
features |= ClimateEntityFeature.PRESET_MODE
|
||||
return features
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new target fan mode."""
|
||||
await self._device.set_fan_mode(fan_mode, set_status=True)
|
||||
|
||||
# setting the fan must reset the preset mode (it deactivates the windFree function)
|
||||
self._attr_preset_mode = None
|
||||
|
||||
# State is set optimistically in the command above, therefore update
|
||||
# the entity state ahead of receiving the confirming push updates
|
||||
self.async_write_ha_state()
|
||||
@ -407,12 +441,12 @@ class SmartThingsAirConditioner(SmartThingsEntity, ClimateEntity):
|
||||
self._hvac_modes = list(modes)
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
def current_temperature(self) -> float | None:
|
||||
"""Return the current temperature."""
|
||||
return self._device.status.temperature
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return device specific state attributes.
|
||||
|
||||
Include attributes from the Demand Response Load Control (drlc)
|
||||
@ -432,12 +466,12 @@ class SmartThingsAirConditioner(SmartThingsEntity, ClimateEntity):
|
||||
return state_attributes
|
||||
|
||||
@property
|
||||
def fan_mode(self):
|
||||
def fan_mode(self) -> str:
|
||||
"""Return the fan setting."""
|
||||
return self._device.status.fan_mode
|
||||
|
||||
@property
|
||||
def fan_modes(self):
|
||||
def fan_modes(self) -> list[str]:
|
||||
"""Return the list of available fan modes."""
|
||||
return self._device.status.supported_ac_fan_modes
|
||||
|
||||
@ -454,11 +488,62 @@ class SmartThingsAirConditioner(SmartThingsEntity, ClimateEntity):
|
||||
return self._hvac_modes
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
def target_temperature(self) -> float:
|
||||
"""Return the temperature we try to reach."""
|
||||
return self._device.status.cooling_setpoint
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
def temperature_unit(self) -> str:
|
||||
"""Return the unit of measurement."""
|
||||
return UNIT_MAP.get(self._device.status.attributes[Attribute.temperature].unit)
|
||||
return UNIT_MAP[self._device.status.attributes[Attribute.temperature].unit]
|
||||
|
||||
def _determine_swing_modes(self) -> list[str]:
|
||||
"""Return the list of available swing modes."""
|
||||
supported_modes = self._device.status.attributes[
|
||||
Attribute.supported_fan_oscillation_modes
|
||||
][0]
|
||||
supported_swings = [
|
||||
FAN_OSCILLATION_TO_SWING.get(m, SWING_OFF) for m in supported_modes
|
||||
]
|
||||
return supported_swings
|
||||
|
||||
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
||||
"""Set swing mode."""
|
||||
fan_oscillation_mode = SWING_TO_FAN_OSCILLATION[swing_mode]
|
||||
await self._device.set_fan_oscillation_mode(fan_oscillation_mode)
|
||||
|
||||
# setting the fan must reset the preset mode (it deactivates the windFree function)
|
||||
self._attr_preset_mode = None
|
||||
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
@property
|
||||
def swing_mode(self) -> str:
|
||||
"""Return the swing setting."""
|
||||
return FAN_OSCILLATION_TO_SWING.get(
|
||||
self._device.status.fan_oscillation_mode, SWING_OFF
|
||||
)
|
||||
|
||||
def _determine_preset_modes(self) -> list[str] | None:
|
||||
"""Return a list of available preset modes."""
|
||||
supported_modes = self._device.status.attributes[
|
||||
"supportedAcOptionalMode"
|
||||
].value
|
||||
if WINDFREE in supported_modes:
|
||||
return [WINDFREE]
|
||||
return None
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set special modes (currently only windFree is supported)."""
|
||||
result = await self._device.command(
|
||||
"main",
|
||||
"custom.airConditionerOptionalMode",
|
||||
"setAcOptionalMode",
|
||||
[preset_mode],
|
||||
)
|
||||
if result:
|
||||
self._device.status.update_attribute_value("acOptionalMode", preset_mode)
|
||||
|
||||
self._attr_preset_mode = preset_mode
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
@ -15,16 +15,20 @@ from homeassistant.components.climate import (
|
||||
ATTR_HVAC_ACTION,
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_HVAC_MODES,
|
||||
ATTR_PRESET_MODE,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
DOMAIN as CLIMATE_DOMAIN,
|
||||
SERVICE_SET_FAN_MODE,
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
SERVICE_SET_SWING_MODE,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
ClimateEntityFeature,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.components.climate.const import ATTR_SWING_MODE
|
||||
from homeassistant.components.smartthings import climate
|
||||
from homeassistant.components.smartthings.const import DOMAIN
|
||||
from homeassistant.const import (
|
||||
@ -155,6 +159,7 @@ def air_conditioner_fixture(device_factory):
|
||||
Capability.switch,
|
||||
Capability.temperature_measurement,
|
||||
Capability.thermostat_cooling_setpoint,
|
||||
Capability.fan_oscillation_mode,
|
||||
],
|
||||
status={
|
||||
Attribute.air_conditioner_mode: "auto",
|
||||
@ -182,6 +187,14 @@ def air_conditioner_fixture(device_factory):
|
||||
],
|
||||
Attribute.switch: "on",
|
||||
Attribute.cooling_setpoint: 23,
|
||||
"supportedAcOptionalMode": ["windFree"],
|
||||
Attribute.supported_fan_oscillation_modes: [
|
||||
"all",
|
||||
"horizontal",
|
||||
"vertical",
|
||||
"fixed",
|
||||
],
|
||||
Attribute.fan_oscillation_mode: "vertical",
|
||||
},
|
||||
)
|
||||
device.status.attributes[Attribute.temperature] = Status(24, "C", None)
|
||||
@ -303,7 +316,10 @@ async def test_air_conditioner_entity_state(
|
||||
assert state.state == HVACMode.HEAT_COOL
|
||||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.FAN_MODE | ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
== ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.SWING_MODE
|
||||
)
|
||||
assert sorted(state.attributes[ATTR_HVAC_MODES]) == [
|
||||
HVACMode.COOL,
|
||||
@ -591,3 +607,40 @@ async def test_entity_and_device_attributes(hass: HomeAssistant, thermostat) ->
|
||||
assert entry.manufacturer == "Generic manufacturer"
|
||||
assert entry.hw_version == "v4.56"
|
||||
assert entry.sw_version == "v7.89"
|
||||
|
||||
|
||||
async def test_set_windfree_off(hass: HomeAssistant, air_conditioner) -> None:
|
||||
"""Test if the windfree preset can be turned on and is turned off when fan mode is set."""
|
||||
entity_ids = ["climate.air_conditioner"]
|
||||
air_conditioner.status.update_attribute_value(Attribute.switch, "on")
|
||||
await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner])
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_ids, ATTR_PRESET_MODE: "windFree"},
|
||||
blocking=True,
|
||||
)
|
||||
state = hass.states.get("climate.air_conditioner")
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "windFree"
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_FAN_MODE,
|
||||
{ATTR_ENTITY_ID: entity_ids, ATTR_FAN_MODE: "low"},
|
||||
blocking=True,
|
||||
)
|
||||
state = hass.states.get("climate.air_conditioner")
|
||||
assert not state.attributes[ATTR_PRESET_MODE]
|
||||
|
||||
|
||||
async def test_set_swing_mode(hass: HomeAssistant, air_conditioner) -> None:
|
||||
"""Test the fan swing is set successfully."""
|
||||
await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner])
|
||||
entity_ids = ["climate.air_conditioner"]
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_SWING_MODE,
|
||||
{ATTR_ENTITY_ID: entity_ids, ATTR_SWING_MODE: "vertical"},
|
||||
blocking=True,
|
||||
)
|
||||
state = hass.states.get("climate.air_conditioner")
|
||||
assert state.attributes[ATTR_SWING_MODE] == "vertical"
|
||||
|
Loading…
Reference in New Issue
Block a user