|
36 | 36 | from homeassistant.helpers.reload import async_setup_reload_service
|
37 | 37 | from homeassistant.helpers.restore_state import RestoreEntity
|
38 | 38 | from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
|
39 |
| - |
40 |
| -from .const import CONF_ENTITY_ID, DOMAIN, LOGGER, PLATFORMS |
| 39 | +from homeassistant.util import dt as dt_util |
| 40 | + |
| 41 | +from .const import ( |
| 42 | + ATTR_LAST_MODIFIED, |
| 43 | + CONF_ENTITY_ID, |
| 44 | + DOMAIN, |
| 45 | + LOGGER, |
| 46 | + PLATFORMS, |
| 47 | +) |
41 | 48 |
|
42 | 49 | ATTR_MIN_VALUE = "min_value"
|
43 | 50 | ATTR_MAX_VALUE = "max_value"
|
@@ -189,6 +196,8 @@ class PeriodicMinMaxSensor(SensorEntity, RestoreEntity):
|
189 | 196 | _attr_icon = ICON
|
190 | 197 | _attr_should_poll = False
|
191 | 198 | _attr_state_class = SensorStateClass.MEASUREMENT
|
| 199 | + _state_had_real_change = False |
| 200 | + _attr_last_modified: datetime = dt_util.utcnow().isoformat() |
192 | 201 |
|
193 | 202 | def __init__(
|
194 | 203 | self,
|
@@ -223,6 +232,14 @@ def __init__(
|
223 | 232 | async def async_added_to_hass(self) -> None:
|
224 | 233 | """Handle added to Hass."""
|
225 | 234 |
|
| 235 | + await super().async_added_to_hass() |
| 236 | + |
| 237 | + last_state = await self.async_get_last_state() |
| 238 | + if last_state: |
| 239 | + last_attrs = last_state.attributes |
| 240 | + if last_attrs and ATTR_LAST_MODIFIED in last_attrs: |
| 241 | + self._attr_last_modified = last_attrs[ATTR_LAST_MODIFIED] |
| 242 | + |
226 | 243 | self.async_on_remove(
|
227 | 244 | async_track_state_change_event(
|
228 | 245 | self.hass,
|
@@ -291,6 +308,15 @@ def native_unit_of_measurement(self) -> str | None:
|
291 | 308 | return "ERR"
|
292 | 309 | return self._unit_of_measurement
|
293 | 310 |
|
| 311 | + @property |
| 312 | + def extra_state_attributes(self) -> dict[str, Any]: |
| 313 | + """Return the device specific state attributes.""" |
| 314 | + attributes: dict[str, Any] = {} |
| 315 | + |
| 316 | + attributes[ATTR_LAST_MODIFIED] = self._attr_last_modified |
| 317 | + |
| 318 | + return attributes |
| 319 | + |
294 | 320 | @callback
|
295 | 321 | def _async_min_max_sensor_state_listener(
|
296 | 322 | self, event: Event[EventStateChangedData], update_state: bool = True
|
@@ -337,23 +363,32 @@ def _async_min_max_sensor_state_listener(
|
337 | 363 | return
|
338 | 364 |
|
339 | 365 | self._calc_values()
|
| 366 | + |
| 367 | + if self._state_had_real_change: |
| 368 | + self._attr_last_modified = dt_util.utcnow().isoformat(sep=" ") |
| 369 | + |
340 | 370 | self.async_write_ha_state()
|
341 | 371 |
|
342 | 372 | @callback
|
343 | 373 | def _calc_values(self) -> None:
|
344 | 374 | """Calculate the values."""
|
| 375 | + self._state_had_real_change = False |
345 | 376 |
|
346 | 377 | """Calculate min value, honoring unknown states."""
|
347 |
| - if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and ( |
348 |
| - self.min_value is None or self.min_value > self._state |
349 |
| - ): |
350 |
| - self.min_value = self._state |
| 378 | + if self._sensor_attr == ATTR_MIN_VALUE: |
| 379 | + if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and ( |
| 380 | + self.min_value is None or self.min_value > self._state |
| 381 | + ): |
| 382 | + self.min_value = self._state |
| 383 | + self._state_had_real_change = True |
351 | 384 |
|
352 | 385 | """Calculate max value, honoring unknown states."""
|
353 |
| - if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and ( |
354 |
| - self.max_value is None or self.max_value < self._state |
355 |
| - ): |
356 |
| - self.max_value = self._state |
| 386 | + if self._sensor_attr == ATTR_MAX_VALUE: |
| 387 | + if self._state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] and ( |
| 388 | + self.max_value is None or self.max_value < self._state |
| 389 | + ): |
| 390 | + self.max_value = self._state |
| 391 | + self._state_had_real_change = True |
357 | 392 |
|
358 | 393 | async def handle_reset(self) -> None:
|
359 | 394 | """Set the min & max to current state."""
|
|
0 commit comments