From 13737ff2e65cd952f29407df3ba23ad176a4ecfc Mon Sep 17 00:00:00 2001 From: Sab44 <64696149+Sab44@users.noreply.github.com> Date: Mon, 23 Feb 2026 11:01:58 +0100 Subject: [PATCH] Bump librehardwaremonitor-api to version 1.10.1 (#163572) --- .../libre_hardware_monitor/manifest.json | 2 +- .../libre_hardware_monitor/sensor.py | 40 ++++++++++++++----- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../libre_hardware_monitor/test_sensor.py | 38 ++++++++++++------ 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/libre_hardware_monitor/manifest.json b/homeassistant/components/libre_hardware_monitor/manifest.json index 7a5873fec60..943f03c6579 100644 --- a/homeassistant/components/libre_hardware_monitor/manifest.json +++ b/homeassistant/components/libre_hardware_monitor/manifest.json @@ -7,5 +7,5 @@ "integration_type": "device", "iot_class": "local_polling", "quality_scale": "silver", - "requirements": ["librehardwaremonitor-api==1.9.1"] + "requirements": ["librehardwaremonitor-api==1.10.1"] } diff --git a/homeassistant/components/libre_hardware_monitor/sensor.py b/homeassistant/components/libre_hardware_monitor/sensor.py index c56bb75fc10..ad00ee35aea 100644 --- a/homeassistant/components/libre_hardware_monitor/sensor.py +++ b/homeassistant/components/libre_hardware_monitor/sensor.py @@ -5,6 +5,7 @@ from __future__ import annotations from typing import Any from librehardwaremonitor_api.model import LibreHardwareMonitorSensorData +from librehardwaremonitor_api.sensor_type import SensorType from homeassistant.components.sensor import SensorEntity, SensorStateClass from homeassistant.core import HomeAssistant, callback @@ -53,12 +54,8 @@ class LibreHardwareMonitorSensor( super().__init__(coordinator) self._attr_name: str = sensor_data.name - self._attr_native_value: str | None = sensor_data.value - self._attr_extra_state_attributes: dict[str, Any] = { - STATE_MIN_VALUE: sensor_data.min, - STATE_MAX_VALUE: sensor_data.max, - } - self._attr_native_unit_of_measurement = sensor_data.unit + + self._set_state(coordinator.data.is_deprecated_version, sensor_data) self._attr_unique_id: str = f"{entry_id}_{sensor_data.sensor_id}" self._sensor_id: str = sensor_data.sensor_id @@ -70,15 +67,36 @@ class LibreHardwareMonitorSensor( model=sensor_data.device_type, ) + def _set_state( + self, + is_deprecated_lhm_version: bool, + sensor_data: LibreHardwareMonitorSensorData, + ) -> None: + value = sensor_data.value + min_value = sensor_data.min + max_value = sensor_data.max + unit = sensor_data.unit + + if not is_deprecated_lhm_version and sensor_data.type == SensorType.THROUGHPUT: + # Temporary fix: convert the B/s value to KB/s to not break existing entries + # This will be migrated properly once SensorDeviceClass is introduced + value = f"{(float(value) / 1024):.1f}" if value else None + min_value = f"{(float(min_value) / 1024):.1f}" if min_value else None + max_value = f"{(float(max_value) / 1024):.1f}" if max_value else None + unit = "KB/s" + + self._attr_native_value: str | None = value + self._attr_extra_state_attributes: dict[str, Any] = { + STATE_MIN_VALUE: min_value, + STATE_MAX_VALUE: max_value, + } + self._attr_native_unit_of_measurement = unit + @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" if sensor_data := self.coordinator.data.sensor_data.get(self._sensor_id): - self._attr_native_value = sensor_data.value - self._attr_extra_state_attributes = { - STATE_MIN_VALUE: sensor_data.min, - STATE_MAX_VALUE: sensor_data.max, - } + self._set_state(self.coordinator.data.is_deprecated_version, sensor_data) else: self._attr_native_value = None diff --git a/requirements_all.txt b/requirements_all.txt index f5271221451..e469254aaf5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1416,7 +1416,7 @@ libpyfoscamcgi==0.0.9 libpyvivotek==0.6.1 # homeassistant.components.libre_hardware_monitor -librehardwaremonitor-api==1.9.1 +librehardwaremonitor-api==1.10.1 # homeassistant.components.mikrotik librouteros==3.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3b9d9810f41..21cbf4d8c57 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1250,7 +1250,7 @@ libpyfoscamcgi==0.0.9 libpyvivotek==0.6.1 # homeassistant.components.libre_hardware_monitor -librehardwaremonitor-api==1.9.1 +librehardwaremonitor-api==1.10.1 # homeassistant.components.mikrotik librouteros==3.2.0 diff --git a/tests/components/libre_hardware_monitor/test_sensor.py b/tests/components/libre_hardware_monitor/test_sensor.py index 8f4db123a49..8f62f716234 100644 --- a/tests/components/libre_hardware_monitor/test_sensor.py +++ b/tests/components/libre_hardware_monitor/test_sensor.py @@ -130,26 +130,38 @@ async def test_sensor_invalid_auth_during_startup( assert all(state.state == STATE_UNAVAILABLE for state in unavailable_states) +@pytest.mark.parametrize( + ("object_id", "sensor_id", "new_value", "state_value"), + [ + ( + "gaming_pc_amd_ryzen_7_7800x3d_package_temperature", + "amdcpu-0-temperature-3", + "42.1", + "42.1", + ), + ( + "gaming_pc_nvidia_geforce_rtx_4080_super_gpu_pcie_tx_throughput", + "gpu-nvidia-0-throughput-1", + "792150000.0", + "773584.0", + ), + ], +) async def test_sensors_are_updated( hass: HomeAssistant, mock_lhm_client: AsyncMock, mock_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, + object_id: str, + sensor_id: str, + new_value: str, + state_value: str, ) -> None: """Test sensors are updated with properly formatted values.""" await init_integration(hass, mock_config_entry) - entity_id = "sensor.gaming_pc_amd_ryzen_7_7800x3d_package_temperature" - state = hass.states.get(entity_id) - - assert state - assert state.state != STATE_UNAVAILABLE - assert state.state == "52.8" - updated_data = dict(mock_lhm_client.get_data.return_value.sensor_data) - updated_data["amdcpu-0-temperature-3"] = replace( - updated_data["amdcpu-0-temperature-3"], value="42.1" - ) + updated_data[sensor_id] = replace(updated_data[sensor_id], value=new_value) mock_lhm_client.get_data.return_value = replace( mock_lhm_client.get_data.return_value, sensor_data=MappingProxyType(updated_data), @@ -159,11 +171,11 @@ async def test_sensors_are_updated( async_fire_time_changed(hass) await hass.async_block_till_done() - state = hass.states.get(entity_id) + state = hass.states.get(f"sensor.{object_id}") assert state assert state.state != STATE_UNAVAILABLE - assert state.state == "42.1" + assert state.state == state_value async def test_sensor_state_is_unknown_when_no_sensor_data_is_provided( @@ -263,6 +275,7 @@ async def _mock_orphaned_device( if not sensor_id.startswith(removed_device) } ), + is_deprecated_version=False, ) return device_registry.async_get_or_create( @@ -287,6 +300,7 @@ async def test_integration_does_not_log_new_devices_on_first_refresh( } ), sensor_data=mock_lhm_client.get_data.return_value.sensor_data, + is_deprecated_version=False, ) with caplog.at_level(logging.WARNING):