Skip to content

Commit

Permalink
Merge branch 'andrew-codechimp:main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
bmos authored Dec 30, 2023
2 parents 2cd9e19 + ecf6b13 commit 2a1c3ab
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 105 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,21 @@ Go into Settings -> Integrations -> Battery Notes and click Configure on the dev
By default Battery Notes filters the device list to only devices with a battery, if you want to add a battery note to a random device then you can disable this filtering by adding the following configuration to your `configuration.yaml` and restart Home Assistant to see all devices.
```
battery_notes:
show_all_devices: true
show_all_devices: True
```

* I only want to add notes to a few devices, can I disable auto discovery?
If you want to disable this functionality you can add the following to your `configuration.yaml`, after a restart of Home Assistant you will not see discovered battery notes.
```
battery_notes:
enable_autodiscovery: false
enable_autodiscovery: False
```

* I don't want to track battery replacement, can I disable this?
Yes, you can add the following to your `configuration.yaml`, after a restart of Home Assistant *new* devices added to battery notes will have the battery replaced sensor and button disabled. Any devices you have previously added to Battery Notes you will have to disable/enable these sensors manually, which also means you can just enable specific sensors of important ones you want to track.
```
battery_notes:
enable_replaced: False
```

* How can I show my support?
Expand All @@ -124,10 +131,10 @@ Do not enable GitHub Actions (disabled by default) on your fork as this will mes
* The make & model names may be different between integrations such as Zigbee2MQTT and ZHA, if you see a similar device please duplicate the entry rather than changing it.
* Please keep devices in alphabetical order by manufacturer/model.
* The `battery_quantity` data is numeric (no quotes) and optional. If a device only requires a single battery, it should be omitted.
* The `battery_type` data should follow the most common naming for general batteries (ex. AAA, D) and the IEC naming for battery cells according to [Wikipedia](https://en.wikipedia.org/wiki/List_of_battery_sizes) (ex. CR2032, 18650)
* The `battery_type` data should follow the most common naming for general batteries (ex. AAA, D) and the IEC naming for battery cells (ex. CR2032, 18650) according to [Wikipedia](https://en.wikipedia.org/wiki/List_of_battery_sizes)
* If a device has a bespoke rechargeable battery you can use `"battery_type": "Rechargeable"`
* For devices like smoke alarms where the battery is not replaceable you can use `"battery_type": "Irreplaceable"`
* If a device shouldn't be discovered because there are multiple revisions with the same model number but different battery types or it's optionally mains powered, it can be added to the library with a `"battery_type": "MANUAL"` to note it is a device that shouldn't have a battery definition added to the library to save removal/re-add because people don't realise there are variants.
* If a device shouldn't be discovered because there are multiple revisions with the same model number but different battery types it can be added to the library with a `"battery_type": "MANUAL"` to note it is a device that shouldn't have a battery definition added to the library to save removal/re-add because people don't realise there are variants.

For the example image below, your JSON entry will look like this:

Expand Down
7 changes: 5 additions & 2 deletions custom_components/battery_notes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
DOMAIN_CONFIG,
PLATFORMS,
CONF_ENABLE_AUTODISCOVERY,
CONF_LIBRARY,
CONF_USER_LIBRARY,
DATA_UPDATE_COORDINATOR,
CONF_SHOW_ALL_DEVICES,
CONF_ENABLE_REPLACED,
SERVICE_BATTERY_REPLACED,
SERVICE_BATTERY_REPLACED_SCHEMA,
DATA_COORDINATOR,
Expand All @@ -53,8 +54,9 @@
vol.Schema(
{
vol.Optional(CONF_ENABLE_AUTODISCOVERY, default=True): cv.boolean,
vol.Optional(CONF_LIBRARY, default="library.json"): cv.string,
vol.Optional(CONF_USER_LIBRARY, default=""): cv.string,
vol.Optional(CONF_SHOW_ALL_DEVICES, default=False): cv.boolean,
vol.Optional(CONF_ENABLE_REPLACED, default=True): cv.boolean,
},
),
),
Expand All @@ -79,6 +81,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
domain_config: ConfigType = config.get(DOMAIN) or {
CONF_ENABLE_AUTODISCOVERY: True,
CONF_SHOW_ALL_DEVICES: False,
CONF_ENABLE_REPLACED: True,
}

hass.data[DOMAIN] = {
Expand Down
63 changes: 24 additions & 39 deletions custom_components/battery_notes/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,19 @@
)

from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import (
ConfigType,
)

from homeassistant.const import (
CONF_NAME,
CONF_UNIQUE_ID,
CONF_DEVICE_ID,
)

from . import PLATFORMS

from .const import (
DOMAIN,
DOMAIN_CONFIG,
DATA_COORDINATOR,
CONF_ENABLE_REPLACED,
)

from .entity import (
Expand All @@ -65,6 +63,7 @@ class BatteryNotesButtonEntityDescription(
translation_key="battery_replaced",
icon="mdi:battery-sync",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default = False,
),
)

Expand Down Expand Up @@ -131,38 +130,38 @@ async def async_registry_updated(event: Event) -> None:

device_id = async_add_to_device(hass, config_entry)

enable_replaced = True
if DOMAIN_CONFIG in hass.data[DOMAIN]:
domain_config = hass.data[DOMAIN][DOMAIN_CONFIG]
enable_replaced = domain_config.get(CONF_ENABLE_REPLACED, True)

description = BatteryNotesButtonEntityDescription(
unique_id_suffix="_battery_replaced_button",
key="battery_replaced",
translation_key="battery_replaced",
icon="mdi:battery-sync",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default = enable_replaced,
)

async_add_entities(
BatteryNotesButton(
[
BatteryNotesButton(
hass,
description,
f"{config_entry.entry_id}{description.unique_id_suffix}",
device_id,
)
for description in ENTITY_DESCRIPTIONS
)
]
)


async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the battery type button."""
device_id: str = config[CONF_DEVICE_ID]
"""Set up the battery note sensor."""

await async_setup_reload_service(hass, DOMAIN, PLATFORMS)

async_add_entities(
BatteryNotesButton(
hass,
description,
f"{config.get(CONF_UNIQUE_ID)}{description.unique_id_suffix}",
device_id,
)
for description in ENTITY_DESCRIPTIONS
)


class BatteryNotesButton(ButtonEntity):
"""Represents a battery replaced button."""

Expand All @@ -185,7 +184,6 @@ def __init__(
self._attr_has_entity_name = True
self._device_id = device_id

self._device_id = device_id
if device_id and (device := device_registry.async_get(device_id)):
self._attr_device_info = DeviceInfo(
connections=device.connections,
Expand All @@ -194,29 +192,15 @@ def __init__(

async def async_added_to_hass(self) -> None:
"""Handle added to Hass."""
# Update entity options
registry = er.async_get(self.hass)
if registry.async_get(self.entity_id) is not None:

registry.async_update_entity_options(
self.entity_id,
DOMAIN,
{"entity_id": self._attr_unique_id},
)

async def update_battery_last_replaced(self):
"""Handle sensor state changes."""

# device_id = self._device_id

# device_entry = {
# "battery_last_replaced" : datetime.utcnow()
# }

# coordinator = self.hass.data[DOMAIN][DATA_COORDINATOR]
# coordinator.async_update_device_config(device_id = device_id, data = device_entry)

self.async_write_ha_state()

async def async_press(self) -> None:
"""Press the button."""
device_id = self._device_id
Expand All @@ -227,3 +211,4 @@ async def async_press(self) -> None:
coordinator.async_update_device_config(device_id=device_id, data=device_entry)
await coordinator._async_update_data()
await coordinator.async_request_refresh()

4 changes: 4 additions & 0 deletions custom_components/battery_notes/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ async def async_step_integration_discovery(
"""Handle integration discovery."""
_LOGGER.debug("Starting discovery flow: %s", discovery_info)

unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}"
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

self.context["title_placeholders"] = {
"name": discovery_info[CONF_DEVICE_NAME],
"manufacturer": discovery_info[CONF_MANUFACTURER],
Expand Down
3 changes: 2 additions & 1 deletion custom_components/battery_notes/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
CONF_BATTERY_TYPE = "battery_type"
CONF_SENSORS = "sensors"
CONF_ENABLE_AUTODISCOVERY = "enable_autodiscovery"
CONF_LIBRARY = "library"
CONF_USER_LIBRARY = "user_library"
CONF_MODEL = "model"
CONF_MANUFACTURER = "manufacturer"
CONF_DEVICE_NAME = "device_name"
CONF_LIBRARY_URL = "https://raw.githubusercontent.com/andrew-codechimp/HA-Battery-Notes/main/custom_components/battery_notes/data/library.json" # pylint: disable=line-too-long
CONF_SHOW_ALL_DEVICES = "show_all_devices"
CONF_ENABLE_REPLACED = "enable_replaced"

DATA_CONFIGURED_ENTITIES = "configured_entities"
DATA_DISCOVERED_ENTITIES = "discovered_entities"
Expand Down
52 changes: 35 additions & 17 deletions custom_components/battery_notes/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
DOMAIN,
DATA_LIBRARY,
DOMAIN_CONFIG,
CONF_LIBRARY,
CONF_USER_LIBRARY,
)

BUILT_IN_DATA_DIRECTORY = os.path.join(os.path.dirname(__file__), "data")
Expand All @@ -23,29 +23,47 @@
class Library: # pylint: disable=too-few-public-methods
"""Hold all known battery types."""

_devices = None
_devices = []

def __init__(self, hass: HomeAssistant) -> None:
"""Init."""

if DOMAIN_CONFIG not in hass.data[DOMAIN]:
json_path = os.path.join(
BUILT_IN_DATA_DIRECTORY,
"library.json",
)
else:
json_path = os.path.join(
BUILT_IN_DATA_DIRECTORY,
hass.data[DOMAIN][DOMAIN_CONFIG].get(CONF_LIBRARY, "library.json"),
)
# User Library
if DOMAIN_CONFIG in hass.data[DOMAIN]:
if CONF_USER_LIBRARY in hass.data[DOMAIN][DOMAIN_CONFIG]:
user_library_filename = hass.data[DOMAIN][DOMAIN_CONFIG].get(CONF_USER_LIBRARY)
if user_library_filename != "":
json_user_path = os.path.join(
BUILT_IN_DATA_DIRECTORY,
user_library_filename,
)
_LOGGER.debug("Using user library file at %s", json_user_path)

try:
with open(json_user_path, encoding="utf-8") as user_file:
user_json_data = json.load(user_file)
self._devices = user_json_data["devices"]
user_file.close()

except FileNotFoundError:
_LOGGER.error(
"User library file not found at %s",
json_user_path,
)

# Default Library
json_default_path = os.path.join(
BUILT_IN_DATA_DIRECTORY,
"library.json",)

_LOGGER.debug("Using library file at %s", json_path)
_LOGGER.debug("Using library file at %s", json_default_path)

try:
with open(json_path, encoding="utf-8") as myfile:
json_data = json.load(myfile)
self._devices = json_data["devices"]
myfile.close()
with open(json_default_path, encoding="utf-8") as default_file:
default_json_data = json.load(default_file)
for i in default_json_data["devices"]:
self._devices.append(i)
default_file.close()

except FileNotFoundError:
_LOGGER.error(
Expand Down
2 changes: 1 addition & 1 deletion custom_components/battery_notes/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"integration_type": "device",
"iot_class": "calculated",
"issue_tracker": "https://github.com/andrew-codechimp/ha-battery-notes/issues",
"version": "1.3.3"
"version": "1.3.4"
}
Loading

0 comments on commit 2a1c3ab

Please sign in to comment.