Sensibo use switch for Pure boost (#73833)
* Initial commit * Finalize pure boost switch * Fix service required
This commit is contained in:
parent
837957d89e
commit
532e25d087
7 changed files with 140 additions and 97 deletions
|
@ -99,13 +99,6 @@ DEVICE_SENSOR_TYPES: tuple[SensiboDeviceBinarySensorEntityDescription, ...] = (
|
|||
)
|
||||
|
||||
PURE_SENSOR_TYPES: tuple[SensiboDeviceBinarySensorEntityDescription, ...] = (
|
||||
SensiboDeviceBinarySensorEntityDescription(
|
||||
key="pure_boost_enabled",
|
||||
device_class=BinarySensorDeviceClass.RUNNING,
|
||||
name="Pure Boost Enabled",
|
||||
icon="mdi:wind-power-outline",
|
||||
value_fn=lambda data: data.pure_boost_enabled,
|
||||
),
|
||||
SensiboDeviceBinarySensorEntityDescription(
|
||||
key="pure_ac_integration",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
|
|
|
@ -107,21 +107,14 @@ async def async_setup_entry(
|
|||
platform.async_register_entity_service(
|
||||
SERVICE_ENABLE_PURE_BOOST,
|
||||
{
|
||||
vol.Inclusive(ATTR_AC_INTEGRATION, "settings"): bool,
|
||||
vol.Inclusive(ATTR_GEO_INTEGRATION, "settings"): bool,
|
||||
vol.Inclusive(ATTR_INDOOR_INTEGRATION, "settings"): bool,
|
||||
vol.Inclusive(ATTR_OUTDOOR_INTEGRATION, "settings"): bool,
|
||||
vol.Inclusive(ATTR_SENSITIVITY, "settings"): vol.In(
|
||||
["Normal", "Sensitive"]
|
||||
),
|
||||
vol.Required(ATTR_AC_INTEGRATION): bool,
|
||||
vol.Required(ATTR_GEO_INTEGRATION): bool,
|
||||
vol.Required(ATTR_INDOOR_INTEGRATION): bool,
|
||||
vol.Required(ATTR_OUTDOOR_INTEGRATION): bool,
|
||||
vol.Required(ATTR_SENSITIVITY): vol.In(["Normal", "Sensitive"]),
|
||||
},
|
||||
"async_enable_pure_boost",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_DISABLE_PURE_BOOST,
|
||||
{},
|
||||
"async_disable_pure_boost",
|
||||
)
|
||||
|
||||
|
||||
class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
||||
|
@ -353,9 +346,3 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
|||
|
||||
await self.async_send_command("set_pure_boost", params)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_disable_pure_boost(self) -> None:
|
||||
"""Disable Pure Boost Configuration."""
|
||||
|
||||
await self.async_send_command("set_pure_boost", {"enabled": False})
|
||||
await self.coordinator.async_refresh()
|
||||
|
|
|
@ -45,45 +45,38 @@ enable_pure_boost:
|
|||
ac_integration:
|
||||
name: AC Integration
|
||||
description: Integrate with Air Conditioner.
|
||||
required: false
|
||||
required: true
|
||||
example: true
|
||||
selector:
|
||||
boolean:
|
||||
geo_integration:
|
||||
name: Geo Integration
|
||||
description: Integrate with Presence.
|
||||
required: false
|
||||
required: true
|
||||
example: true
|
||||
selector:
|
||||
boolean:
|
||||
indoor_integration:
|
||||
name: Indoor Air Quality
|
||||
description: Integrate with checking indoor air quality.
|
||||
required: false
|
||||
required: true
|
||||
example: true
|
||||
selector:
|
||||
boolean:
|
||||
outdoor_integration:
|
||||
name: Outdoor Air Quality
|
||||
description: Integrate with checking outdoor air quality.
|
||||
required: false
|
||||
required: true
|
||||
example: true
|
||||
selector:
|
||||
boolean:
|
||||
sensitivity:
|
||||
name: Sensitivity
|
||||
description: Set the sensitivity for Pure Boost.
|
||||
required: false
|
||||
required: true
|
||||
example: "Normal"
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "Normal"
|
||||
- "Sensitive"
|
||||
disable_pure_boost:
|
||||
name: Disable Pure Boost
|
||||
description: Disable Pure Boost.
|
||||
target:
|
||||
entity:
|
||||
integration: sensibo
|
||||
domain: climate
|
||||
|
|
|
@ -29,7 +29,7 @@ class DeviceBaseEntityDescriptionMixin:
|
|||
"""Mixin for required Sensibo base description keys."""
|
||||
|
||||
value_fn: Callable[[SensiboDevice], bool | None]
|
||||
extra_fn: Callable[[SensiboDevice], dict[str, str | bool | None]]
|
||||
extra_fn: Callable[[SensiboDevice], dict[str, str | bool | None]] | None
|
||||
command_on: str
|
||||
command_off: str
|
||||
remote_key: str
|
||||
|
@ -56,6 +56,19 @@ DEVICE_SWITCH_TYPES: tuple[SensiboDeviceSwitchEntityDescription, ...] = (
|
|||
),
|
||||
)
|
||||
|
||||
PURE_SWITCH_TYPES: tuple[SensiboDeviceSwitchEntityDescription, ...] = (
|
||||
SensiboDeviceSwitchEntityDescription(
|
||||
key="pure_boost_switch",
|
||||
device_class=SwitchDeviceClass.SWITCH,
|
||||
name="Pure Boost",
|
||||
value_fn=lambda data: data.pure_boost_enabled,
|
||||
extra_fn=None,
|
||||
command_on="set_pure_boost",
|
||||
command_off="set_pure_boost",
|
||||
remote_key="pure_boost_enabled",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def build_params(command: str, device_data: SensiboDevice) -> dict[str, Any] | None:
|
||||
"""Build params for turning on switch."""
|
||||
|
@ -66,6 +79,16 @@ def build_params(command: str, device_data: SensiboDevice) -> dict[str, Any] | N
|
|||
"acState": {**device_data.ac_states, "on": new_state},
|
||||
}
|
||||
return params
|
||||
if command == "set_pure_boost":
|
||||
new_state = bool(device_data.pure_boost_enabled is False)
|
||||
params = {"enabled": new_state}
|
||||
if device_data.pure_measure_integration is None:
|
||||
params["sensitivity"] = "N"
|
||||
params["measurementsIntegration"] = True
|
||||
params["acIntegration"] = False
|
||||
params["geoIntegration"] = False
|
||||
params["primeIntegration"] = False
|
||||
return params
|
||||
return None
|
||||
|
||||
|
||||
|
@ -84,6 +107,12 @@ async def async_setup_entry(
|
|||
for device_id, device_data in coordinator.data.parsed.items()
|
||||
if device_data.model != "pure"
|
||||
)
|
||||
entities.extend(
|
||||
SensiboDeviceSwitch(coordinator, device_id, description)
|
||||
for description in PURE_SWITCH_TYPES
|
||||
for device_id, device_data in coordinator.data.parsed.items()
|
||||
if device_data.model == "pure"
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
@ -130,7 +159,10 @@ class SensiboDeviceSwitch(SensiboDeviceBaseEntity, SwitchEntity):
|
|||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity off."""
|
||||
result = await self.async_send_command(self.entity_description.command_off)
|
||||
params = build_params(self.entity_description.command_on, self.device_data)
|
||||
result = await self.async_send_command(
|
||||
self.entity_description.command_off, params
|
||||
)
|
||||
|
||||
if result["status"] == "success":
|
||||
setattr(self.device_data, self.entity_description.remote_key, False)
|
||||
|
@ -141,6 +173,8 @@ class SensiboDeviceSwitch(SensiboDeviceBaseEntity, SwitchEntity):
|
|||
)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> Mapping[str, Any]:
|
||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||
"""Return additional attributes."""
|
||||
return self.entity_description.extra_fn(self.device_data)
|
||||
if self.entity_description.extra_fn:
|
||||
return self.entity_description.extra_fn(self.device_data)
|
||||
return None
|
||||
|
|
|
@ -27,20 +27,18 @@ async def test_binary_sensor(
|
|||
state2 = hass.states.get("binary_sensor.hallway_motion_sensor_main_sensor")
|
||||
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion")
|
||||
state4 = hass.states.get("binary_sensor.hallway_room_occupied")
|
||||
state5 = hass.states.get("binary_sensor.kitchen_pure_boost_enabled")
|
||||
state6 = hass.states.get(
|
||||
state5 = hass.states.get(
|
||||
"binary_sensor.kitchen_pure_boost_linked_with_indoor_air_quality"
|
||||
)
|
||||
state7 = hass.states.get(
|
||||
state6 = hass.states.get(
|
||||
"binary_sensor.kitchen_pure_boost_linked_with_outdoor_air_quality"
|
||||
)
|
||||
assert state1.state == "on"
|
||||
assert state2.state == "on"
|
||||
assert state3.state == "on"
|
||||
assert state4.state == "on"
|
||||
assert state5.state == "off"
|
||||
assert state6.state == "on"
|
||||
assert state7.state == "off"
|
||||
assert state5.state == "on"
|
||||
assert state6.state == "off"
|
||||
|
||||
monkeypatch.setattr(
|
||||
get_data.parsed["ABC999111"].motion_sensors["AABBCC"], "alive", False
|
||||
|
|
|
@ -28,7 +28,6 @@ from homeassistant.components.sensibo.climate import (
|
|||
ATTR_OUTDOOR_INTEGRATION,
|
||||
ATTR_SENSITIVITY,
|
||||
SERVICE_ASSUME_STATE,
|
||||
SERVICE_DISABLE_PURE_BOOST,
|
||||
SERVICE_ENABLE_PURE_BOOST,
|
||||
SERVICE_ENABLE_TIMER,
|
||||
_find_valid_target_temp,
|
||||
|
@ -809,7 +808,7 @@ async def test_climate_pure_boost(
|
|||
await hass.async_block_till_done()
|
||||
|
||||
state_climate = hass.states.get("climate.kitchen")
|
||||
state2 = hass.states.get("binary_sensor.kitchen_pure_boost_enabled")
|
||||
state2 = hass.states.get("switch.kitchen_pure_boost")
|
||||
assert state2.state == "off"
|
||||
|
||||
with patch(
|
||||
|
@ -878,7 +877,7 @@ async def test_climate_pure_boost(
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state1 = hass.states.get("binary_sensor.kitchen_pure_boost_enabled")
|
||||
state1 = hass.states.get("switch.kitchen_pure_boost")
|
||||
state2 = hass.states.get(
|
||||
"binary_sensor.kitchen_pure_boost_linked_with_indoor_air_quality"
|
||||
)
|
||||
|
@ -890,49 +889,3 @@ async def test_climate_pure_boost(
|
|||
assert state2.state == "on"
|
||||
assert state3.state == "on"
|
||||
assert state4.state == "s"
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
|
||||
return_value=get_data,
|
||||
), patch(
|
||||
"homeassistant.components.sensibo.coordinator.SensiboClient.async_set_pureboost",
|
||||
return_value={
|
||||
"status": "success",
|
||||
"result": {
|
||||
"enabled": False,
|
||||
"sensitivity": "S",
|
||||
"measurements_integration": True,
|
||||
"ac_integration": False,
|
||||
"geo_integration": False,
|
||||
"prime_integration": True,
|
||||
},
|
||||
},
|
||||
) as mock_set_pureboost:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_DISABLE_PURE_BOOST,
|
||||
{
|
||||
ATTR_ENTITY_ID: state_climate.entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
mock_set_pureboost.assert_called_once()
|
||||
|
||||
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_boost_enabled", False)
|
||||
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_sensitivity", "s")
|
||||
|
||||
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()
|
||||
|
||||
state1 = hass.states.get("binary_sensor.kitchen_pure_boost_enabled")
|
||||
state4 = hass.states.get("sensor.kitchen_pure_sensitivity")
|
||||
assert state1.state == "off"
|
||||
assert state4.state == "s"
|
||||
|
|
|
@ -25,7 +25,7 @@ from homeassistant.util import dt
|
|||
from tests.common import async_fire_time_changed
|
||||
|
||||
|
||||
async def test_switch(
|
||||
async def test_switch_timer(
|
||||
hass: HomeAssistant,
|
||||
load_int: ConfigEntry,
|
||||
monkeypatch: MonkeyPatch,
|
||||
|
@ -105,6 +105,81 @@ async def test_switch(
|
|||
assert state1.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_switch_pure_boost(
|
||||
hass: HomeAssistant,
|
||||
load_int: ConfigEntry,
|
||||
monkeypatch: MonkeyPatch,
|
||||
get_data: SensiboData,
|
||||
) -> None:
|
||||
"""Test the Sensibo switch."""
|
||||
|
||||
state1 = hass.states.get("switch.kitchen_pure_boost")
|
||||
assert state1.state == STATE_OFF
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
|
||||
return_value=get_data,
|
||||
), patch(
|
||||
"homeassistant.components.sensibo.util.SensiboClient.async_set_pureboost",
|
||||
return_value={"status": "success"},
|
||||
):
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: state1.entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_boost_enabled", True)
|
||||
|
||||
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()
|
||||
state1 = hass.states.get("switch.kitchen_pure_boost")
|
||||
assert state1.state == STATE_ON
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
|
||||
return_value=get_data,
|
||||
), patch(
|
||||
"homeassistant.components.sensibo.util.SensiboClient.async_set_pureboost",
|
||||
return_value={"status": "success"},
|
||||
):
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{
|
||||
ATTR_ENTITY_ID: state1.entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_boost_enabled", False)
|
||||
|
||||
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()
|
||||
|
||||
state1 = hass.states.get("switch.kitchen_pure_boost")
|
||||
assert state1.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_switch_command_failure(
|
||||
hass: HomeAssistant,
|
||||
load_int: ConfigEntry,
|
||||
|
@ -162,4 +237,14 @@ async def test_build_params(
|
|||
"minutesFromNow": 60,
|
||||
"acState": {**get_data.parsed["ABC999111"].ac_states, "on": False},
|
||||
}
|
||||
|
||||
monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pure_measure_integration", None)
|
||||
assert build_params("set_pure_boost", get_data.parsed["AAZZAAZZ"]) == {
|
||||
"enabled": True,
|
||||
"sensitivity": "N",
|
||||
"measurementsIntegration": True,
|
||||
"acIntegration": False,
|
||||
"geoIntegration": False,
|
||||
"primeIntegration": False,
|
||||
}
|
||||
assert build_params("incorrect_command", get_data.parsed["ABC999111"]) is None
|
||||
|
|
Loading…
Add table
Reference in a new issue