From 6c30eef5768871977e289c1901d84b2b0ab59451 Mon Sep 17 00:00:00 2001 From: axxonite Date: Tue, 22 Sep 2026 11:43:06 -0400 Subject: [PATCH 1/2] feat: add `battery_status` property to `Tile` The Tile API returns a battery status on every tile detail response, but the `Tile` object defines no property for it, so consumers cannot reach it without touching `_tile_data` directly. This closes #107. The field is already present in this repo's own test fixtures (`tile_details_response.json` and `tile_details_missing_last_state_response.json` both carry `"battery_status": "NONE"`), so no fixture changes were needed. Observed against a live account with six Tiles: values are `NONE`, `LEVEL1` and `LEVEL2`, and whether a Tile reports a level at all depends on its firmware generation. The `05.x` firmware reported `LEVEL1`/`LEVEL2` while `40.x`/`42.x`/`43.x` reported `NONE`, so a missing level is normal rather than an error. The property uses `.get()` and is typed `str | None` accordingly. Note on `last_tile_state.battery_level`, also requested in #107: it is deliberately not added here. Across those same six Tiles it read exactly `0.0` on every poll, and this repo's fixture carries `0` as well. It appears to be a key Tile populates but never writes to, so exposing it would invite consumers to build low-battery logic on a value that is always zero. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Qui3EQaoxiVRCBVVe9waLw --- README.md | 1 + pytile/tile.py | 14 ++++++++++++++ tests/test_tile.py | 2 ++ 3 files changed, 17 insertions(+) diff --git a/README.md b/README.md index cdbae5d..06ba5f7 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ The Tile object comes with several properties: - `accuracy`: the location accuracy of the Tile - `altitude`: the altitude of the Tile - `archetype`: the internal reference string that describes the Tile's "family" +- `battery_status`: the Tile's battery status (e.g., `NONE`, `LEVEL1`, `LEVEL2`) - `dead`: whether the Tile is inactive - `firmware_version`: the Tile's firmware version - `hardware_version`: the Tile's hardware version diff --git a/pytile/tile.py b/pytile/tile.py index 78cb180..a97345e 100644 --- a/pytile/tile.py +++ b/pytile/tile.py @@ -69,6 +69,19 @@ def archetype(self) -> str: """ return cast(str, self._tile_data["result"]["archetype"]) + @property + def battery_status(self) -> str | None: + """Return the battery status. + + Observed values are "NONE", "LEVEL1" and "LEVEL2"; whether a Tile reports a + level at all depends on its firmware generation. The key is absent for some + node types, so this returns None rather than raising. + + Returns: + The battery status (if it exists). + """ + return cast("str | None", self._tile_data["result"].get("battery_status")) + @property def dead(self) -> bool: """Return whether the Tile is dead. @@ -237,6 +250,7 @@ def as_dict(self) -> dict[str, Any]: "accuracy": self.accuracy, "altitude": self.altitude, "archetype": self.archetype, + "battery_status": self.battery_status, "dead": self.dead, "firmware_version": self.firmware_version, "hardware_version": self.hardware_version, diff --git a/tests/test_tile.py b/tests/test_tile.py index d1c8cbb..3408229 100644 --- a/tests/test_tile.py +++ b/tests/test_tile.py @@ -125,6 +125,7 @@ async def test_get_tiles( assert tile.accuracy == 13.496111 assert tile.altitude == 0.4076319168123 assert tile.archetype == "WALLET" + assert tile.battery_status == "NONE" assert not tile.dead assert not tile.lost assert tile.firmware_version == "01.12.14.0" @@ -295,6 +296,7 @@ async def test_tile_as_dict( "accuracy": 13.496111, "altitude": 0.4076319168123, "archetype": "WALLET", + "battery_status": "NONE", "dead": False, "firmware_version": "01.12.14.0", "hardware_version": "02.09", From 708d6c51d8a5ed47373a5be21ca467a2f47f9bd4 Mon Sep 17 00:00:00 2001 From: axxonite Date: Tue, 22 Sep 2026 17:07:54 -0400 Subject: [PATCH 2/2] chore: allow `Tile` to exceed pylint's public-method limit Adding `battery_status` took `Tile` to 21 public methods, one past pylint's default of 20, which failed the Linting & Static Analysis job. `Tile` exposes one read-only property per API field, so its method count tracks the API surface rather than any design problem. Silence R0904 on the class with an inline disable, matching how `API.__init__` already handles `too-many-arguments`, instead of loosening the limit project-wide. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Qui3EQaoxiVRCBVVe9waLw --- pytile/tile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytile/tile.py b/pytile/tile.py index a97345e..1520ad4 100644 --- a/pytile/tile.py +++ b/pytile/tile.py @@ -9,7 +9,7 @@ from .const import LOGGER -class Tile: +class Tile: # pylint: disable=too-many-public-methods """Define a Tile.""" def __init__(