From e4fbe539aafb8c8029ca3064fc4b68847e4b59eb Mon Sep 17 00:00:00 2001 From: fhoekstra <32362869+fhoekstra@users.noreply.github.com> Date: Sun, 7 Apr 2024 15:05:22 +0200 Subject: [PATCH] Add GPU sensor to Glances (#106322) * feat: add GPU sensor to Glances * Add translations to Glances GPU sensor * Fix translations of GPU processor and memory usage * PR feedback: move icons to icons.json thanks to @wittypluck * Update glances snapshot with added GPU * Remove JSON trailing comma Co-authored-by: Joost Lekkerkerker * Limit precision of Glance GPU mem usage sensor Co-authored-by: Joost Lekkerkerker * Clean up outdated snapshots --------- Co-authored-by: Joost Lekkerkerker --- homeassistant/components/glances/icons.json | 6 + homeassistant/components/glances/sensor.py | 32 ++- homeassistant/components/glances/strings.json | 6 + tests/components/glances/__init__.py | 8 + .../glances/snapshots/test_sensor.ambr | 204 ++++++++++++++++++ 5 files changed, 255 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/glances/icons.json b/homeassistant/components/glances/icons.json index 92ef28ad325..9f3e00540de 100644 --- a/homeassistant/components/glances/icons.json +++ b/homeassistant/components/glances/icons.json @@ -54,6 +54,12 @@ }, "uptime": { "default": "mdi:clock-time-eight-outline" + }, + "gpu_processor_usage": { + "default": "mdi:expansion-card" + }, + "gpu_memory_usage": { + "default": "mdi:memory" } } } diff --git a/homeassistant/components/glances/sensor.py b/homeassistant/components/glances/sensor.py index fc83d297645..80671c0642e 100644 --- a/homeassistant/components/glances/sensor.py +++ b/homeassistant/components/glances/sensor.py @@ -235,6 +235,36 @@ SENSOR_TYPES = { translation_key="uptime", device_class=SensorDeviceClass.TIMESTAMP, ), + ("gpu", "mem"): GlancesSensorEntityDescription( + key="mem", + type="gpu", + translation_key="gpu_memory_usage", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + ("gpu", "proc"): GlancesSensorEntityDescription( + key="proc", + type="gpu", + translation_key="gpu_processor_usage", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=1, + ), + ("gpu", "temperature"): GlancesSensorEntityDescription( + key="temperature", + type="gpu", + translation_key="temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + ("gpu", "fan_speed"): GlancesSensorEntityDescription( + key="fan_speed", + type="gpu", + translation_key="fan_speed", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), } @@ -249,7 +279,7 @@ async def async_setup_entry( entities: list[GlancesSensor] = [] for sensor_type, sensors in coordinator.data.items(): - if sensor_type in ["fs", "diskio", "sensors", "raid"]: + if sensor_type in ["fs", "diskio", "sensors", "raid", "gpu"]: entities.extend( GlancesSensor( coordinator, diff --git a/homeassistant/components/glances/strings.json b/homeassistant/components/glances/strings.json index e2ef185727c..208d14563df 100644 --- a/homeassistant/components/glances/strings.json +++ b/homeassistant/components/glances/strings.json @@ -109,6 +109,12 @@ }, "uptime": { "name": "Uptime" + }, + "gpu_memory_usage": { + "name": "{sensor_label} memory usage" + }, + "gpu_processor_usage": { + "name": "{sensor_label} processor usage" } } }, diff --git a/tests/components/glances/__init__.py b/tests/components/glances/__init__.py index c7f2657fb37..6fbfc73b7be 100644 --- a/tests/components/glances/__init__.py +++ b/tests/components/glances/__init__.py @@ -215,4 +215,12 @@ HA_SENSOR_DATA: dict[str, Any] = { }, }, "uptime": "3 days, 10:25:20", + "gpu": { + "NVIDIA GeForce RTX 3080 (GPU 0)": { + "temperature": 51, + "mem": 8.41064453125, + "proc": 26, + "fan_speed": 0, + } + }, } diff --git a/tests/components/glances/snapshots/test_sensor.ambr b/tests/components/glances/snapshots/test_sensor.ambr index d6cccdab4ee..64ea8dd1052 100644 --- a/tests/components/glances/snapshots/test_sensor.ambr +++ b/tests/components/glances/snapshots/test_sensor.ambr @@ -802,6 +802,210 @@ 'state': 'unavailable', }) # --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_fan_speed-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_fan_speed', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'NVIDIA GeForce RTX 3080 (GPU 0) fan speed', + 'platform': 'glances', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fan_speed', + 'unique_id': 'test-NVIDIA GeForce RTX 3080 (GPU 0)-fan_speed', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_fan_speed-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '0.0.0.0 NVIDIA GeForce RTX 3080 (GPU 0) fan speed', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_fan_speed', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_memory_usage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_memory_usage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'NVIDIA GeForce RTX 3080 (GPU 0) memory usage', + 'platform': 'glances', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'gpu_memory_usage', + 'unique_id': 'test-NVIDIA GeForce RTX 3080 (GPU 0)-mem', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_memory_usage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '0.0.0.0 NVIDIA GeForce RTX 3080 (GPU 0) memory usage', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_memory_usage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '8.41064453125', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_processor_usage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_processor_usage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'NVIDIA GeForce RTX 3080 (GPU 0) processor usage', + 'platform': 'glances', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'gpu_processor_usage', + 'unique_id': 'test-NVIDIA GeForce RTX 3080 (GPU 0)-proc', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_processor_usage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '0.0.0.0 NVIDIA GeForce RTX 3080 (GPU 0) processor usage', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_processor_usage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '26', + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'NVIDIA GeForce RTX 3080 (GPU 0) temperature', + 'platform': 'glances', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'temperature', + 'unique_id': 'test-NVIDIA GeForce RTX 3080 (GPU 0)-temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor_states[sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': '0.0.0.0 NVIDIA GeForce RTX 3080 (GPU 0) temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.0_0_0_0_nvidia_geforce_rtx_3080_gpu_0_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51', + }) +# --- # name: test_sensor_states[sensor.0_0_0_0_nvme0n1_disk_read-entry] EntityRegistryEntrySnapshot({ 'aliases': set({