Add entity service - Set Full AC state to Sensibo (#80820)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
G Johansson 2022-10-23 20:55:53 +02:00 committed by GitHub
parent d4a5393f7b
commit 57b2bb4889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 222 additions and 0 deletions

View File

@ -7,12 +7,15 @@ from typing import TYPE_CHECKING, Any
import voluptuous as vol
from homeassistant.components.climate import (
ATTR_FAN_MODE,
ATTR_SWING_MODE,
ClimateEntity,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_MODE,
ATTR_STATE,
ATTR_TEMPERATURE,
PRECISION_TENTHS,
@ -34,12 +37,16 @@ SERVICE_ENABLE_TIMER = "enable_timer"
ATTR_MINUTES = "minutes"
SERVICE_ENABLE_PURE_BOOST = "enable_pure_boost"
SERVICE_DISABLE_PURE_BOOST = "disable_pure_boost"
SERVICE_FULL_STATE = "full_state"
ATTR_AC_INTEGRATION = "ac_integration"
ATTR_GEO_INTEGRATION = "geo_integration"
ATTR_INDOOR_INTEGRATION = "indoor_integration"
ATTR_OUTDOOR_INTEGRATION = "outdoor_integration"
ATTR_SENSITIVITY = "sensitivity"
ATTR_TARGET_TEMPERATURE = "target_temperature"
ATTR_HORIZONTAL_SWING_MODE = "horizontal_swing_mode"
ATTR_LIGHT = "light"
BOOST_INCLUSIVE = "boost_inclusive"
PARALLEL_UPDATES = 0
@ -118,6 +125,20 @@ async def async_setup_entry(
},
"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):
@ -335,6 +356,37 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
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:
"""Enable the timer."""
new_state = bool(self.device_data.ac_states["on"] is False)
@ -419,3 +471,14 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
result = {}
result = await self._client.async_set_pureboost(self._device_id, data)
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")

View File

@ -80,3 +80,69 @@ enable_pure_boost:
options:
- "Normal"
- "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"

View File

@ -23,19 +23,24 @@ from homeassistant.components.climate import (
from homeassistant.components.sensibo.climate import (
ATTR_AC_INTEGRATION,
ATTR_GEO_INTEGRATION,
ATTR_HORIZONTAL_SWING_MODE,
ATTR_INDOOR_INTEGRATION,
ATTR_LIGHT,
ATTR_MINUTES,
ATTR_OUTDOOR_INTEGRATION,
ATTR_SENSITIVITY,
ATTR_TARGET_TEMPERATURE,
SERVICE_ASSUME_STATE,
SERVICE_ENABLE_PURE_BOOST,
SERVICE_ENABLE_TIMER,
SERVICE_FULL_STATE,
_find_valid_target_temp,
)
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_MODE,
ATTR_STATE,
ATTR_TEMPERATURE,
SERVICE_TURN_OFF,
@ -916,3 +921,91 @@ async def test_climate_pure_boost(
assert state2.state == "on"
assert state3.state == "on"
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