diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 12b75af1b..fb1064aa6 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -21,14 +21,13 @@ BinarySensorEntityDescription, BinarySensorDeviceClass, ) - +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, +) from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.event import ( - EventStateChangedData, - async_track_state_change_event, async_track_entity_registry_updated_event, ) -from homeassistant.helpers.typing import EventType from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.const import ( @@ -42,27 +41,12 @@ from .const import ( DOMAIN, - DOMAIN_CONFIG, DATA, - CONF_ENABLE_REPLACED, - CONF_ROUND_BATTERY, - CONF_BATTERY_INCREASE_THRESHOLD, - EVENT_BATTERY_THRESHOLD, - EVENT_BATTERY_INCREASED, - DEFAULT_BATTERY_INCREASE_THRESHOLD, - ATTR_DEVICE_ID, - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, - ATTR_BATTERY_LOW, ATTR_BATTERY_LOW_THRESHOLD, - ATTR_DEVICE_NAME, - ATTR_BATTERY_LEVEL, - ATTR_PREVIOUS_BATTERY_LEVEL, ) from .common import isfloat -from .device import BatteryNotesDevice + from .coordinator import BatteryNotesCoordinator from .entity import ( @@ -147,21 +131,12 @@ async def async_registry_updated(event: Event) -> None: device_id = async_add_to_device(hass, config_entry) - enable_replaced = True - round_battery = False - - if DOMAIN_CONFIG in hass.data[DOMAIN]: - domain_config: dict = hass.data[DOMAIN][DOMAIN_CONFIG] - enable_replaced = domain_config.get(CONF_ENABLE_REPLACED, True) - round_battery = domain_config.get(CONF_ROUND_BATTERY, False) - description = BatteryNotesBinarySensorEntityDescription( unique_id_suffix="_battery_low", - key="battery_low", + key="_battery_plus_low", translation_key="battery_low", icon="mdi:battery-alert", entity_category=EntityCategory.DIAGNOSTIC, - entity_registry_enabled_default=enable_replaced, device_class=BinarySensorDeviceClass.BATTERY, ) @@ -175,8 +150,6 @@ async def async_registry_updated(event: Event) -> None: coordinator, description, f"{config_entry.entry_id}{description.unique_id_suffix}", - device, - round_battery, ) ] ) @@ -190,17 +163,10 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) -class BatteryNotesBatteryLowSensor(BinarySensorEntity): +class BatteryNotesBatteryLowSensor(BinarySensorEntity, CoordinatorEntity[BatteryNotesCoordinator]): """Represents a low battery threshold binary sensor.""" _attr_should_poll = False - _battery_entity_id = None - device_name = None - _previous_battery_low = None - _previous_battery_level = None - _previous_state_last_changed = None - - entity_description: BatteryNotesBinarySensorEntityDescription def __init__( self, @@ -208,17 +174,17 @@ def __init__( coordinator: BatteryNotesCoordinator, description: BatteryNotesBinarySensorEntityDescription, unique_id: str, - device: BatteryNotesDevice, - round_battery: bool, ) -> None: """Create a low battery binary sensor.""" + device_registry = dr.async_get(hass) self.coordinator = coordinator self.entity_description = description self._attr_unique_id = unique_id self._attr_has_entity_name = True - self.round_battery = round_battery + + super().__init__(coordinator=coordinator) if coordinator.device_id and ( device_entry := device_registry.async_get(coordinator.device_id) @@ -228,141 +194,53 @@ def __init__( identifiers=device_entry.identifiers, ) - self.entity_id = f"binary_sensor.{device.name.lower()}_{description.key}" - self.device_name = device.name - - self._battery_entity_id = ( - device.wrapped_battery.entity_id if device.wrapped_battery else None - ) - - @callback - async def async_state_changed_listener( - self, event: EventType[EventStateChangedData] | None = None - ) -> None: - # pylint: disable=unused-argument - """Handle child updates.""" - - if not self._battery_entity_id: - return - - if ( - wrapped_battery_state := self.hass.states.get(self._battery_entity_id) - ) is None or wrapped_battery_state.state in [STATE_UNAVAILABLE, STATE_UNKNOWN]: - self._attr_is_on = False - self._attr_available = True - return - - battery_low = bool( - float(wrapped_battery_state.state) < self.coordinator.battery_low_threshold - ) - - self.coordinator.set_battery_low(battery_low) - - self._attr_is_on = self.coordinator.battery_low - - self._attr_available = True - - self.async_write_ha_state() - - _LOGGER.debug( - "%s battery_low changed: %s", self._battery_entity_id, battery_low - ) - - await self.coordinator.async_request_refresh() - - if isfloat(wrapped_battery_state.state): - if self.round_battery: - battery_level = round(float(wrapped_battery_state.state), 0) - else: - battery_level = round(float(wrapped_battery_state.state), 1) - else: - battery_level = wrapped_battery_state.state - - if self._previous_state_last_changed: - # Battery low event - if battery_low != self._previous_battery_low: - self.hass.bus.fire( - EVENT_BATTERY_THRESHOLD, - { - ATTR_DEVICE_ID: self.coordinator.device_id, - ATTR_DEVICE_NAME: self.device_name, - ATTR_BATTERY_LOW: battery_low, - ATTR_BATTERY_TYPE_AND_QUANTITY: self.coordinator.battery_type_and_quantity, - ATTR_BATTERY_TYPE: self.coordinator.battery_type, - ATTR_BATTERY_QUANTITY: self.coordinator.battery_quantity, - ATTR_BATTERY_LEVEL: battery_level, - ATTR_PREVIOUS_BATTERY_LEVEL: self._previous_battery_level, - }, - ) - - _LOGGER.debug("battery_threshold event fired Low: %s", battery_low) - - # Battery increased event - increase_threshold = DEFAULT_BATTERY_INCREASE_THRESHOLD - if DOMAIN_CONFIG in self.hass.data[DOMAIN]: - domain_config: dict = self.hass.data[DOMAIN][DOMAIN_CONFIG] - increase_threshold = domain_config.get( - CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD - ) - - if wrapped_battery_state.state not in [STATE_UNAVAILABLE, STATE_UNKNOWN]: - if ( - wrapped_battery_state.state - and self._previous_battery_level - and float(wrapped_battery_state.state) - >= (self._previous_battery_level + increase_threshold) - ): - self.hass.bus.fire( - EVENT_BATTERY_INCREASED, - { - ATTR_DEVICE_ID: self.coordinator.device_id, - ATTR_DEVICE_NAME: self.device_name, - ATTR_BATTERY_LOW: battery_low, - ATTR_BATTERY_TYPE_AND_QUANTITY: self.coordinator.battery_type_and_quantity, - ATTR_BATTERY_TYPE: self.coordinator.battery_type, - ATTR_BATTERY_QUANTITY: self.coordinator.battery_quantity, - ATTR_BATTERY_LEVEL: battery_level, - ATTR_PREVIOUS_BATTERY_LEVEL: self._previous_battery_level, - }, - ) - - _LOGGER.debug("battery_increased event fired") - - self._previous_battery_level = battery_level - self._previous_state_last_changed = wrapped_battery_state.last_changed - self._previous_battery_low = battery_low + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" async def async_added_to_hass(self) -> None: """Handle added to Hass.""" - @callback - async def _async_state_changed_listener( - event: EventType[EventStateChangedData] | None = None, - ) -> None: - """Handle child updates.""" - await self.async_state_changed_listener(event) - - if self._battery_entity_id: - self.async_on_remove( - async_track_state_change_event( - self.hass, [self._battery_entity_id], _async_state_changed_listener - ) - ) - - # Call once on adding - await _async_state_changed_listener() + await super().async_added_to_hass() # Update entity options registry = er.async_get(self.hass) - if registry.async_get(self.entity_id) is not None and self._battery_entity_id: + if registry.async_get(self.entity_id) is not None and self.coordinator.wrapped_battery.entity_id: registry.async_update_entity_options( self.entity_id, DOMAIN, - {"entity_id": self._battery_entity_id}, + {"entity_id": self.coordinator.wrapped_battery.entity_id}, ) await self.coordinator.async_config_entry_first_refresh() + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + + if ( + ( + wrapped_battery_state := self.hass.states.get( + self.coordinator.wrapped_battery.entity_id + ) + ) + is None + or wrapped_battery_state.state + in [ + STATE_UNAVAILABLE, + STATE_UNKNOWN, + ] + or not isfloat(wrapped_battery_state.state) + ): + self._attr_is_on = None + self._attr_available = False + self.async_write_ha_state() + return + + self._attr_is_on = self.coordinator.battery_low + + self.async_write_ha_state() + + _LOGGER.debug("%s binary sensor battery_low set to: %s", self.coordinator.wrapped_battery.entity_id, self.coordinator.battery_low) + @property def extra_state_attributes(self) -> dict[str, str] | None: """Return the state attributes of battery low.""" diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 9307fd525..9f0394f93 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -174,6 +174,9 @@ def __init__( device_id: str, ) -> None: """Create a battery replaced button.""" + + super().__init__() + device_registry = dr.async_get(hass) self.coordinator = coordinator @@ -188,7 +191,7 @@ def __init__( identifiers=device.identifiers, ) - self.entity_id = f"button.{device.name.lower()}_{description.key}" + self.entity_id = f"button.{coordinator.device_name.lower()}_{description.key}" async def async_added_to_hass(self) -> None: """Handle added to Hass.""" diff --git a/custom_components/battery_notes/common.py b/custom_components/battery_notes/common.py index 1f688e70e..181a99afd 100644 --- a/custom_components/battery_notes/common.py +++ b/custom_components/battery_notes/common.py @@ -3,8 +3,10 @@ def isfloat(num): """Is the value a float.""" - try: - float(num) - return True - except ValueError: - return False + if num: + try: + float(num) + return True + except ValueError: + return False + return False diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index e93015356..591e53a58 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -70,6 +70,8 @@ ATTR_BATTERY_LOW_THRESHOLD = "battery_low_threshold" ATTR_DEVICE_NAME = "device_name" ATTR_BATTERY_LEVEL = "battery_level" +ATTR_BATTERY_LAST_REPORTED = "battery_last_reported" +ATTR_BATTERY_LAST_REPORTED_LEVEL = "battery_last_reported_level" ATTR_PREVIOUS_BATTERY_LEVEL = "previous_battery_level" SERVICE_BATTERY_REPLACED_SCHEMA = vol.Schema( diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index de5ae782e..ba3f565c6 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -10,10 +10,32 @@ DataUpdateCoordinator, ) +from homeassistant.const import ( + STATE_UNAVAILABLE, + STATE_UNKNOWN, +) + + +from .common import isfloat from .store import BatteryNotesStorage from .const import ( DOMAIN, + DOMAIN_CONFIG, + CONF_BATTERY_INCREASE_THRESHOLD, + CONF_ENABLE_REPLACED, + CONF_ROUND_BATTERY, + EVENT_BATTERY_THRESHOLD, + EVENT_BATTERY_INCREASED, + DEFAULT_BATTERY_INCREASE_THRESHOLD, + ATTR_DEVICE_ID, + ATTR_BATTERY_QUANTITY, + ATTR_BATTERY_TYPE, + ATTR_BATTERY_TYPE_AND_QUANTITY, + ATTR_BATTERY_LOW, + ATTR_DEVICE_NAME, + ATTR_BATTERY_LEVEL, + ATTR_PREVIOUS_BATTERY_LEVEL, ATTR_REMOVE, LAST_REPLACED, ) @@ -25,22 +47,99 @@ class BatteryNotesCoordinator(DataUpdateCoordinator): """Define an object to hold Battery Notes device.""" device_id: str + device_name: str battery_type: str battery_quantity: int - battery_low: bool battery_low_threshold: int + last_reported: datetime = None + last_reported_level: float = None + wrapped_battery: RegistryEntry + _current_battery_level: str = None + enable_replaced: bool = True + _round_battery: bool = False + _previous_battery_low: bool = None + _previous_battery_level: str = None def __init__( self, hass, store: BatteryNotesStorage, wrapped_battery: RegistryEntry ): """Initialize.""" - self.hass = hass self.store = store self.wrapped_battery = wrapped_battery - self.battery_low = False + + if DOMAIN_CONFIG in hass.data[DOMAIN]: + domain_config: dict = hass.data[DOMAIN][DOMAIN_CONFIG] + self.enable_replaced = domain_config.get(CONF_ENABLE_REPLACED, True) + self._round_battery = domain_config.get(CONF_ROUND_BATTERY, False) super().__init__(hass, _LOGGER, name=DOMAIN) + @property + def current_battery_level(self): + """Get the current battery level.""" + return self._current_battery_level + + @current_battery_level.setter + def current_battery_level(self, value): + """Set the current battery level and fire events if valid.""" + self._current_battery_level = value + + if self._previous_battery_level is not None: + # Battery low event + if self.battery_low != self._previous_battery_low: + self.hass.bus.async_fire( + EVENT_BATTERY_THRESHOLD, + { + ATTR_DEVICE_ID: self.device_id, + ATTR_DEVICE_NAME: self.device_name, + ATTR_BATTERY_LOW: self.battery_low, + ATTR_BATTERY_TYPE_AND_QUANTITY: self.battery_type_and_quantity, + ATTR_BATTERY_TYPE: self.battery_type, + ATTR_BATTERY_QUANTITY: self.battery_quantity, + ATTR_BATTERY_LEVEL: self.rounded_battery_level, + ATTR_PREVIOUS_BATTERY_LEVEL: self._previous_battery_level, + }, + ) + + _LOGGER.debug("battery_threshold event fired Low: %s", self.battery_low) + + # Battery increased event + increase_threshold = DEFAULT_BATTERY_INCREASE_THRESHOLD + if DOMAIN_CONFIG in self.hass.data[DOMAIN]: + domain_config: dict = self.hass.data[DOMAIN][DOMAIN_CONFIG] + increase_threshold = domain_config.get( + CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD + ) + + if self._current_battery_level not in [STATE_UNAVAILABLE, STATE_UNKNOWN]: + if ( + self._current_battery_level + and self._previous_battery_level + and float(self._current_battery_level) + >= (float(self._previous_battery_level) + increase_threshold) + ): + self.hass.bus.async_fire( + EVENT_BATTERY_INCREASED, + { + ATTR_DEVICE_ID: self.device_id, + ATTR_DEVICE_NAME: self.device_name, + ATTR_BATTERY_LOW: self.battery_low, + ATTR_BATTERY_TYPE_AND_QUANTITY: self.battery_type_and_quantity, + ATTR_BATTERY_TYPE: self.battery_type, + ATTR_BATTERY_QUANTITY: self.battery_quantity, + ATTR_BATTERY_LEVEL: self.rounded_battery_level, + ATTR_PREVIOUS_BATTERY_LEVEL: self._previous_battery_level, + }, + ) + + _LOGGER.debug("battery_increased event fired") + + if self._current_battery_level not in [STATE_UNAVAILABLE, STATE_UNKNOWN]: + self.last_reported = datetime.utcnow() + self.last_reported_level = self._current_battery_level + self._previous_battery_low = self.battery_low + self._previous_battery_level = self._current_battery_level + @property def battery_type_and_quantity(self) -> str: """Merge battery type & quantity.""" @@ -49,7 +148,7 @@ def battery_type_and_quantity(self) -> str: return self.battery_type @property - def last_replaced(self) -> datetime: + def last_replaced(self) -> datetime | None: """Get the last replaced datetime.""" device_entry = self.store.async_get_device(self.device_id) if device_entry: @@ -60,9 +159,23 @@ def last_replaced(self) -> datetime: return last_replaced_date return None - def set_battery_low(self, value: bool): - """Battery low setter.""" - self.battery_low = value + @property + def battery_low(self) -> bool: + """Check if battery low against threshold.""" + if isfloat(self.current_battery_level): + return bool( + float(self.current_battery_level) < self.battery_low_threshold + ) + + return False + + @property + def rounded_battery_level(self) -> float: + """Return the battery level, rounded if preferred.""" + if isfloat(self.current_battery_level): + return round(float(self.current_battery_level), 0 if self._round_battery else 1) + else: + return self.current_battery_level async def _async_update_data(self): """Update data.""" diff --git a/custom_components/battery_notes/device.py b/custom_components/battery_notes/device.py index 4817c8fec..d7d0ae688 100644 --- a/custom_components/battery_notes/device.py +++ b/custom_components/battery_notes/device.py @@ -115,6 +115,7 @@ async def async_setup(self) -> bool: ) self.coordinator.device_id = device_id + self.coordinator.device_name = self.device_name self.coordinator.battery_type = config.data.get(CONF_BATTERY_TYPE) try: self.coordinator.battery_quantity = int( diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 16af6f7db..81f5fb042 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -62,6 +62,8 @@ ATTR_BATTERY_LAST_REPLACED, ATTR_BATTERY_LOW, ATTR_BATTERY_LOW_THRESHOLD, + ATTR_BATTERY_LAST_REPORTED, + ATTR_BATTERY_LAST_REPORTED_LEVEL, ) from .common import isfloat @@ -277,7 +279,7 @@ def __init__( identifiers=device_entry.identifiers, ) - self.entity_id = f"sensor.{device_entry.name.lower()}_{description.key}" + self.entity_id = f"sensor.{coordinator.device_name.lower()}_{description.key}" entity_category = ( device.wrapped_battery.entity_category if device.wrapped_battery else None @@ -285,26 +287,27 @@ def __init__( self._attr_entity_category = entity_category self._attr_unique_id = unique_id - self._battery_entity_id = ( - device.wrapped_battery.entity_id if device.wrapped_battery else None - ) self._attr_device_class = SensorDeviceClass.BATTERY self._attr_state_class = SensorStateClass.MEASUREMENT self._attr_native_unit_of_measurement = PERCENTAGE @callback - def async_state_changed_listener( + async def async_state_changed_listener( self, event: EventType[EventStateChangedData] | None = None ) -> None: # pylint: disable=unused-argument """Handle child updates.""" - if not self._battery_entity_id: + if not self.coordinator.wrapped_battery.entity_id: return if ( - (wrapped_battery_state := self.hass.states.get(self._battery_entity_id)) + ( + wrapped_battery_state := self.hass.states.get( + self.coordinator.wrapped_battery.entity_id + ) + ) is None or wrapped_battery_state.state in [ @@ -318,13 +321,12 @@ def async_state_changed_listener( self.async_write_ha_state() return - self._attr_available = True + self.coordinator.current_battery_level = wrapped_battery_state.state - if self.round_battery: - self._attr_native_value = round(float(wrapped_battery_state.state), 0) - else: - self._attr_native_value = round(float(wrapped_battery_state.state), 1) + await self.coordinator.async_request_refresh() + self._attr_available = True + self._attr_native_value = self.coordinator.rounded_battery_level self._wrapped_attributes = wrapped_battery_state.attributes self.async_write_ha_state() @@ -333,50 +335,59 @@ async def async_added_to_hass(self) -> None: """Handle added to Hass.""" @callback - def _async_state_changed_listener( + async def _async_state_changed_listener( event: EventType[EventStateChangedData] | None = None, ) -> None: """Handle child updates.""" - self.async_state_changed_listener(event) + await self.async_state_changed_listener(event) - if self._battery_entity_id: + if self.coordinator.wrapped_battery.entity_id: self.async_on_remove( async_track_state_change_event( - self.hass, [self._battery_entity_id], _async_state_changed_listener + self.hass, + [self.coordinator.wrapped_battery.entity_id], + _async_state_changed_listener, ) ) # Call once on adding - _async_state_changed_listener() + await _async_state_changed_listener() # Update entity options registry = er.async_get(self.hass) - if registry.async_get(self.entity_id) is not None and self._battery_entity_id: + if ( + registry.async_get(self.entity_id) is not None + and self.coordinator.wrapped_battery.entity_id + ): registry.async_update_entity_options( self.entity_id, DOMAIN, - {"entity_id": self._battery_entity_id}, + {"entity_id": self.coordinator.wrapped_battery.entity_id}, ) - if not (wrapped_battery := registry.async_get(self._battery_entity_id)): + if not self.coordinator.wrapped_battery: return if DOMAIN_CONFIG in self.hass.data[DOMAIN]: domain_config: dict = self.hass.data[DOMAIN][DOMAIN_CONFIG] hide_battery = domain_config.get(CONF_HIDE_BATTERY, False) if hide_battery: - if wrapped_battery and not wrapped_battery.hidden: + if ( + self.coordinator.wrapped_battery + and not self.coordinator.wrapped_battery.hidden + ): registry.async_update_entity( - wrapped_battery.entity_id, + self.coordinator.wrapped_battery.entity_id, hidden_by=er.RegistryEntryHider.INTEGRATION, ) else: if ( - wrapped_battery - and wrapped_battery.hidden_by == er.RegistryEntryHider.INTEGRATION + self.coordinator.wrapped_battery + and self.coordinator.wrapped_battery.hidden_by + == er.RegistryEntryHider.INTEGRATION ): registry.async_update_entity( - wrapped_battery.entity_id, hidden_by=None + self.coordinator.wrapped_battery.entity_id, hidden_by=None ) def copy_custom_name(wrapped_battery: er.RegistryEntry) -> None: @@ -387,7 +398,7 @@ def copy_custom_name(wrapped_battery: er.RegistryEntry) -> None: self.entity_id, name=wrapped_battery.name + "+" ) - copy_custom_name(wrapped_battery) + copy_custom_name(self.coordinator.wrapped_battery) self.async_on_remove( self.coordinator.async_add_listener(self._handle_coordinator_update) @@ -413,6 +424,8 @@ def extra_state_attributes(self) -> dict[str, str] | None: ATTR_BATTERY_TYPE_AND_QUANTITY: self.coordinator.battery_type_and_quantity, ATTR_BATTERY_LOW: self.coordinator.battery_low, ATTR_BATTERY_LOW_THRESHOLD: self.coordinator.battery_low_threshold, + ATTR_BATTERY_LAST_REPORTED: self.coordinator.last_reported, + ATTR_BATTERY_LAST_REPORTED_LEVEL: self.coordinator.last_reported_level, } if self.enable_replaced: @@ -465,7 +478,7 @@ def __init__( identifiers=device_entry.identifiers, ) - self.entity_id = f"sensor.{device_entry.name.lower()}_{description.key}" + self.entity_id = f"sensor.{coordinator.device_name.lower()}_{description.key}" self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity @@ -515,7 +528,6 @@ class BatteryNotesLastReplacedSensor( _attr_should_poll = False entity_description: BatteryNotesSensorEntityDescription - _battery_entity_id = None def __init__( self, @@ -527,7 +539,7 @@ def __init__( ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(coordinator) + self._attr_device_class = description.device_class self._attr_has_entity_name = True self._attr_unique_id = unique_id @@ -535,6 +547,9 @@ def __init__( self.entity_description = description self._native_value = None + super().__init__( + coordinator=coordinator) + self._set_native_value(log_on_error=False) device_registry = dr.async_get(hass) @@ -547,7 +562,7 @@ def __init__( identifiers=device_entry.identifiers, ) - self.entity_id = f"sensor.{device_entry.name.lower()}_{description.key}" + self.entity_id = f"sensor.{coordinator.device_name.lower()}_{description.key}" async def async_added_to_hass(self) -> None: """Handle added to Hass.""" diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 074142f2a..422971005 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Lav tærskel for batteri" + }, + "battery_last_reported": { + "name": "Batteri sidst rapporteret" + }, + "battery_last_reported_level": { + "name": "Sidst rapporterede batteriniveau" } } }, diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index fc4aaa0d8..11ec66ca9 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Schwelle für niedrigen Batteriestand" + }, + "battery_last_reported": { + "name": "Batterie zuletzt gemeldet" + }, + "battery_last_reported_level": { + "name": "Letzter gemeldeter Batteriestand" } } }, diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index eea54911a..b7be4aa25 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Battery low threshold" + }, + "battery_last_reported": { + "name": "Battery last reported" + }, + "battery_last_reported_level": { + "name": "Battery last reported level" } } }, diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index 3dd47289b..0f6dfb113 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Seuil bas de la batterie" + }, + "battery_last_reported": { + "name": "Batterie signalée pour la dernière fois" + }, + "battery_last_reported_level": { + "name": "Dernier niveau de batterie signalé" } } }, diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index 490c866a8..c8a4836ff 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Az akkumulátor alacsony küszöbértéke" + }, + "battery_last_reported": { + "name": "Az akkumulátor legutóbbi jelentése" + }, + "battery_last_reported_level": { + "name": "Az akkumulátor utoljára jelentett szintje" } } }, diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index 3f3e5fdfa..76fbab5b0 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Próg niskiego poziomu baterii" + }, + "battery_last_reported": { + "name": "Ostatni raport dotyczący baterii" + }, + "battery_last_reported_level": { + "name": "Ostatni zgłoszony poziom baterii" } } }, diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index 70a3affb4..6d4c8e361 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "Nízky prah batérie" + }, + "battery_last_reported": { + "name": "Batéria bola naposledy nahlásená" + }, + "battery_last_reported_level": { + "name": "Posledná nahlásená úroveň batérie" } } }, diff --git a/custom_components/battery_notes/translations/ur.json b/custom_components/battery_notes/translations/ur.json index 4e973c7ed..86719e218 100644 --- a/custom_components/battery_notes/translations/ur.json +++ b/custom_components/battery_notes/translations/ur.json @@ -86,6 +86,12 @@ }, "battery_low_threshold": { "name": "بیٹری کی کم حد" + }, + "battery_last_reported": { + "name": "بیٹری کی آخری اطلاع دی گئی۔" + }, + "battery_last_reported_level": { + "name": "بیٹری کی آخری اطلاع دی گئی سطح" } } }, @@ -121,4 +127,4 @@ "name": "سیٹ کی بیٹری کو تبدیل کر دیا گیا۔" } } -} +} \ No newline at end of file diff --git a/docs/entities.md b/docs/entities.md index 06c2be33f..8e92a15f1 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -18,7 +18,9 @@ See how to use this entity in the [community contributions](./community.md) | `battery_type_and_quantity` | `string` | The type of batteries with the quantity if more than 1 | | `battery_last_replaced` | `string` | The date and time the battery was last replaced | | `battery_low` | `bool` | An indicator of whether the battery is low based on the device or global threshold | -| `battery_low_threshold` | `int` | The device or global threshold for when the battery is low. | +| `battery_low_threshold` | `int` | The device or global threshold for when the battery is low | +| `battery_last_reported` | `datetime` | The datetime when the battery level was last reported | +| `battery_last_reported_level` | `float` | The level when the battery was last reported | ## Battery Type `sensor.{{device_name}}_battery_type` @@ -41,7 +43,7 @@ The last time the battery of the device was replaced. A button to set the battery_last_replaced entity to now. ## Battery Low -`sensor.{{device_name}}_battery_low` +`sensor.{{device_name}}_battery_plus_low` A boolean sensor indicating if the battery is low, true when the battery is below the device or global threshold. diff --git a/hacs.json b/hacs.json index 16e27e6c3..cd4652c11 100644 --- a/hacs.json +++ b/hacs.json @@ -2,8 +2,8 @@ "name": "Battery Notes", "filename": "battery_notes.zip", "hide_default_branch": true, - "homeassistant": "2023.8.0", + "homeassistant": "2023.9.0", "render_readme": true, "zip_release": true, "persistent_directory": "data" -} +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 1fcc9904a..9eaa78764 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ colorlog==6.8.2 -homeassistant==2023.8.0 +homeassistant==2023.9.0 pip>=21.0,<24.1 ruff==0.2.0