diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index e4aa6be1ff1..35258555537 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -55,8 +55,7 @@ STORAGE_KEY = DOMAIN STORAGE_VERSION = 1 CREATE_FIELDS = { - vol.Required(CONF_NAME): vol.All(str, vol.Length(min=1)), - vol.Optional(CONF_NAME): cv.string, + vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_DURATION, default=DEFAULT_DURATION): cv.time_period, } @@ -199,6 +198,9 @@ class Timer(RestoreEntity): self._end: datetime | None = None self._listener: Callable[[], None] | None = None + self._attr_should_poll = False + self._attr_force_update = True + @classmethod def from_yaml(cls, config: dict) -> Timer: """Return entity instance initialized from yaml storage.""" @@ -207,16 +209,6 @@ class Timer(RestoreEntity): timer.editable = False return timer - @property - def should_poll(self): - """If entity should be polled.""" - return False - - @property - def force_update(self) -> bool: - """Return True to fix restart issues.""" - return True - @property def name(self): """Return name of the timer.""" @@ -266,9 +258,6 @@ class Timer(RestoreEntity): if self._listener: self._listener() self._listener = None - newduration = None - if duration: - newduration = duration event = EVENT_TIMER_STARTED if self._state in (STATUS_ACTIVE, STATUS_PAUSED): @@ -277,17 +266,13 @@ class Timer(RestoreEntity): self._state = STATUS_ACTIVE start = dt_util.utcnow().replace(microsecond=0) - if self._remaining and newduration is None: - self._end = start + self._remaining - - elif newduration: - self._duration = newduration - self._remaining = newduration - self._end = start + self._duration - - else: + # Set remaining to new value if needed + if duration: + self._remaining = self._duration = duration + elif not self._remaining: self._remaining = self._duration - self._end = start + self._duration + + self._end = start + self._remaining self.hass.bus.async_fire(event, {"entity_id": self.entity_id}) diff --git a/tests/components/timer/test_init.py b/tests/components/timer/test_init.py index 92958a7bce6..5c276bc0cfc 100644 --- a/tests/components/timer/test_init.py +++ b/tests/components/timer/test_init.py @@ -8,6 +8,7 @@ import pytest from homeassistant.components.timer import ( ATTR_DURATION, + ATTR_REMAINING, CONF_DURATION, CONF_ICON, CONF_NAME, @@ -190,6 +191,46 @@ async def test_methods_and_events(hass): assert len(results) == expectedEvents +async def test_start_service(hass): + """Test the start/stop service.""" + await async_setup_component(hass, DOMAIN, {DOMAIN: {"test1": {CONF_DURATION: 10}}}) + + state = hass.states.get("timer.test1") + assert state + assert state.state == STATUS_IDLE + assert state.attributes[ATTR_DURATION] == "0:00:10" + + await hass.services.async_call( + DOMAIN, SERVICE_START, {CONF_ENTITY_ID: "timer.test1"} + ) + await hass.async_block_till_done() + state = hass.states.get("timer.test1") + assert state + assert state.state == STATUS_ACTIVE + assert state.attributes[ATTR_DURATION] == "0:00:10" + assert state.attributes[ATTR_REMAINING] == "0:00:10" + + await hass.services.async_call( + DOMAIN, SERVICE_CANCEL, {CONF_ENTITY_ID: "timer.test1"} + ) + await hass.async_block_till_done() + state = hass.states.get("timer.test1") + assert state + assert state.state == STATUS_IDLE + assert state.attributes[ATTR_DURATION] == "0:00:10" + assert ATTR_REMAINING not in state.attributes + + await hass.services.async_call( + DOMAIN, SERVICE_START, {CONF_ENTITY_ID: "timer.test1", CONF_DURATION: 15} + ) + await hass.async_block_till_done() + state = hass.states.get("timer.test1") + assert state + assert state.state == STATUS_ACTIVE + assert state.attributes[ATTR_DURATION] == "0:00:15" + assert state.attributes[ATTR_REMAINING] == "0:00:15" + + async def test_wait_till_timer_expires(hass): """Test for a timer to end.""" hass.state = CoreState.starting