mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Change duration for timer.start service to only change running duration (#99628)
* Get back duration for timer * running duration * Mods * Finish * Fix start call * remove restore idle * running duration not None * fix tests
This commit is contained in:
parent
6b19602322
commit
c414e52b55
@ -205,7 +205,8 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
"""Initialize a timer."""
|
||||
self._config: dict = config
|
||||
self._state: str = STATUS_IDLE
|
||||
self._duration = cv.time_period_str(config[CONF_DURATION])
|
||||
self._configured_duration = cv.time_period_str(config[CONF_DURATION])
|
||||
self._running_duration: timedelta = self._configured_duration
|
||||
self._remaining: timedelta | None = None
|
||||
self._end: datetime | None = None
|
||||
self._listener: Callable[[], None] | None = None
|
||||
@ -248,7 +249,7 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
attrs = {
|
||||
ATTR_DURATION: _format_timedelta(self._duration),
|
||||
ATTR_DURATION: _format_timedelta(self._running_duration),
|
||||
ATTR_EDITABLE: self.editable,
|
||||
}
|
||||
if self._end is not None:
|
||||
@ -275,12 +276,12 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
|
||||
# Begin restoring state
|
||||
self._state = state.state
|
||||
self._duration = cv.time_period(state.attributes[ATTR_DURATION])
|
||||
|
||||
# Nothing more to do if the timer is idle
|
||||
if self._state == STATUS_IDLE:
|
||||
return
|
||||
|
||||
self._running_duration = cv.time_period(state.attributes[ATTR_DURATION])
|
||||
# If the timer was paused, we restore the remaining time
|
||||
if self._state == STATUS_PAUSED:
|
||||
self._remaining = cv.time_period(state.attributes[ATTR_REMAINING])
|
||||
@ -314,11 +315,11 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
self._state = STATUS_ACTIVE
|
||||
start = dt_util.utcnow().replace(microsecond=0)
|
||||
|
||||
# Set remaining to new value if needed
|
||||
# Set remaining and running duration unless resuming or restarting
|
||||
if duration:
|
||||
self._remaining = self._duration = duration
|
||||
self._remaining = self._running_duration = duration
|
||||
elif not self._remaining:
|
||||
self._remaining = self._duration
|
||||
self._remaining = self._running_duration
|
||||
|
||||
self._end = start + self._remaining
|
||||
|
||||
@ -336,9 +337,9 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
raise HomeAssistantError(
|
||||
f"Timer {self.entity_id} is not running, only active timers can be changed"
|
||||
)
|
||||
if self._remaining and (self._remaining + duration) > self._duration:
|
||||
if self._remaining and (self._remaining + duration) > self._running_duration:
|
||||
raise HomeAssistantError(
|
||||
f"Not possible to change timer {self.entity_id} beyond configured duration"
|
||||
f"Not possible to change timer {self.entity_id} beyond duration"
|
||||
)
|
||||
if self._remaining and (self._remaining + duration) < timedelta():
|
||||
raise HomeAssistantError(
|
||||
@ -377,6 +378,7 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
self._state = STATUS_IDLE
|
||||
self._end = None
|
||||
self._remaining = None
|
||||
self._running_duration = self._configured_duration
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_TIMER_CANCELLED, {ATTR_ENTITY_ID: self.entity_id}
|
||||
)
|
||||
@ -395,6 +397,7 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
self._state = STATUS_IDLE
|
||||
self._end = None
|
||||
self._remaining = None
|
||||
self._running_duration = self._configured_duration
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_TIMER_FINISHED,
|
||||
{ATTR_ENTITY_ID: self.entity_id, ATTR_FINISHED_AT: end.isoformat()},
|
||||
@ -412,6 +415,7 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
end = self._end
|
||||
self._end = None
|
||||
self._remaining = None
|
||||
self._running_duration = self._configured_duration
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_TIMER_FINISHED,
|
||||
{ATTR_ENTITY_ID: self.entity_id, ATTR_FINISHED_AT: end.isoformat()},
|
||||
@ -421,6 +425,8 @@ class Timer(collection.CollectionEntity, RestoreEntity):
|
||||
async def async_update_config(self, config: ConfigType) -> None:
|
||||
"""Handle when the config is updated."""
|
||||
self._config = config
|
||||
self._duration = cv.time_period_str(config[CONF_DURATION])
|
||||
self._configured_duration = cv.time_period_str(config[CONF_DURATION])
|
||||
if self._state == STATUS_IDLE:
|
||||
self._running_duration = self._configured_duration
|
||||
self._restore = config.get(CONF_RESTORE, DEFAULT_RESTORE)
|
||||
self.async_write_ha_state()
|
||||
|
@ -319,7 +319,7 @@ async def test_start_service(hass: HomeAssistant) -> None:
|
||||
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Not possible to change timer timer.test1 beyond configured duration",
|
||||
match="Not possible to change timer timer.test1 beyond duration",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
@ -370,7 +370,7 @@ async def test_start_service(hass: HomeAssistant) -> None:
|
||||
state = hass.states.get("timer.test1")
|
||||
assert state
|
||||
assert state.state == STATUS_IDLE
|
||||
assert state.attributes[ATTR_DURATION] == "0:00:15"
|
||||
assert state.attributes[ATTR_DURATION] == "0:00:10"
|
||||
assert ATTR_REMAINING not in state.attributes
|
||||
|
||||
with pytest.raises(
|
||||
@ -387,7 +387,7 @@ async def test_start_service(hass: HomeAssistant) -> None:
|
||||
state = hass.states.get("timer.test1")
|
||||
assert state
|
||||
assert state.state == STATUS_IDLE
|
||||
assert state.attributes[ATTR_DURATION] == "0:00:15"
|
||||
assert state.attributes[ATTR_DURATION] == "0:00:10"
|
||||
assert ATTR_REMAINING not in state.attributes
|
||||
|
||||
|
||||
@ -844,43 +844,6 @@ async def test_setup_no_config(hass: HomeAssistant, hass_admin_user: MockUser) -
|
||||
assert count_start == len(hass.states.async_entity_ids())
|
||||
|
||||
|
||||
async def test_restore_idle(hass: HomeAssistant) -> None:
|
||||
"""Test entity restore logic when timer is idle."""
|
||||
utc_now = utcnow()
|
||||
stored_state = StoredState(
|
||||
State(
|
||||
"timer.test",
|
||||
STATUS_IDLE,
|
||||
{ATTR_DURATION: "0:00:30"},
|
||||
),
|
||||
None,
|
||||
utc_now,
|
||||
)
|
||||
|
||||
data = async_get(hass)
|
||||
await data.store.async_save([stored_state.as_dict()])
|
||||
await data.async_load()
|
||||
|
||||
entity = Timer.from_storage(
|
||||
{
|
||||
CONF_ID: "test",
|
||||
CONF_NAME: "test",
|
||||
CONF_DURATION: "0:01:00",
|
||||
CONF_RESTORE: True,
|
||||
}
|
||||
)
|
||||
entity.hass = hass
|
||||
entity.entity_id = "timer.test"
|
||||
|
||||
await entity.async_added_to_hass()
|
||||
await hass.async_block_till_done()
|
||||
assert entity.state == STATUS_IDLE
|
||||
assert entity.extra_state_attributes[ATTR_DURATION] == "0:00:30"
|
||||
assert ATTR_REMAINING not in entity.extra_state_attributes
|
||||
assert ATTR_FINISHES_AT not in entity.extra_state_attributes
|
||||
assert entity.extra_state_attributes[ATTR_RESTORE]
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2023-06-05 17:47:50")
|
||||
async def test_restore_paused(hass: HomeAssistant) -> None:
|
||||
"""Test entity restore logic when timer is paused."""
|
||||
@ -1007,7 +970,7 @@ async def test_restore_active_finished_outside_grace(hass: HomeAssistant) -> Non
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entity.state == STATUS_IDLE
|
||||
assert entity.extra_state_attributes[ATTR_DURATION] == "0:00:30"
|
||||
assert entity.extra_state_attributes[ATTR_DURATION] == "0:01:00"
|
||||
assert ATTR_REMAINING not in entity.extra_state_attributes
|
||||
assert ATTR_FINISHES_AT not in entity.extra_state_attributes
|
||||
assert entity.extra_state_attributes[ATTR_RESTORE]
|
||||
|
Loading…
x
Reference in New Issue
Block a user