From f2e26efff093c8b7b34568cc88442f432e12db4b Mon Sep 17 00:00:00 2001 From: Renaud ZERT Date: Tue, 29 Sep 2026 17:13:53 +0200 Subject: [PATCH] Handle missing time_since_update in diskio data Glances v4 only adds "time_since_update" (and the rates) to a plugin's stats once a previous sample exists. The first diskio sample after the Glances server starts therefore lacks it, and get_ha_sensor_data() raised KeyError. In Home Assistant this fails the config entry setup for good when Glances and Home Assistant start together (host reboot). Keep the disk with read/write set to None for that sample, like the network sensors, so the entities are still created and get values on the next update. Fixes #57 Co-Authored-By: Claude Opus 5.5 --- glances_api/__init__.py | 11 ++++++++--- tests/test_responses.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/glances_api/__init__.py b/glances_api/__init__.py index 5522ae9..d2a054c 100644 --- a/glances_api/__init__.py +++ b/glances_api/__init__.py @@ -227,9 +227,14 @@ async def get_ha_sensor_data(self) -> dict[str, Any]: if data := self.data.get("diskio"): sensor_data["diskio"] = {} for disk in data: - time_since_update = disk["time_since_update"] + read = write = None + # Glances v4 omits "time_since_update" on the first sample after + # the server starts, as there is no previous sample to compare to + if time_since_update := disk.get("time_since_update"): + read = round(disk["read_bytes"] / time_since_update) + write = round(disk["write_bytes"] / time_since_update) sensor_data["diskio"][disk["disk_name"]] = { - "read": round(disk["read_bytes"] / time_since_update), - "write": round(disk["write_bytes"] / time_since_update), + "read": read, + "write": write, } return sensor_data diff --git a/tests/test_responses.py b/tests/test_responses.py index 16fffc9..b8c7409 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -453,6 +453,38 @@ async def test_ha_sensor_data( assert result == expected +@pytest.mark.asyncio +async def test_ha_sensor_data_diskio_first_sample(httpx_mock: HTTPXMock) -> None: + """Test the diskio sensors on the first sample after Glances v4 starts.""" + # No previous sample yet: no "time_since_update", no rates, raw counters + response = { + **RESPONSE_V4, + "diskio": [ + { + "read_count": 442933, + "write_count": 937984, + "read_bytes": 15653558272, + "write_bytes": 16872076288, + "read_time": 64763666, + "write_time": 171581008, + "key": "disk_name", + "disk_name": "nvme0n1", + }, + ], + } + expected = { + **HA_SENSOR_DATA_V4, + "diskio": {"nvme0n1": {"read": None, "write": None}}, + } + + httpx_mock.add_response(json=response) + + client = Glances(version=4) + result = await client.get_ha_sensor_data() + + assert result == expected + + @pytest.mark.asyncio async def test_ha_sensor_data_with_incomplete_container_information( httpx_mock: HTTPXMock,