diff --git a/homeassistant/components/time_date/sensor.py b/homeassistant/components/time_date/sensor.py index a1d5024e9b1..550e849af9d 100644 --- a/homeassistant/components/time_date/sensor.py +++ b/homeassistant/components/time_date/sensor.py @@ -86,8 +86,6 @@ class TimeDateSensor(SensorEntity): self.hass = hass self.unsub: CALLBACK_TYPE | None = None - self._update_internal_state(dt_util.utcnow()) - @property def name(self) -> str: """Return the name of the sensor.""" @@ -109,9 +107,7 @@ class TimeDateSensor(SensorEntity): async def async_added_to_hass(self) -> None: """Set up first update.""" - self.unsub = async_track_point_in_utc_time( - self.hass, self.point_in_time_listener, self.get_next_interval() - ) + self._update_state_and_setup_listener() async def async_will_remove_from_hass(self) -> None: """Cancel next update.""" @@ -119,25 +115,23 @@ class TimeDateSensor(SensorEntity): self.unsub() self.unsub = None - def get_next_interval(self) -> datetime: + def get_next_interval(self, time_date: datetime) -> datetime: """Compute next time an update should occur.""" - now = dt_util.utcnow() - if self.type == "date": - tomorrow = dt_util.as_local(now) + timedelta(days=1) + tomorrow = dt_util.as_local(time_date) + timedelta(days=1) return dt_util.start_of_local_day(tomorrow) if self.type == "beat": # Add 1 hour because @0 beats is at 23:00:00 UTC. - timestamp = dt_util.as_timestamp(now + timedelta(hours=1)) + timestamp = dt_util.as_timestamp(time_date + timedelta(hours=1)) interval = 86.4 else: - timestamp = dt_util.as_timestamp(now) + timestamp = dt_util.as_timestamp(time_date) interval = 60 delta = interval - (timestamp % interval) - next_interval = now + timedelta(seconds=delta) - _LOGGER.debug("%s + %s -> %s (%s)", now, delta, next_interval, self.type) + next_interval = time_date + timedelta(seconds=delta) + _LOGGER.debug("%s + %s -> %s (%s)", time_date, delta, next_interval, self.type) return next_interval @@ -179,11 +173,16 @@ class TimeDateSensor(SensorEntity): f"{date} {time}", raise_on_error=True ).isoformat() + def _update_state_and_setup_listener(self) -> None: + """Update state and setup listener for next interval.""" + now = dt_util.utcnow() + self._update_internal_state(now) + self.unsub = async_track_point_in_utc_time( + self.hass, self.point_in_time_listener, self.get_next_interval(now) + ) + @callback def point_in_time_listener(self, time_date: datetime) -> None: """Get the latest data and update state.""" - self._update_internal_state(time_date) + self._update_state_and_setup_listener() self.async_write_ha_state() - self.unsub = async_track_point_in_utc_time( - self.hass, self.point_in_time_listener, self.get_next_interval() - ) diff --git a/tests/components/time_date/test_sensor.py b/tests/components/time_date/test_sensor.py index 4989a65984b..e156c1d5a3e 100644 --- a/tests/components/time_date/test_sensor.py +++ b/tests/components/time_date/test_sensor.py @@ -94,34 +94,32 @@ async def test_states(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> No state = hass.states.get("sensor.date_time_iso") assert state.state == "2017-05-18T00:54:00" + # Time travel now = dt_util.utc_from_timestamp(1602952963.2) freezer.move_to(now) async_fire_time_changed(hass, now) await hass.async_block_till_done() - # The time should be 2020-10-17 18:42 / @738, however the time_date sensor - # does not check the current time when calculating the state, it instead checks - # the time when it expected an update state = hass.states.get("sensor.time") - assert state.state == "00:55" + assert state.state == "16:42" state = hass.states.get("sensor.date") - assert state.state == "2017-05-19" + assert state.state == "2020-10-17" state = hass.states.get("sensor.time_utc") - assert state.state == "00:55" + assert state.state == "16:42" state = hass.states.get("sensor.date_time") - assert state.state == "2017-05-18, 00:55" + assert state.state == "2020-10-17, 16:42" state = hass.states.get("sensor.date_time_utc") - assert state.state == "2017-05-18, 00:55" + assert state.state == "2020-10-17, 16:42" state = hass.states.get("sensor.internet_time") - assert state.state == "@080" + assert state.state == "@738" state = hass.states.get("sensor.date_time_iso") - assert state.state == "2017-05-18T00:55:00" + assert state.state == "2020-10-17T16:42:00" async def test_states_non_default_timezone( @@ -156,34 +154,32 @@ async def test_states_non_default_timezone( state = hass.states.get("sensor.date_time_iso") assert state.state == "2017-05-17T20:54:00" + # Time travel now = dt_util.utc_from_timestamp(1602952963.2) freezer.move_to(now) async_fire_time_changed(hass, now) await hass.async_block_till_done() - # The time should be 2020-10-17 12:42 / @738, however the time_date sensor - # does not check the current time when calculating the state, it instead checks - # the time when it expected an update state = hass.states.get("sensor.time") - assert state.state == "20:55" + assert state.state == "12:42" state = hass.states.get("sensor.date") - assert state.state == "2017-05-18" + assert state.state == "2020-10-17" state = hass.states.get("sensor.time_utc") - assert state.state == "00:55" + assert state.state == "16:42" state = hass.states.get("sensor.date_time") - assert state.state == "2017-05-17, 20:55" + assert state.state == "2020-10-17, 12:42" state = hass.states.get("sensor.date_time_utc") - assert state.state == "2017-05-18, 00:55" + assert state.state == "2020-10-17, 16:42" state = hass.states.get("sensor.internet_time") - assert state.state == "@080" + assert state.state == "@738" state = hass.states.get("sensor.date_time_iso") - assert state.state == "2017-05-17T20:55:00" + assert state.state == "2020-10-17T12:42:00" @patch(