From 3e0d75fec42bf061af6c20f772af416726cf8b7b Mon Sep 17 00:00:00 2001 From: Erwin Douna Date: Wed, 26 Aug 2026 22:51:40 +0200 Subject: [PATCH] Proxmox refactor to use UPTIME sensor (#169704) --- homeassistant/components/proxmoxve/sensor.py | 49 +++++---- .../proxmoxve/snapshots/test_sensor.ambr | 100 +++++------------- tests/components/proxmoxve/test_sensor.py | 1 + 3 files changed, 55 insertions(+), 95 deletions(-) diff --git a/homeassistant/components/proxmoxve/sensor.py b/homeassistant/components/proxmoxve/sensor.py index d4140fc13d5e..efe605007cd1 100644 --- a/homeassistant/components/proxmoxve/sensor.py +++ b/homeassistant/components/proxmoxve/sensor.py @@ -2,7 +2,7 @@ from collections.abc import Callable from dataclasses import dataclass -from datetime import datetime +from datetime import datetime, timedelta from typing import Any, override from homeassistant.components.sensor import ( @@ -44,14 +44,14 @@ class ProxmoxNodeSensorEntityDescription(SensorEntityDescription): class ProxmoxVMSensorEntityDescription(SensorEntityDescription): """Class to hold Proxmox VM sensor description.""" - value_fn: Callable[[dict[str, Any]], StateType] + value_fn: Callable[[dict[str, Any]], StateType | datetime] @dataclass(frozen=True, kw_only=True) class ProxmoxContainerSensorEntityDescription(SensorEntityDescription): """Class to hold Proxmox container sensor description.""" - value_fn: Callable[[dict[str, Any]], StateType] + value_fn: Callable[[dict[str, Any]], StateType | datetime] @dataclass(frozen=True, kw_only=True) @@ -138,12 +138,15 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = ( ProxmoxNodeSensorEntityDescription( key="node_uptime", translation_key="node_uptime", - value_fn=lambda data: data.node["uptime"], - device_class=SensorDeviceClass.DURATION, - native_unit_of_measurement=UnitOfTime.SECONDS, - suggested_unit_of_measurement=UnitOfTime.HOURS, + value_fn=( + lambda data: ( + (dt_util.utcnow() - timedelta(seconds=data.node["uptime"])) + if data.node["uptime"] is not None + else None + ) + ), + device_class=SensorDeviceClass.UPTIME, entity_category=EntityCategory.DIAGNOSTIC, - state_class=SensorStateClass.MEASUREMENT, ), ProxmoxNodeSensorEntityDescription( key="node_status", @@ -236,12 +239,15 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = ( ProxmoxVMSensorEntityDescription( key="vm_uptime", translation_key="vm_uptime", - value_fn=lambda data: data.get("uptime"), - device_class=SensorDeviceClass.DURATION, - native_unit_of_measurement=UnitOfTime.SECONDS, - suggested_unit_of_measurement=UnitOfTime.HOURS, + value_fn=( + lambda data: ( + (dt_util.utcnow() - timedelta(seconds=data["uptime"])) + if data.get("uptime") is not None + else None + ) + ), + device_class=SensorDeviceClass.UPTIME, entity_category=EntityCategory.DIAGNOSTIC, - state_class=SensorStateClass.MEASUREMENT, ), ProxmoxVMSensorEntityDescription( key="vm_disk", @@ -353,12 +359,15 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = ( ProxmoxContainerSensorEntityDescription( key="container_uptime", translation_key="container_uptime", - value_fn=lambda data: data.get("uptime"), - device_class=SensorDeviceClass.DURATION, - native_unit_of_measurement=UnitOfTime.SECONDS, - suggested_unit_of_measurement=UnitOfTime.HOURS, + value_fn=( + lambda data: ( + (dt_util.utcnow() - timedelta(seconds=data["uptime"])) + if data.get("uptime") is not None + else None + ) + ), + device_class=SensorDeviceClass.UPTIME, entity_category=EntityCategory.DIAGNOSTIC, - state_class=SensorStateClass.MEASUREMENT, ), ProxmoxContainerSensorEntityDescription( key="container_disk", @@ -577,7 +586,7 @@ class ProxmoxVMSensor(ProxmoxVMEntity, SensorEntity): @property @override - def native_value(self) -> StateType: + def native_value(self) -> StateType | datetime: """Return the native value of the sensor.""" return self.entity_description.value_fn(self.vm_data) @@ -589,7 +598,7 @@ class ProxmoxContainerSensor(ProxmoxContainerEntity, SensorEntity): @property @override - def native_value(self) -> StateType: + def native_value(self) -> StateType | datetime: """Return the native value of the sensor.""" return self.entity_description.value_fn(self.container_data) diff --git a/tests/components/proxmoxve/snapshots/test_sensor.ambr b/tests/components/proxmoxve/snapshots/test_sensor.ambr index 5396a051d964..dae6576fddd0 100644 --- a/tests/components/proxmoxve/snapshots/test_sensor.ambr +++ b/tests/components/proxmoxve/snapshots/test_sensor.ambr @@ -600,9 +600,7 @@ None, ]), 'area_id': None, - 'capabilities': dict({ - : , - }), + 'capabilities': None, 'config_entry_id': , 'config_subentry_id': , 'device_class': None, @@ -620,14 +618,8 @@ 'name': None, 'object_id_base': 'Uptime', 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 2, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), }), - 'original_device_class': , + 'original_device_class': , 'original_icon': None, 'original_name': 'Uptime', 'platform': 'proxmoxve', @@ -636,23 +628,21 @@ 'supported_features': 0, 'translation_key': 'container_uptime', 'unique_id': '1234_201_container_uptime', - 'unit_of_measurement': , + 'unit_of_measurement': None, }) # --- # name: test_all_entities[sensor.ct_backup_uptime-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 'duration', + : 'uptime', : 'ct-backup Uptime', - : , - : , }), 'context': , 'entity_id': 'sensor.ct_backup_uptime', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '12.0', + 'state': '2026-05-03T00:00:00+00:00', }) # --- # name: test_all_entities[sensor.ct_nginx_cpu_usage-entry] @@ -1256,9 +1246,7 @@ None, ]), 'area_id': None, - 'capabilities': dict({ - : , - }), + 'capabilities': None, 'config_entry_id': , 'config_subentry_id': , 'device_class': None, @@ -1276,14 +1264,8 @@ 'name': None, 'object_id_base': 'Uptime', 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 2, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), }), - 'original_device_class': , + 'original_device_class': , 'original_icon': None, 'original_name': 'Uptime', 'platform': 'proxmoxve', @@ -1292,23 +1274,21 @@ 'supported_features': 0, 'translation_key': 'container_uptime', 'unique_id': '1234_200_container_uptime', - 'unit_of_measurement': , + 'unit_of_measurement': None, }) # --- # name: test_all_entities[sensor.ct_nginx_uptime-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 'duration', + : 'uptime', : 'ct-nginx Uptime', - : , - : , }), 'context': , 'entity_id': 'sensor.ct_nginx_uptime', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '12.0', + 'state': '2026-05-03T00:00:00+00:00', }) # --- # name: test_all_entities[sensor.pve1_backup_duration-entry] @@ -1900,9 +1880,7 @@ None, ]), 'area_id': None, - 'capabilities': dict({ - : , - }), + 'capabilities': None, 'config_entry_id': , 'config_subentry_id': , 'device_class': None, @@ -1920,14 +1898,8 @@ 'name': None, 'object_id_base': 'Uptime', 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 2, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), }), - 'original_device_class': , + 'original_device_class': , 'original_icon': None, 'original_name': 'Uptime', 'platform': 'proxmoxve', @@ -1936,23 +1908,21 @@ 'supported_features': 0, 'translation_key': 'node_uptime', 'unique_id': '1234_node/pve1_node_uptime', - 'unit_of_measurement': , + 'unit_of_measurement': None, }) # --- # name: test_all_entities[sensor.pve1_uptime-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 'duration', + : 'uptime', : 'pve1 Uptime', - : , - : , }), 'context': , 'entity_id': 'sensor.pve1_uptime', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '24.0', + 'state': '2026-05-02T12:00:00+00:00', }) # --- # name: test_all_entities[sensor.storage_local_available_storage-entry] @@ -3030,9 +3000,7 @@ None, ]), 'area_id': None, - 'capabilities': dict({ - : , - }), + 'capabilities': None, 'config_entry_id': , 'config_subentry_id': , 'device_class': None, @@ -3050,14 +3018,8 @@ 'name': None, 'object_id_base': 'Uptime', 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 2, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), }), - 'original_device_class': , + 'original_device_class': , 'original_icon': None, 'original_name': 'Uptime', 'platform': 'proxmoxve', @@ -3066,23 +3028,21 @@ 'supported_features': 0, 'translation_key': 'vm_uptime', 'unique_id': '1234_101_vm_uptime', - 'unit_of_measurement': , + 'unit_of_measurement': None, }) # --- # name: test_all_entities[sensor.vm_db_uptime-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 'duration', + : 'uptime', : 'vm-db Uptime', - : , - : , }), 'context': , 'entity_id': 'sensor.vm_db_uptime', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '24.0', + 'state': '2026-05-02T12:00:00+00:00', }) # --- # name: test_all_entities[sensor.vm_web_cpu_usage-entry] @@ -3686,9 +3646,7 @@ None, ]), 'area_id': None, - 'capabilities': dict({ - : , - }), + 'capabilities': None, 'config_entry_id': , 'config_subentry_id': , 'device_class': None, @@ -3706,14 +3664,8 @@ 'name': None, 'object_id_base': 'Uptime', 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 2, - }), - 'sensor.private': dict({ - 'suggested_unit_of_measurement': , - }), }), - 'original_device_class': , + 'original_device_class': , 'original_icon': None, 'original_name': 'Uptime', 'platform': 'proxmoxve', @@ -3722,22 +3674,20 @@ 'supported_features': 0, 'translation_key': 'vm_uptime', 'unique_id': '1234_100_vm_uptime', - 'unit_of_measurement': , + 'unit_of_measurement': None, }) # --- # name: test_all_entities[sensor.vm_web_uptime-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 'duration', + : 'uptime', : 'vm-web Uptime', - : , - : , }), 'context': , 'entity_id': 'sensor.vm_web_uptime', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '24.0', + 'state': '2026-05-02T12:00:00+00:00', }) # --- diff --git a/tests/components/proxmoxve/test_sensor.py b/tests/components/proxmoxve/test_sensor.py index a2109bbd0372..7d8714fff321 100644 --- a/tests/components/proxmoxve/test_sensor.py +++ b/tests/components/proxmoxve/test_sensor.py @@ -23,6 +23,7 @@ def enable_all_entities(entity_registry_enabled_by_default: None) -> None: """Make sure all entities are enabled.""" +@pytest.mark.freeze_time("2026-05-03T12:00:00+00:00") async def test_all_entities( hass: HomeAssistant, snapshot: SnapshotAssertion,