Skip to content

Commit

Permalink
202409 (#2273)
Browse files Browse the repository at this point in the history
* Change service to new 2024.9 schema

* Version bump to 2024.9

* Add a default battery last reported to now

* Set default battery last reported in device setup

* Default battery last replaced

* Don't default last replaced on older than 2024.9 devices

* Handle epoch

* Update dev environment

* Tidy up last replaced store update

* Add battery replaced event

* Remove import

* Apply automatic changes

* Lint error

* Remove unused import

---------

Co-authored-by: andrew-codechimp <[email protected]>
  • Loading branch information
andrew-codechimp and andrew-codechimp authored Oct 27, 2024
1 parent e12e7ac commit 858c914
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/integration/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "BN Integration",
"image": "mcr.microsoft.com/vscode/devcontainers/python:3.12-bullseye",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"postCreateCommand": "scripts/setup",
"runArgs": [
"--network=host"
Expand Down
2 changes: 1 addition & 1 deletion .ruff.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The contents of this file is based on https://github.com/home-assistant/core/blob/dev/pyproject.toml

target-version = "py310"
target-version = "py312"

[lint]
select = [
Expand Down
50 changes: 40 additions & 10 deletions custom_components/battery_notes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
DOMAIN,
DOMAIN_CONFIG,
EVENT_BATTERY_NOT_REPORTED,
EVENT_BATTERY_REPLACED,
EVENT_BATTERY_THRESHOLD,
MIN_HA_VERSION,
PLATFORMS,
Expand Down Expand Up @@ -306,11 +307,7 @@ async def handle_battery_replaced(call):
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
)
coordinator.last_replaced =datetime_replaced
await coordinator.async_request_refresh()

_LOGGER.debug(
Expand All @@ -319,6 +316,24 @@ async def handle_battery_replaced(call):
str(datetime_replaced),
)

hass.bus.async_fire(
EVENT_BATTERY_REPLACED,
{
ATTR_DEVICE_ID: coordinator.device_id or "",
ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id
or "",
ATTR_DEVICE_NAME: coordinator.device_name,
ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity,
ATTR_BATTERY_TYPE: coordinator.battery_type,
ATTR_BATTERY_QUANTITY: coordinator.battery_quantity,
},
)

_LOGGER.debug(
"Raised event battery replaced %s",
coordinator.device_id,
)

return

_LOGGER.error("Entity %s not configured in Battery Notes", source_entity_id)
Expand All @@ -340,11 +355,7 @@ async def handle_battery_replaced(call):
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
)
coordinator.last_replaced =datetime_replaced

await coordinator.async_request_refresh()

Expand All @@ -354,6 +365,24 @@ async def handle_battery_replaced(call):
str(datetime_replaced),
)

hass.bus.async_fire(
EVENT_BATTERY_REPLACED,
{
ATTR_DEVICE_ID: coordinator.device_id or "",
ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id
or "",
ATTR_DEVICE_NAME: coordinator.device_name,
ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity,
ATTR_BATTERY_TYPE: coordinator.battery_type,
ATTR_BATTERY_QUANTITY: coordinator.battery_quantity,
},
)

_LOGGER.debug(
"Raised event battery replaced %s",
coordinator.device_id,
)

# Found and dealt with, exit
return

Expand All @@ -362,6 +391,7 @@ async def handle_battery_replaced(call):
device_id,
)


async def handle_battery_last_reported(call):
"""Handle the service call."""
days_last_reported = call.data.get(SERVICE_DATA_DAYS_LAST_REPORTED)
Expand Down
37 changes: 28 additions & 9 deletions custom_components/battery_notes/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import logging
from dataclasses import dataclass
from datetime import datetime

Expand Down Expand Up @@ -35,18 +36,27 @@

from . import PLATFORMS
from .const import (
ATTR_BATTERY_QUANTITY,
ATTR_BATTERY_TYPE,
ATTR_BATTERY_TYPE_AND_QUANTITY,
ATTR_DEVICE_ID,
ATTR_DEVICE_NAME,
ATTR_SOURCE_ENTITY_ID,
CONF_ENABLE_REPLACED,
CONF_SOURCE_ENTITY_ID,
DATA,
DOMAIN,
DOMAIN_CONFIG,
EVENT_BATTERY_REPLACED,
)
from .coordinator import BatteryNotesCoordinator
from .device import BatteryNotesDevice
from .entity import (
BatteryNotesEntityDescription,
)

_LOGGER = logging.getLogger(__name__)


