Skip to content

Commit

Permalink
HACS updates #16
Browse files Browse the repository at this point in the history
  • Loading branch information
BeardedTinker committed May 13, 2024
1 parent 6c9850b commit b3eb82a
Show file tree
Hide file tree
Showing 15 changed files with 609 additions and 176 deletions.
100 changes: 72 additions & 28 deletions custom_components/battery_notes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
DATA_STORE,
ATTR_REMOVE,
ATTR_DEVICE_ID,
ATTR_SOURCE_ENTITY_ID,
ATTR_DEVICE_NAME,
ATTR_BATTERY_TYPE_AND_QUANTITY,
ATTR_BATTERY_TYPE,
Expand Down Expand Up @@ -279,6 +280,7 @@ def register_services(hass: HomeAssistant):
async def handle_battery_replaced(call):
"""Handle the service call."""
device_id = call.data.get(ATTR_DEVICE_ID, "")
source_entity_id = call.data.get(ATTR_SOURCE_ENTITY_ID, "")
datetime_replaced_entry = call.data.get(SERVICE_DATA_DATE_TIME_REPLACED)

if datetime_replaced_entry:
Expand All @@ -288,45 +290,85 @@ async def handle_battery_replaced(call):
else:
datetime_replaced = datetime.utcnow()

entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)

device_entry = device_registry.async_get(device_id)
if not device_entry:
_LOGGER.error(
"Device %s not found",
device_id,
)
return

