From 639fbb6a3d3451f7b5f4bcc6d684023f6b225b8e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 5 Mar 2024 08:52:34 +0000 Subject: [PATCH] Battery low service (#1234) * Add check_battery_low service * Community example * Typo * Remove @bind_hass * Add battery levels * Fix service icons * Change event data to reminder * Lint issues --- custom_components/battery_notes/__init__.py | 41 ++++++++++++++++++- custom_components/battery_notes/const.py | 2 + .../battery_notes/coordinator.py | 3 ++ custom_components/battery_notes/icons.json | 3 +- .../battery_notes/library_updater.py | 2 +- custom_components/battery_notes/services.yaml | 3 ++ custom_components/battery_notes/store.py | 3 -- .../battery_notes/translations/en.json | 4 ++ docs/community.md | 16 ++++++++ docs/events.md | 1 + docs/services.md | 11 +++++ 11 files changed, 83 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 7b0dc19fc..71ba9654c 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -56,7 +56,9 @@ SERVICE_CHECK_BATTERY_LAST_REPORTED, SERVICE_DATA_DAYS_LAST_REPORTED, SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA, + SERVICE_CHECK_BATTERY_LOW, EVENT_BATTERY_NOT_REPORTED, + EVENT_BATTERY_THRESHOLD, DATA_STORE, ATTR_REMOVE, ATTR_DEVICE_ID, @@ -67,6 +69,10 @@ ATTR_BATTERY_LAST_REPORTED, ATTR_BATTERY_LAST_REPORTED_DAYS, ATTR_BATTERY_LAST_REPORTED_LEVEL, + ATTR_BATTERY_LEVEL, + ATTR_PREVIOUS_BATTERY_LEVEL, + ATTR_BATTERY_THRESHOLD_REMINDER, + ATTR_BATTERY_LOW, CONF_BATTERY_TYPE, CONF_BATTERY_QUANTITY, MIN_HA_VERSION, @@ -267,7 +273,7 @@ async def async_update_options(hass: HomeAssistant, entry: ConfigEntry) -> None: @callback -def register_services(hass): +def register_services(hass: HomeAssistant): """Register services used by battery notes component.""" async def handle_battery_replaced(call): @@ -356,6 +362,33 @@ async def handle_battery_last_reported(call): str(device.coordinator.last_reported), ) + async def handle_battery_low(call): + """Handle the service call.""" + + device: BatteryNotesDevice + for device in hass.data[DOMAIN][DATA].devices.values(): + if device.coordinator.battery_low is True: + + hass.bus.async_fire( + EVENT_BATTERY_THRESHOLD, + { + ATTR_DEVICE_ID: device.coordinator.device_id, + ATTR_DEVICE_NAME: device.coordinator.device_name, + ATTR_BATTERY_LOW: device.coordinator.battery_low, + ATTR_BATTERY_TYPE_AND_QUANTITY: device.coordinator.battery_type_and_quantity, + ATTR_BATTERY_TYPE: device.coordinator.battery_type, + ATTR_BATTERY_QUANTITY: device.coordinator.battery_quantity, + ATTR_BATTERY_LEVEL: device.coordinator.rounded_battery_level, + ATTR_PREVIOUS_BATTERY_LEVEL: device.coordinator._previous_battery_level, + ATTR_BATTERY_THRESHOLD_REMINDER: True, + }, + ) + + _LOGGER.debug( + "Raised event device %s battery low", + device.coordinator.device_id, + ) + hass.services.async_register( DOMAIN, SERVICE_BATTERY_REPLACED, @@ -369,3 +402,9 @@ async def handle_battery_last_reported(call): handle_battery_last_reported, schema=SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA, ) + + hass.services.async_register( + DOMAIN, + SERVICE_CHECK_BATTERY_LOW, + handle_battery_low, + ) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index d749e7d73..f404cb720 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -65,6 +65,7 @@ SERVICE_CHECK_BATTERY_LAST_REPORTED = "check_battery_last_reported" SERVICE_DATA_DAYS_LAST_REPORTED = "days_last_reported" +SERVICE_CHECK_BATTERY_LOW = "check_battery_low" EVENT_BATTERY_THRESHOLD = "battery_notes_battery_threshold" EVENT_BATTERY_INCREASED = "battery_notes_battery_increased" @@ -84,6 +85,7 @@ ATTR_BATTERY_LAST_REPORTED_DAYS = "battery_last_reported_days" ATTR_BATTERY_LAST_REPORTED_LEVEL = "battery_last_reported_level" ATTR_PREVIOUS_BATTERY_LEVEL = "previous_battery_level" +ATTR_BATTERY_THRESHOLD_REMINDER = "reminder" SERVICE_BATTERY_REPLACED_SCHEMA = vol.Schema( { diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 3579ad1e4..dbb0f9547 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -36,6 +36,7 @@ ATTR_DEVICE_NAME, ATTR_BATTERY_LEVEL, ATTR_PREVIOUS_BATTERY_LEVEL, + ATTR_BATTERY_THRESHOLD_REMINDER, ATTR_REMOVE, LAST_REPLACED, LAST_REPORTED, @@ -96,6 +97,7 @@ def battery_low_template_state(self, value): ATTR_BATTERY_TYPE_AND_QUANTITY: self.battery_type_and_quantity, ATTR_BATTERY_TYPE: self.battery_type, ATTR_BATTERY_QUANTITY: self.battery_quantity, + ATTR_BATTERY_THRESHOLD_REMINDER: False, }, ) @@ -145,6 +147,7 @@ def current_battery_level(self, value): ATTR_BATTERY_QUANTITY: self.battery_quantity, ATTR_BATTERY_LEVEL: self.rounded_battery_level, ATTR_PREVIOUS_BATTERY_LEVEL: self._previous_battery_level, + ATTR_BATTERY_THRESHOLD_REMINDER: False, }, ) diff --git a/custom_components/battery_notes/icons.json b/custom_components/battery_notes/icons.json index 12e03b769..acbbd05b3 100644 --- a/custom_components/battery_notes/icons.json +++ b/custom_components/battery_notes/icons.json @@ -1,6 +1,7 @@ { "services": { "set_battery_replaced": "mdi:battery-sync", - "check_battery_reported": "mdi:battery-unknown" + "check_battery_last_reported": "mdi:battery-unknown", + "check_battery_low": "mdi:battery-alert" } } \ No newline at end of file diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 2e4a6f324..00e35468f 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -100,7 +100,7 @@ async def get_library_updates(self, time): except LibraryUpdaterClientError: _LOGGER.warning( - "Library update failed, this could be a GitHub or internet connectivity issue, will retry later." + "Unable to update library, this could be a GitHub or internet connectivity issue, will retry later." ) async def time_to_update_library(self) -> bool: diff --git a/custom_components/battery_notes/services.yaml b/custom_components/battery_notes/services.yaml index 46a6044e2..977d3fb24 100644 --- a/custom_components/battery_notes/services.yaml +++ b/custom_components/battery_notes/services.yaml @@ -29,3 +29,6 @@ check_battery_last_reported: min: 1 max: 100 mode: box +check_battery_low: + name: Check battery low + description: "Raise events for devices that have a low battery." diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 146361582..57bfcbf72 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -9,7 +9,6 @@ import attr from homeassistant.core import callback, HomeAssistant -from homeassistant.loader import bind_hass from homeassistant.helpers.storage import Store from .const import ( @@ -140,8 +139,6 @@ def async_update_device(self, device_id: str, changes: dict) -> DeviceEntry: self.async_schedule_save() return new - -@bind_hass async def async_get_registry(hass: HomeAssistant) -> BatteryNotesStorage: """Return battery notes storage instance.""" task = hass.data.get(DATA_REGISTRY) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index cd0666346..00c7e25d9 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -139,6 +139,10 @@ } }, "name": "Check battery last reported" + }, + "check_battery_low": { + "description": "Raise events for devices that have a low battery.", + "name": "Check battery low" } } } \ No newline at end of file diff --git a/docs/community.md b/docs/community.md index 673eeb80d..1eb4412bc 100644 --- a/docs/community.md +++ b/docs/community.md @@ -72,6 +72,22 @@ action: mode: queued ``` +### Check Battery Low daily reminder +Call the check battery low service every day to raise events for those that are still low. +To be used in conjunction with a [Battery Low Notification](community.md/#battery-low-notification) or similar. + +```yaml +alias: Daily Battery Low Check +description: Check whether a battery is low +trigger: + - platform: time + at: "09:00:00" +condition: [] +action: + - service: battery_notes.check_battery_low +mode: single +``` + ### Battery Replaced Mark a battery as replaced when there is an increase in battery level. diff --git a/docs/events.md b/docs/events.md index 9400eb505..698bcf2e3 100644 --- a/docs/events.md +++ b/docs/events.md @@ -19,6 +19,7 @@ You can use this to send notifications in your preferred method. An example aut | `battery_quantity` | `int` | Battery quantity. | | `battery_level` | `float` | Battery level % of the device. | | `previous_battery_level` | `float` | Previous battery level % of the device. | +| `reminder` | `bool` | Returns true if the event was raised by a service call, false if it's from a device event. | ### Automation Example diff --git a/docs/services.md b/docs/services.md index 62cd9de4a..c543f7e43 100644 --- a/docs/services.md +++ b/docs/services.md @@ -24,3 +24,14 @@ See how to use this service in the [community contributions](./community.md) | Parameter | Optional | Description | | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------- | | `data.days` | `no` | The number of days since a device last reported its battery level. | + +## battery_notes.check_battery_low + +For raising events for devices that have a battery low status. + +The service will raise a seperate [battery_threshold](./events/battery_threshold) event for each device that have a battery low status. + +You can use this service call as a reminder that is convenient to you, e.g. when you wake up, once a week etc. The event has a boolean data item `reminder` to determine if the event was raised by this service or the device battery going to a low state. + +See how to use this service in the [community contributions](./community.md) +