mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
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
@ -99,13 +99,6 @@ DEVICE_SENSOR_TYPES: tuple[SensiboDeviceBinarySensorEntityDescription, ...] = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
PURE_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(
|
SensiboDeviceBinarySensorEntityDescription(
|
||||||
key="pure_ac_integration",
|
key="pure_ac_integration",
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
@ -107,21 +107,14 @@ async def async_setup_entry(
|
|||||||
platform.async_register_entity_service(
|
platform.async_register_entity_service(
|
||||||
SERVICE_ENABLE_PURE_BOOST,
|
SERVICE_ENABLE_PURE_BOOST,
|
||||||
{
|
{
|
||||||
vol.Inclusive(ATTR_AC_INTEGRATION, "settings"): bool,
|
vol.Required(ATTR_AC_INTEGRATION): bool,
|
||||||
vol.Inclusive(ATTR_GEO_INTEGRATION, "settings"): bool,
|
vol.Required(ATTR_GEO_INTEGRATION): bool,
|
||||||
vol.Inclusive(ATTR_INDOOR_INTEGRATION, "settings"): bool,
|
vol.Required(ATTR_INDOOR_INTEGRATION): bool,
|
||||||
vol.Inclusive(ATTR_OUTDOOR_INTEGRATION, "settings"): bool,
|
vol.Required(ATTR_OUTDOOR_INTEGRATION): bool,
|
||||||
vol.Inclusive(ATTR_SENSITIVITY, "settings"): vol.In(
|
vol.Required(ATTR_SENSITIVITY): vol.In(["Normal", "Sensitive"]),
|
||||||
["Normal", "Sensitive"]
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"async_enable_pure_boost",
|
"async_enable_pure_boost",
|
||||||
)
|
)
|
||||||
platform.async_register_entity_service(
|
|
||||||
SERVICE_DISABLE_PURE_BOOST,
|
|
||||||
{},
|
|
||||||
"async_disable_pure_boost",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
||||||
@ -353,9 +346,3 @@ class SensiboClimate(SensiboDeviceBaseEntity, ClimateEntity):
|
|||||||
|
|
||||||
await self.async_send_command("set_pure_boost", params)
|
await self.async_send_command("set_pure_boost", params)
|
||||||
await self.coordinator.async_refresh()
|
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:
|
ac_integration:
|
||||||
name: AC Integration
|
name: AC Integration
|
||||||
description: Integrate with Air Conditioner.
|
description: Integrate with Air Conditioner.
|
||||||
required: false
|
required: true
|
||||||
example: true
|
example: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
geo_integration:
|
geo_integration:
|
||||||
name: Geo Integration
|
name: Geo Integration
|
||||||
description: Integrate with Presence.
|
description: Integrate with Presence.
|
||||||
required: false
|
required: true
|
||||||
example: true
|
example: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
indoor_integration:
|
indoor_integration:
|
||||||
name: Indoor Air Quality
|
name: Indoor Air Quality
|
||||||
description: Integrate with checking indoor air quality.
|
description: Integrate with checking indoor air quality.
|
||||||
required: false
|
required: true
|
||||||
example: true
|
example: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
outdoor_integration:
|
outdoor_integration:
|
||||||
name: Outdoor Air Quality
|
name: Outdoor Air Quality
|
||||||
description: Integrate with checking outdoor air quality.
|
description: Integrate with checking outdoor air quality.
|
||||||
required: false
|
required: true
|
||||||
example: true
|
example: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
sensitivity:
|
sensitivity:
|
||||||
name: Sensitivity
|
name: Sensitivity
|
||||||
description: Set the sensitivity for Pure Boost.
|
description: Set the sensitivity for Pure Boost.
|
||||||
required: false
|
required: true
|
||||||
example: "Normal"
|
example: "Normal"
|
||||||
selector:
|
selector:
|
||||||
select:
|
select:
|
||||||
options:
|
options:
|
||||||
- "Normal"
|
- "Normal"
|
||||||
- "Sensitive"
|
- "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."""
|
"""Mixin for required Sensibo base description keys."""
|
||||||
|
|
||||||
value_fn: Callable[[SensiboDevice], bool | None]
|
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_on: str
|
||||||
command_off: str
|
command_off: str
|
||||||
remote_key: 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:
|
def build_params(command: str, device_data: SensiboDevice) -> dict[str, Any] | None:
|
||||||
"""Build params for turning on switch."""
|
"""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},
|
"acState": {**device_data.ac_states, "on": new_state},
|
||||||
}
|
}
|
||||||
return params
|
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
|
return None
|
||||||
|
|
||||||
|
|
||||||
@ -84,6 +107,12 @@ async def async_setup_entry(
|
|||||||
for device_id, device_data in coordinator.data.parsed.items()
|
for device_id, device_data in coordinator.data.parsed.items()
|
||||||
if device_data.model != "pure"
|
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)
|
async_add_entities(entities)
|
||||||
|
|
||||||
@ -130,7 +159,10 @@ class SensiboDeviceSwitch(SensiboDeviceBaseEntity, SwitchEntity):
|
|||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""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":
|
if result["status"] == "success":
|
||||||
setattr(self.device_data, self.entity_description.remote_key, False)
|
setattr(self.device_data, self.entity_description.remote_key, False)
|
||||||
@ -141,6 +173,8 @@ class SensiboDeviceSwitch(SensiboDeviceBaseEntity, SwitchEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> Mapping[str, Any]:
|
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||||
"""Return additional attributes."""
|
"""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")
|
state2 = hass.states.get("binary_sensor.hallway_motion_sensor_main_sensor")
|
||||||
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion")
|
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion")
|
||||||
state4 = hass.states.get("binary_sensor.hallway_room_occupied")
|
state4 = hass.states.get("binary_sensor.hallway_room_occupied")
|
||||||
state5 = hass.states.get("binary_sensor.kitchen_pure_boost_enabled")
|
state5 = hass.states.get(
|
||||||
state6 = hass.states.get(
|
|
||||||
"binary_sensor.kitchen_pure_boost_linked_with_indoor_air_quality"
|
"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"
|
"binary_sensor.kitchen_pure_boost_linked_with_outdoor_air_quality"
|
||||||
)
|
)
|
||||||
assert state1.state == "on"
|
assert state1.state == "on"
|
||||||
assert state2.state == "on"
|
assert state2.state == "on"
|
||||||
assert state3.state == "on"
|
assert state3.state == "on"
|
||||||
assert state4.state == "on"
|
assert state4.state == "on"
|
||||||
assert state5.state == "off"
|
assert state5.state == "on"
|
||||||
assert state6.state == "on"
|
assert state6.state == "off"
|
||||||
assert state7.state == "off"
|
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
get_data.parsed["ABC999111"].motion_sensors["AABBCC"], "alive", False
|
get_data.parsed["ABC999111"].motion_sensors["AABBCC"], "alive", False
|
||||||
|
@ -28,7 +28,6 @@ from homeassistant.components.sensibo.climate import (
|
|||||||
ATTR_OUTDOOR_INTEGRATION,
|
ATTR_OUTDOOR_INTEGRATION,
|
||||||
ATTR_SENSITIVITY,
|
ATTR_SENSITIVITY,
|
||||||
SERVICE_ASSUME_STATE,
|
SERVICE_ASSUME_STATE,
|
||||||
SERVICE_DISABLE_PURE_BOOST,
|
|
||||||
SERVICE_ENABLE_PURE_BOOST,
|
SERVICE_ENABLE_PURE_BOOST,
|
||||||
SERVICE_ENABLE_TIMER,
|
SERVICE_ENABLE_TIMER,
|
||||||
_find_valid_target_temp,
|
_find_valid_target_temp,
|
||||||
@ -809,7 +808,7 @@ async def test_climate_pure_boost(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state_climate = hass.states.get("climate.kitchen")
|
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"
|
assert state2.state == "off"
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
@ -878,7 +877,7 @@ async def test_climate_pure_boost(
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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(
|
state2 = hass.states.get(
|
||||||
"binary_sensor.kitchen_pure_boost_linked_with_indoor_air_quality"
|
"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 state2.state == "on"
|
||||||
assert state3.state == "on"
|
assert state3.state == "on"
|
||||||
assert state4.state == "s"
|
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
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
async def test_switch(
|
async def test_switch_timer(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
load_int: ConfigEntry,
|
load_int: ConfigEntry,
|
||||||
monkeypatch: MonkeyPatch,
|
monkeypatch: MonkeyPatch,
|
||||||
@ -105,6 +105,81 @@ async def test_switch(
|
|||||||
assert state1.state == STATE_OFF
|
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(
|
async def test_switch_command_failure(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
load_int: ConfigEntry,
|
load_int: ConfigEntry,
|
||||||
@ -162,4 +237,14 @@ async def test_build_params(
|
|||||||
"minutesFromNow": 60,
|
"minutesFromNow": 60,
|
||||||
"acState": {**get_data.parsed["ABC999111"].ac_states, "on": False},
|
"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
|
assert build_params("incorrect_command", get_data.parsed["ABC999111"]) is None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user