for entry_id in device_entry.config_entries:
if (
entry := hass.config_entries.async_get_entry(entry_id)
) and entry.domain == DOMAIN:
coordinator = (
hass.data[DOMAIN][DATA].devices[entry.entry_id].coordinator
if source_entity_id:
source_entity_entry = entity_registry.async_get(source_entity_id)
if not source_entity_entry:
_LOGGER.error(
"Entity %s not found",
source_entity_id,
)
return

device_entry = {"battery_last_replaced": datetime_replaced}
# entity_id is the associated entity, now need to find the config entry for battery notes
for config_entry in hass.config_entries.async_entries(DOMAIN):
if config_entry.data.get("source_entity_id") == source_entity_id:
config_entry_id = config_entry.entry_id

coordinator.async_update_device_config(
device_id=device_id, data=device_entry
)
coordinator = (
hass.data[DOMAIN][DATA].devices[config_entry_id].coordinator
)

entry = {"battery_last_replaced": datetime_replaced}

coordinator.async_update_entity_config(
entity_id=source_entity_id, data=entry
)
await coordinator.async_request_refresh()

_LOGGER.debug(
"Entity %s battery replaced on %s",
source_entity_id,
str(datetime_replaced),
)

await coordinator.async_request_refresh()
return

_LOGGER.debug(
"Device %s battery replaced on %s",
_LOGGER.error(
"Entity %s not configured in Battery Notes",
source_entity_id
)

else:
device_entry = device_registry.async_get(device_id)
if not device_entry:
_LOGGER.error(
"Device %s not found",
device_id,
str(datetime_replaced),
)

# Found and dealt with, exit
return

_LOGGER.error(
"Device %s not configured in Battery Notes",
device_id,
)
for entry_id in device_entry.config_entries:
if (
entry := hass.config_entries.async_get_entry(entry_id)
) and entry.domain == DOMAIN:
coordinator = (
hass.data[DOMAIN][DATA].devices[entry.entry_id].coordinator
)

device_entry = {"battery_last_replaced": datetime_replaced}

coordinator.async_update_device_config(
device_id=device_id, data=device_entry
)

await coordinator.async_request_refresh()

_LOGGER.debug(
"Device %s battery replaced on %s",
device_id,
str(datetime_replaced),
)

# Found and dealt with, exit
return

_LOGGER.error(
"Device %s not configured in Battery Notes",
device_id,
)

async def handle_battery_last_reported(call):
"""Handle the service call."""
Expand All @@ -346,6 +388,7 @@ async def handle_battery_last_reported(call):
EVENT_BATTERY_NOT_REPORTED,
{
ATTR_DEVICE_ID: device.coordinator.device_id,
ATTR_SOURCE_ENTITY_ID: device.coordinator.source_entity_id,
ATTR_DEVICE_NAME: device.coordinator.device_name,
ATTR_BATTERY_TYPE_AND_QUANTITY: device.coordinator.battery_type_and_quantity,
ATTR_BATTERY_TYPE: device.coordinator.battery_type,
Expand Down Expand Up @@ -374,6 +417,7 @@ async def handle_battery_low(call):
{
ATTR_DEVICE_ID: device.coordinator.device_id,
ATTR_DEVICE_NAME: device.coordinator.device_name,
ATTR_SOURCE_ENTITY_ID: device.coordinator.source_entity_id,
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,
Expand Down
63 changes: 45 additions & 18 deletions custom_components/battery_notes/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ENTITY_ID
from homeassistant.core import (
HomeAssistant,
callback,
Event,
split_entity_id,
)
from homeassistant.exceptions import TemplateError
from homeassistant.helpers.entity import Entity
Expand Down Expand Up @@ -64,9 +64,10 @@
DOMAIN,
DATA,
ATTR_BATTERY_LOW_THRESHOLD,
CONF_SOURCE_ENTITY_ID,
)

from .common import isfloat
from .common import validate_is_float

from .device import BatteryNotesDevice
from .coordinator import BatteryNotesCoordinator
Expand All @@ -87,22 +88,25 @@ class BatteryNotesBinarySensorEntityDescription(

unique_id_suffix: str


PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{vol.Optional(CONF_NAME): cv.string, vol.Required(CONF_DEVICE_ID): cv.string}
{
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_DEVICE_ID): cv.string,
vol.Optional(CONF_SOURCE_ENTITY_ID): cv.string,
}
)


@callback
def async_add_to_device(hass: HomeAssistant, entry: ConfigEntry) -> str | None:
"""Add our config entry to the device."""
device_registry = dr.async_get(hass)

device_id = entry.data.get(CONF_DEVICE_ID)

if device_registry.async_get(device_id):
device_registry.async_update_device(device_id, add_config_entry_id=entry.entry_id)
return device_id
if device_id:
if device_registry.async_get(device_id):
device_registry.async_update_device(device_id, add_config_entry_id=entry.entry_id)
return device_id
return None

async def async_setup_entry(
Expand Down Expand Up @@ -133,7 +137,7 @@ async def async_registry_updated(event: Event) -> None:
# If the tracked battery note is no longer in the device, remove our config entry
# from the device
if (
not (entity_entry := entity_registry.async_get(data[CONF_ENTITY_ID]))
not (entity_entry := entity_registry.async_get(data["entity_id"]))
or not device_registry.async_get(device_id)
or entity_entry.device_id == device_id
):
Expand All @@ -152,10 +156,13 @@ async def async_registry_updated(event: Event) -> None:
)
)

device_id = async_add_to_device(hass, config_entry)
device: BatteryNotesDevice = hass.data[DOMAIN][DATA].devices[config_entry.entry_id]

if not device_id:
return
if not device.fake_device:
device_id = async_add_to_device(hass, config_entry)

if not device_id:
return

description = BatteryNotesBinarySensorEntityDescription(
unique_id_suffix="_battery_low",
Expand Down Expand Up @@ -315,7 +322,6 @@ def __init__(
self.coordinator = coordinator
self.entity_description = description
self._attr_unique_id = unique_id
self._attr_has_entity_name = True
self._template_attrs: dict[Template, list[_TemplateAttribute]] = {}

super().__init__(coordinator=coordinator)
Expand All @@ -328,7 +334,18 @@ def __init__(
identifiers=device_entry.identifiers,
)

self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"
self._attr_has_entity_name = True

if coordinator.source_entity_id and not coordinator.device_id:
self._attr_translation_placeholders = {"device_name": coordinator.device_name + " "}
self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"
elif coordinator.source_entity_id and coordinator.device_id:
source_entity_domain, source_object_id = split_entity_id(coordinator.source_entity_id)
self._attr_translation_placeholders = {"device_name": coordinator.source_entity_name + " "}
self.entity_id = f"binary_sensor.{source_object_id}_{description.key}"
else:
self._attr_translation_placeholders = {"device_name": ""}
self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"

self._template = template
self._state: bool | None = None
Expand Down Expand Up @@ -497,9 +514,21 @@ def __init__(
device_registry = dr.async_get(hass)

self.coordinator = coordinator
self._attr_has_entity_name = True

if coordinator.source_entity_id and not coordinator.device_id:
self._attr_translation_placeholders = {"device_name": coordinator.device_name + " "}
self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"
elif coordinator.source_entity_id and coordinator.device_id:
source_entity_domain, source_object_id = split_entity_id(coordinator.source_entity_id)
self._attr_translation_placeholders = {"device_name": coordinator.source_entity_name + " "}
self.entity_id = f"binary_sensor.{source_object_id}_{description.key}"
else:
self._attr_translation_placeholders = {"device_name": ""}
self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"

self.entity_description = description
self._attr_unique_id = unique_id
self._attr_has_entity_name = True

super().__init__(coordinator=coordinator)

Expand All @@ -511,8 +540,6 @@ def __init__(
identifiers=device_entry.identifiers,
)

self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{description.key}"

async def async_added_to_hass(self) -> None:
"""Handle added to Hass."""

Expand All @@ -536,7 +563,7 @@ def _handle_coordinator_update(self) -> None:
STATE_UNAVAILABLE,
STATE_UNKNOWN,
]
or not isfloat(wrapped_battery_state.state)
or not validate_is_float(wrapped_battery_state.state)
):
self._attr_is_on = None
self._attr_available = False
Expand Down
Loading

0 comments on commit b3eb82a

Please sign in to comment.