@dataclass
class BatteryNotesButtonEntityDescription(
Expand Down Expand Up @@ -241,15 +251,24 @@ async def async_added_to_hass(self) -> None:

async def async_press(self) -> None:
"""Press the button."""
device_id = self._device_id

entry = {"battery_last_replaced": datetime.utcnow()}
self.coordinator.last_replaced = datetime.utcnow()

self.hass.bus.async_fire(
EVENT_BATTERY_REPLACED,
{
ATTR_DEVICE_ID: self.coordinator.device_id or "",
ATTR_SOURCE_ENTITY_ID: self.coordinator.source_entity_id
or "",
ATTR_DEVICE_NAME: self.coordinator.device_name,
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,
},
)

if self._source_entity_id:
self.coordinator.async_update_entity_config(
entity_id=self.coordinator.source_entity_id, data=entry
)
else:
self.coordinator.async_update_device_config(device_id=device_id, data=entry)
_LOGGER.debug(
"Raised event battery replaced %s",
self.coordinator.device_id,
)

await self.coordinator.async_request_refresh()
3 changes: 2 additions & 1 deletion custom_components/battery_notes/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

LOGGER: Logger = getLogger(__package__)

MIN_HA_VERSION = "2024.7"
MIN_HA_VERSION = "2024.9"

manifestfile = Path(__file__).parent / "manifest.json"
with open(file=manifestfile, encoding="UTF-8") as json_file:
Expand Down Expand Up @@ -71,6 +71,7 @@
EVENT_BATTERY_THRESHOLD = "battery_notes_battery_threshold"
EVENT_BATTERY_INCREASED = "battery_notes_battery_increased"
EVENT_BATTERY_NOT_REPORTED = "battery_notes_battery_not_reported"
EVENT_BATTERY_REPLACED = "battery_notes_battery_replaced"

ATTR_DEVICE_ID = "device_id"
ATTR_SOURCE_ENTITY_ID = "source_entity_id"
Expand Down
13 changes: 12 additions & 1 deletion custom_components/battery_notes/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ def last_replaced(self) -> datetime | None:
return last_replaced_date
return None

@last_replaced.setter
def last_replaced(self, value):
"""Set the last replaced datetime and store it."""
entry = {LAST_REPLACED: value}

if self.source_entity_id:
self.async_update_entity_config(entity_id=self.source_entity_id, data=entry)
else:
self.async_update_device_config(device_id=self.device_id, data=entry)

@property
def last_reported(self) -> datetime | None:
"""Get the last reported datetime."""
Expand All @@ -257,12 +267,13 @@ def last_reported(self) -> datetime | None:
str(entry[LAST_REPORTED]) + "+00:00"
)
return last_reported_date

return None

@last_reported.setter
def last_reported(self, value):
"""Set the last reported datetime and store it."""
entry = {"battery_last_reported": value}
entry = {LAST_REPORTED: value}

if self.source_entity_id:
self.async_update_entity_config(entity_id=self.source_entity_id, data=entry)
Expand Down
32 changes: 32 additions & 0 deletions custom_components/battery_notes/device.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Battery Notes device, contains device level details."""

import logging
from datetime import datetime

from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.sensor import (
Expand Down Expand Up @@ -186,6 +187,37 @@ async def async_setup(self) -> bool:
self.coordinator.battery_low_threshold,
)

# If there is not a last replaced, set to device created date if not epoch
if not self.coordinator.last_replaced:
last_replaced = None
if entity.device_id:
device_entry = device_registry.async_get(entity.device_id)

if device_entry.created_at.year > 1970:
last_replaced = device_entry.created_at.strftime("%Y-%m-%dT%H:%M:%S:%f")
else:
entity = entity_registry.async_get(source_entity_id)
if entity.created_at.year > 1970:
last_replaced = entity.created_at.strftime("%Y-%m-%dT%H:%M:%S:%f")

_LOGGER.debug(
"Defaulting %s battery last replaced to %s",
source_entity_id or device_id,
last_replaced,
)

self.coordinator.last_replaced = last_replaced

# If there is not a last_reported set to now
if not self.coordinator.last_reported:
last_reported = datetime.utcnow()
_LOGGER.debug(
"Defaulting %s battery last reported to %s",
source_entity_id or device_id,
last_replaced,
)
self.coordinator.last_reported = last_reported

self.hass.data[DOMAIN][DATA].devices[config.entry_id] = self
self.reset_jobs.append(config.add_update_listener(self.async_update))

Expand Down
12 changes: 9 additions & 3 deletions custom_components/battery_notes/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
}
},
"services": {
"set_battery_replaced": "mdi:battery-sync",
"check_battery_last_reported": "mdi:battery-unknown",
"check_battery_low": "mdi:battery-alert"
"set_battery_replaced": {
"service": "mdi:battery-sync"
},
"check_battery_last_reported": {
"service": "mdi:battery-unknown"
},
"check_battery_low": {
"service": "mdi:battery-alert"
}
}
}
3 changes: 1 addition & 2 deletions custom_components/battery_notes/library_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

import asyncio
import json
import logging
import os
Expand Down Expand Up @@ -172,7 +171,7 @@ async def _api_wrapper(
# response.raise_for_status()
return await response.text()

except asyncio.TimeoutError as exception:
except TimeoutError as exception:
raise LibraryUpdaterClientCommunicationError(
"Timeout error fetching information",
) from exception
Expand Down
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Battery Notes",
"filename": "battery_notes.zip",
"hide_default_branch": true,
"homeassistant": "2024.7.0",
"homeassistant": "2024.9.0",
"render_readme": true,
"zip_release": true,
"persistent_directory": "data"
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
colorlog>=6.8.2,<7.0
homeassistant==2024.7.0
ruff>=0.5.0,<0.8
homeassistant==2024.9.0
ruff>=0.5.0,<0.8

0 comments on commit 858c914

Please sign in to comment.