mirror of
https://github.com/home-assistant/core.git
synced 2025-04-26 02:07:54 +00:00
Add entity service - Set Full AC state to Sensibo (#80820)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
d4a5393f7b
commit
57b2bb4889
@ -7,12 +7,15 @@ from typing import TYPE_CHECKING, Any
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
|
ATTR_FAN_MODE,
|
||||||
|
ATTR_SWING_MODE,
|
||||||
ClimateEntity,
|
ClimateEntity,
|
||||||
ClimateEntityFeature,
|
ClimateEntityFeature,
|
||||||
HVACMode,
|
HVACMode,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_MODE,
|
||||||
ATTR_STATE,
|
ATTR_STATE,
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
PRECISION_TENTHS,
|
PRECISION_TENTHS,
|
||||||
@ -34,12 +37,16 @@ SERVICE_ENABLE_TIMER = "enable_timer"
|
|||||||
ATTR_MINUTES = "minutes"
|
ATTR_MINUTES = "minutes"
|
||||||
SERVICE_ENABLE_PURE_BOOST = "enable_pure_boost"
|
SERVICE_ENABLE_PURE_BOOST = "enable_pure_boost"
|
||||||
SERVICE_DISABLE_PURE_BOOST = "disable_pure_boost"
|
SERVICE_DISABLE_PURE_BOOST = "disable_pure_boost"
|
||||||
|
SERVICE_FULL_STATE = "full_state"
|
||||||
|
|
||||||
ATTR_AC_INTEGRATION = "ac_integration"
|
ATTR_AC_INTEGRATION = "ac_integration"
|
||||||
ATTR_GEO_INTEGRATION = "geo_integration"
|
ATTR_GEO_INTEGRATION = "geo_integration"
|
||||||
ATTR_INDOOR_INTEGRATION = "indoor_integration"
|
ATTR_INDOOR_INTEGRATION = "indoor_integration"
|
||||||
ATTR_OUTDOOR_INTEGRATION = "outdoor_integration"
|
ATTR_OUTDOOR_INTEGRATION = "outdoor_integration"
|
||||||
ATTR_SENSITIVITY = "sensitivity"
|
ATTR_SENSITIVITY = "sensitivity"
|
||||||
|
ATTR_TARGET_TEMPERATURE = "target_temperature"
|
||||||
|
ATTR_HORIZONTAL_SWING_MODE = "horizontal_swing_mode"
|
||||||
|
ATTR_LIGHT = "light"
|
||||||
BOOST_INCLUSIVE = "boost_inclusive"
|
BOOST_INCLUSIVE = "boost_inclusive"
|
||||||
|
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
@ -118,6 +125,20 @@ async def async_setup_entry(
|
|||||||
},
|
},
|
||||||
"async_enable_pure_boost",
|
"async_enable_pure_boost",
|
||||||
)
|
)
|
||||||
|
platform.async_register_entity_service(
|
||||||
|
SERVICE_FULL_STATE,
|
||||||
|
{
|
||||||
|
vol.Required(ATTR_MODE): vol.In(
|
||||||
|
["cool", "heat", "fan", "auto", "dry", "off"]
|
||||||
|
),
|
||||||
|
vol.Optional(ATTR_TARGET_TEMPERATURE): int,
|
||||||
|
vol.Optional(ATTR_FAN_MODE): str,
|
||||||
|
vol.Optional(ATTR_SWING_MODE): str,
|
||||||
|
vol.Optional(ATTR_HORIZONTAL_SWING_MODE): str,
|
||||||
|
vol.Optional(ATTR_LIGHT): vol.In(["on", "off"]),
|
||||||
|
},
|
||||||
|
"async_full_ac_state",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
||||||
@ -335,6 +356,37 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
|||||||
assumed_state=True,
|
assumed_state=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_full_ac_state(
|
||||||
|
self,
|
||||||
|
mode: str,
|
||||||
|
target_temperature: int | None = None,
|
||||||
|
fan_mode: str | None = None,
|
||||||
|
swing_mode: str | None = None,
|
||||||
|
horizontal_swing_mode: str | None = None,
|
||||||
|
light: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Set full AC state."""
|
||||||
|
new_ac_state = self.device_data.ac_states
|
||||||
|
new_ac_state.pop("timestamp")
|
||||||
|
new_ac_state["on"] = False
|
||||||
|
if mode != "off":
|
||||||
|
new_ac_state["on"] = True
|
||||||
|
new_ac_state["mode"] = mode
|
||||||
|
if target_temperature:
|
||||||
|
new_ac_state["targetTemperature"] = target_temperature
|
||||||
|
if fan_mode:
|
||||||
|
new_ac_state["fanLevel"] = fan_mode
|
||||||
|
if swing_mode:
|
||||||
|
new_ac_state["swing"] = swing_mode
|
||||||
|
if horizontal_swing_mode:
|
||||||
|
new_ac_state["horizontalSwing"] = horizontal_swing_mode
|
||||||
|
if light:
|
||||||
|
new_ac_state["light"] = light
|
||||||
|
|
||||||
|
await self.api_call_custom_service_full_ac_state(
|
||||||
|
key="hvac_mode", value=mode, data=new_ac_state
|
||||||
|
)
|
||||||
|
|
||||||
async def async_enable_timer(self, minutes: int) -> None:
|
async def async_enable_timer(self, minutes: int) -> None:
|
||||||
"""Enable the timer."""
|
"""Enable the timer."""
|
||||||
new_state = bool(self.device_data.ac_states["on"] is False)
|
new_state = bool(self.device_data.ac_states["on"] is False)
|
||||||
@ -419,3 +471,14 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
|||||||
result = {}
|
result = {}
|
||||||
result = await self._client.async_set_pureboost(self._device_id, data)
|
result = await self._client.async_set_pureboost(self._device_id, data)
|
||||||
return bool(result.get("status") == "success")
|
return bool(result.get("status") == "success")
|
||||||
|
|
||||||
|
@async_handle_api_call
|
||||||
|
async def api_call_custom_service_full_ac_state(
|
||||||
|
self,
|
||||||
|
key: str,
|
||||||
|
value: Any,
|
||||||
|
data: dict,
|
||||||
|
) -> bool:
|
||||||
|
"""Make service call to api."""
|
||||||
|
result = await self._client.async_set_ac_states(self._device_id, data)
|
||||||
|
return bool(result.get("result", {}).get("status") == "Success")
|
||||||
|
@ -80,3 +80,69 @@ enable_pure_boost:
|
|||||||
options:
|
options:
|
||||||
- "Normal"
|
- "Normal"
|
||||||
- "Sensitive"
|
- "Sensitive"
|
||||||
|
full_state:
|
||||||
|
name: Set full state
|
||||||
|
description: Set full state for Sensibo device
|
||||||
|
target:
|
||||||
|
entity:
|
||||||
|
integration: sensibo
|
||||||
|
domain: climate
|
||||||
|
fields:
|
||||||
|
mode:
|
||||||
|
name: HVAC mode
|
||||||
|
description: HVAC mode to set
|
||||||
|
required: true
|
||||||
|
example: "heat"
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- "cool"
|
||||||
|
- "heat"
|
||||||
|
- "fan"
|
||||||
|
- "auto"
|
||||||
|
- "dry"
|
||||||
|
- "off"
|
||||||
|
target_temperature:
|
||||||
|
name: Target Temperature
|
||||||
|
description: Optionally set target temperature
|
||||||
|
required: false
|
||||||
|
example: 23
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 0
|
||||||
|
step: 1
|
||||||
|
mode: box
|
||||||
|
fan_mode:
|
||||||
|
name: Fan mode
|
||||||
|
description: Optionally set fan mode
|
||||||
|
required: false
|
||||||
|
example: "low"
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
type: text
|
||||||
|
swing_mode:
|
||||||
|
name: swing mode
|
||||||
|
description: Optionally set swing mode
|
||||||
|
required: false
|
||||||
|
example: "fixedBottom"
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
type: text
|
||||||
|
horizontal_swing_mode:
|
||||||
|
name: Horizontal swing mode
|
||||||
|
description: Optionally set horizontal swing mode
|
||||||
|
required: false
|
||||||
|
example: "fixedLeft"
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
type: text
|
||||||
|
light:
|
||||||
|
name: Light
|
||||||
|
description: Set light on or off
|
||||||
|
required: false
|
||||||
|
example: "on"
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- "on"
|
||||||
|
- "off"
|
||||||
|
@ -23,19 +23,24 @@ from homeassistant.components.climate import (
|
|||||||
from homeassistant.components.sensibo.climate import (
|
from homeassistant.components.sensibo.climate import (
|
||||||
ATTR_AC_INTEGRATION,
|
ATTR_AC_INTEGRATION,
|
||||||
ATTR_GEO_INTEGRATION,
|
ATTR_GEO_INTEGRATION,
|
||||||
|
ATTR_HORIZONTAL_SWING_MODE,
|
||||||
ATTR_INDOOR_INTEGRATION,
|
ATTR_INDOOR_INTEGRATION,
|
||||||
|
ATTR_LIGHT,
|
||||||
ATTR_MINUTES,
|
ATTR_MINUTES,
|
||||||
ATTR_OUTDOOR_INTEGRATION,
|
ATTR_OUTDOOR_INTEGRATION,
|
||||||
ATTR_SENSITIVITY,
|
ATTR_SENSITIVITY,
|
||||||
|
ATTR_TARGET_TEMPERATURE,
|
||||||
SERVICE_ASSUME_STATE,
|
SERVICE_ASSUME_STATE,
|
||||||
SERVICE_ENABLE_PURE_BOOST,
|
SERVICE_ENABLE_PURE_BOOST,
|
||||||
SERVICE_ENABLE_TIMER,
|
SERVICE_ENABLE_TIMER,
|
||||||
|
SERVICE_FULL_STATE,
|
||||||
_find_valid_target_temp,
|
_find_valid_target_temp,
|
||||||
)
|
)
|
||||||
from homeassistant.components.sensibo.const import DOMAIN
|
from homeassistant.components.sensibo.const import DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
|
ATTR_MODE,
|
||||||
ATTR_STATE,
|
ATTR_STATE,
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
@ -916,3 +921,91 @@ async def test_climate_pure_boost(
|
|||||||
assert state2.state == "on"
|
assert state2.state == "on"
|
||||||
assert state3.state == "on"
|
assert state3.state == "on"
|
||||||
assert state4.state == "s"
|
assert state4.state == "s"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_climate_full_ac_state(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry_enabled_by_default: AsyncMock,
|
||||||
|
load_int: ConfigEntry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
get_data: SensiboData,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Sensibo climate Full AC state service."""
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
|
||||||
|
return_value=get_data,
|
||||||
|
):
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass,
|
||||||
|
dt.utcnow() + timedelta(minutes=5),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state_climate = hass.states.get("climate.hallway")
|
||||||
|
assert state_climate.state == "heat"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_states",
|
||||||
|
):
|
||||||
|
with pytest.raises(MultipleInvalid):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_FULL_STATE,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: state_climate.entity_id,
|
||||||
|
ATTR_TARGET_TEMPERATURE: 22,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
|
||||||
|
return_value=get_data,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_states",
|
||||||
|
return_value={"result": {"status": "Success"}},
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_FULL_STATE,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: state_climate.entity_id,
|
||||||
|
ATTR_MODE: "cool",
|
||||||
|
ATTR_TARGET_TEMPERATURE: 22,
|
||||||
|
ATTR_FAN_MODE: "high",
|
||||||
|
ATTR_SWING_MODE: "stopped",
|
||||||
|
ATTR_HORIZONTAL_SWING_MODE: "stopped",
|
||||||
|
ATTR_LIGHT: "on",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "hvac_mode", "cool")
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "device_on", True)
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "target_temp", 22)
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "fan_mode", "high")
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "swing_mode", "stopped")
|
||||||
|
monkeypatch.setattr(
|
||||||
|
get_data.parsed["ABC999111"], "horizontal_swing_mode", "stopped"
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(get_data.parsed["ABC999111"], "light_mode", "on")
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
|
||||||
|
return_value=get_data,
|
||||||
|
):
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass,
|
||||||
|
dt.utcnow() + timedelta(minutes=5),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("climate.hallway")
|
||||||
|
|
||||||
|
assert state.state == "cool"
|
||||||
|
assert state.attributes["temperature"] == 22
|
||||||
|
Loading…
x
Reference in New Issue
Block a user