mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 08:51:46 -04:00
Stop exposing sleep timers and adaptive learning on Modern Forms Gen4 fans (#180525)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
df4c7f0169
commit
f5aaa35355
@@ -20,16 +20,19 @@ async def async_setup_entry(
|
||||
"""Set up Modern Forms binary sensors."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
binary_sensors: list[ModernFormsBinarySensor] = [
|
||||
ModernFormsFanSleepTimerActive(entry.entry_id, coordinator),
|
||||
]
|
||||
binary_sensors: list[ModernFormsBinarySensor] = []
|
||||
|
||||
# Only setup light sleep timer sensor if light unit installed
|
||||
if coordinator.data.info.light_type:
|
||||
if coordinator.data.has_sleep_timer():
|
||||
binary_sensors.append(
|
||||
ModernFormsLightSleepTimerActive(entry.entry_id, coordinator)
|
||||
ModernFormsFanSleepTimerActive(entry.entry_id, coordinator)
|
||||
)
|
||||
|
||||
# Only setup light sleep timer sensor if light unit installed
|
||||
if coordinator.data.info.light_type:
|
||||
binary_sensors.append(
|
||||
ModernFormsLightSleepTimerActive(entry.entry_id, coordinator)
|
||||
)
|
||||
|
||||
async_add_entities(binary_sensors)
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components.fan import FanEntity, FanEntityFeature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util.percentage import (
|
||||
@@ -19,6 +20,7 @@ from . import modernforms_exception_handler
|
||||
from .const import (
|
||||
ATTR_SLEEP_TIME,
|
||||
CLEAR_TIMER,
|
||||
DOMAIN,
|
||||
OPT_ON,
|
||||
OPT_SPEED,
|
||||
OPT_WIND,
|
||||
@@ -186,6 +188,11 @@ class ModernFormsFanEntity(FanEntity, ModernFormsDeviceEntity):
|
||||
sleep_time: int,
|
||||
) -> None:
|
||||
"""Set a Modern Forms light sleep timer."""
|
||||
if not self.coordinator.data.has_sleep_timer():
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="sleep_timer_not_supported",
|
||||
)
|
||||
await self.coordinator.modern_forms.fan(sleep=sleep_time * 60)
|
||||
|
||||
@modernforms_exception_handler
|
||||
@@ -193,4 +200,9 @@ class ModernFormsFanEntity(FanEntity, ModernFormsDeviceEntity):
|
||||
self,
|
||||
) -> None:
|
||||
"""Clear a Modern Forms fan sleep timer."""
|
||||
if not self.coordinator.data.has_sleep_timer():
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="sleep_timer_not_supported",
|
||||
)
|
||||
await self.coordinator.modern_forms.fan(sleep=CLEAR_TIMER)
|
||||
|
||||
@@ -8,6 +8,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util.percentage import (
|
||||
@@ -19,6 +20,7 @@ from . import modernforms_exception_handler
|
||||
from .const import (
|
||||
ATTR_SLEEP_TIME,
|
||||
CLEAR_TIMER,
|
||||
DOMAIN,
|
||||
OPT_BRIGHTNESS,
|
||||
OPT_ON,
|
||||
SERVICE_CLEAR_LIGHT_SLEEP_TIMER,
|
||||
@@ -159,6 +161,11 @@ class ModernFormsLightEntity(ModernFormsDeviceEntity, LightEntity):
|
||||
sleep_time: int,
|
||||
) -> None:
|
||||
"""Set a Modern Forms light sleep timer."""
|
||||
if not self.coordinator.data.has_sleep_timer():
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="sleep_timer_not_supported",
|
||||
)
|
||||
await self._async_control_light(sleep=sleep_time * 60)
|
||||
|
||||
@modernforms_exception_handler
|
||||
@@ -166,6 +173,11 @@ class ModernFormsLightEntity(ModernFormsDeviceEntity, LightEntity):
|
||||
self,
|
||||
) -> None:
|
||||
"""Clear a Modern Forms light sleep timer."""
|
||||
if not self.coordinator.data.has_sleep_timer():
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="sleep_timer_not_supported",
|
||||
)
|
||||
await self._async_control_light(sleep=CLEAR_TIMER)
|
||||
|
||||
async def _async_control_light(self, **kwargs: Any) -> None:
|
||||
|
||||
@@ -22,16 +22,19 @@ async def async_setup_entry(
|
||||
"""Set up Modern Forms sensor based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
sensors: list[ModernFormsSensor] = [
|
||||
ModernFormsFanTimerRemainingTimeSensor(entry.entry_id, coordinator),
|
||||
]
|
||||
sensors: list[ModernFormsSensor] = []
|
||||
|
||||
# Only setup light sleep timer sensor if light unit installed
|
||||
if coordinator.data.info.light_type:
|
||||
if coordinator.data.has_sleep_timer():
|
||||
sensors.append(
|
||||
ModernFormsLightTimerRemainingTimeSensor(entry.entry_id, coordinator)
|
||||
ModernFormsFanTimerRemainingTimeSensor(entry.entry_id, coordinator)
|
||||
)
|
||||
|
||||
# Only setup light sleep timer sensor if light unit installed
|
||||
if coordinator.data.info.light_type:
|
||||
sensors.append(
|
||||
ModernFormsLightTimerRemainingTimeSensor(entry.entry_id, coordinator)
|
||||
)
|
||||
|
||||
async_add_entities(sensors)
|
||||
|
||||
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
},
|
||||
"invalid_response": {
|
||||
"message": "Invalid response from the Modern Forms device"
|
||||
},
|
||||
"sleep_timer_not_supported": {
|
||||
"message": "This fan does not support sleep timers"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
|
||||
@@ -19,10 +19,13 @@ async def async_setup_entry(
|
||||
"""Set up Modern Forms switch based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
switches = [
|
||||
switches: list[ModernFormsSwitch] = [
|
||||
ModernFormsAwaySwitch(entry.entry_id, coordinator),
|
||||
ModernFormsAdaptiveLearningSwitch(entry.entry_id, coordinator),
|
||||
]
|
||||
|
||||
if coordinator.data.has_adaptive_learning():
|
||||
switches.append(ModernFormsAdaptiveLearningSwitch(entry.entry_id, coordinator))
|
||||
|
||||
async_add_entities(switches)
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from homeassistant.components.modern_forms.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import init_integration
|
||||
from . import init_integration, init_integration_gen4
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@@ -43,3 +43,26 @@ async def test_binary_sensors(
|
||||
state = hass.states.get("binary_sensor.modernformsfan_fan_sleep_timer_active")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
async def test_no_sleep_timer_binary_sensors_on_gen4(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test the sleep-timer binary sensors aren't created for Gen4 fans."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
# Both entities are disabled by default, so checking hass.states here
|
||||
# wouldn't distinguish "not created" from "created but disabled" --
|
||||
# check the entity registry instead.
|
||||
assert (
|
||||
entity_registry.async_get("binary_sensor.modernformsfan_fan_sleep_timer_active")
|
||||
is None
|
||||
)
|
||||
assert (
|
||||
entity_registry.async_get(
|
||||
"binary_sensor.modernformsfan_light_sleep_timer_active"
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
@@ -43,6 +43,7 @@ from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import (
|
||||
init_integration,
|
||||
init_integration_gen4,
|
||||
modern_forms_breeze_active_call_mock,
|
||||
modern_forms_breeze_call_mock,
|
||||
)
|
||||
@@ -395,3 +396,41 @@ async def test_turn_off_does_not_touch_wind(
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
fan_mock.assert_called_once_with(on=False)
|
||||
|
||||
|
||||
async def test_fan_sleep_timer_not_supported_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test setting a sleep timer on a Gen4 fan raises an error."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SET_FAN_SLEEP_TIMER,
|
||||
{ATTR_ENTITY_ID: "fan.modernformsfan_fan", ATTR_SLEEP_TIME: 1},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_domain == DOMAIN
|
||||
assert exc_info.value.translation_key == "sleep_timer_not_supported"
|
||||
|
||||
|
||||
async def test_clear_fan_sleep_timer_not_supported_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test clearing a sleep timer on a Gen4 fan raises an error."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_CLEAR_FAN_SLEEP_TIMER,
|
||||
{ATTR_ENTITY_ID: "fan.modernformsfan_fan"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_domain == DOMAIN
|
||||
assert exc_info.value.translation_key == "sleep_timer_not_supported"
|
||||
|
||||
@@ -326,28 +326,39 @@ async def test_light_change_state_gen4(
|
||||
light_mock.assert_not_called()
|
||||
|
||||
|
||||
async def test_sleep_timer_services_gen4(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
async def test_light_sleep_timer_not_supported_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test Gen4 sleep timer services pass sleep through light_fixture()."""
|
||||
"""Test setting a sleep timer on a Gen4 light fixture raises an error."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
with patch("aiomodernforms.ModernFormsDevice.light_fixture") as light_fixture_mock:
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SET_LIGHT_SLEEP_TIMER,
|
||||
{ATTR_ENTITY_ID: "light.modernformsfan_uplight", ATTR_SLEEP_TIME: 1},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
light_fixture_mock.assert_called_once_with(2, sleep=60)
|
||||
|
||||
with patch("aiomodernforms.ModernFormsDevice.light_fixture") as light_fixture_mock:
|
||||
assert exc_info.value.translation_domain == DOMAIN
|
||||
assert exc_info.value.translation_key == "sleep_timer_not_supported"
|
||||
|
||||
|
||||
async def test_clear_light_sleep_timer_not_supported_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test clearing a sleep timer on a Gen4 light fixture raises an error."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_CLEAR_LIGHT_SLEEP_TIMER,
|
||||
{ATTR_ENTITY_ID: "light.modernformsfan_uplight"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
light_fixture_mock.assert_called_once_with(2, sleep=0)
|
||||
|
||||
assert exc_info.value.translation_domain == DOMAIN
|
||||
assert exc_info.value.translation_key == "sleep_timer_not_supported"
|
||||
|
||||
@@ -6,7 +6,7 @@ from homeassistant.components.sensor import SensorDeviceClass
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import init_integration, modern_forms_timers_set_mock
|
||||
from . import init_integration, init_integration_gen4, modern_forms_timers_set_mock
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@@ -51,3 +51,14 @@ async def test_active_sensors(
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP
|
||||
datetime.fromisoformat(state.state)
|
||||
|
||||
|
||||
async def test_no_sleep_timer_sensors_on_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test the sleep-timer sensors aren't created for Gen4 fans."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
assert hass.states.get("sensor.modernformsfan_fan_sleep_time") is None
|
||||
assert hass.states.get("sensor.modernformsfan_light_sleep_time") is None
|
||||
|
||||
@@ -18,7 +18,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import init_integration
|
||||
from . import init_integration, init_integration_gen4
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@@ -156,3 +156,14 @@ async def test_switch_connection_error(
|
||||
|
||||
state = hass.states.get("switch.modernformsfan_away_mode")
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_no_adaptive_learning_switch_on_gen4(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test the adaptive learning switch isn't created for Gen4 fans."""
|
||||
await init_integration_gen4(hass, aioclient_mock)
|
||||
|
||||
assert hass.states.get("switch.modernformsfan_adaptive_learning") is None
|
||||
assert hass.states.get("switch.modernformsfan_away_mode") is not None
|
||||
|
||||
Reference in New Issue
Block a user