Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LHM robustness for sensors None values #507

Merged
merged 2 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 83 additions & 58 deletions library/sensors/sensors_librehardwaremonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ class Cpu(sensors.Cpu):
def percentage(interval: float) -> float:
cpu = get_hw_and_update(Hardware.HardwareType.Cpu)
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("CPU Total"):
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
"CPU Total") and sensor.Value is not None:
return float(sensor.Value)

logger.error("CPU load cannot be read")
Expand All @@ -186,19 +187,22 @@ def percentage(interval: float) -> float:
def frequency() -> float:
frequencies = []
cpu = get_hw_and_update(Hardware.HardwareType.Cpu)
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Clock:
# Keep only real core clocks, ignore effective core clocks
if "Core #" in str(sensor.Name) and "Effective" not in str(sensor.Name):
if sensor.Value:
try:
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Clock:
# Keep only real core clocks, ignore effective core clocks
if "Core #" in str(sensor.Name) and "Effective" not in str(
sensor.Name) and sensor.Value is not None:
frequencies.append(float(sensor.Value))

if frequencies:
# Take mean of all core clock as "CPU clock" (as it is done in Windows Task Manager Performance tab)
return mean(frequencies)
else:
# Frequencies reading is not supported on this CPU
return math.nan
if frequencies:
# Take mean of all core clock as "CPU clock" (as it is done in Windows Task Manager Performance tab)
return mean(frequencies)
except:
pass

# Frequencies reading is not supported on this CPU
return math.nan

@staticmethod
def load() -> Tuple[float, float, float]: # 1 / 5 / 15min avg (%):
Expand All @@ -208,22 +212,29 @@ def load() -> Tuple[float, float, float]: # 1 / 5 / 15min avg (%):
@staticmethod
def temperature() -> float:
cpu = get_hw_and_update(Hardware.HardwareType.Cpu)
# By default, the average temperature of all CPU cores will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core Average"):
return float(sensor.Value)
# If not available, the max core temperature will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core Max"):
return float(sensor.Value)
# If not available, the CPU Package temperature (usually same as max core temperature) will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("CPU Package"):
return float(sensor.Value)
# Otherwise any sensor named "Core..." will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core"):
return float(sensor.Value)
try:
# By default, the average temperature of all CPU cores will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
"Core Average") and sensor.Value is not None:
return float(sensor.Value)
# If not available, the max core temperature will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
"Core Max") and sensor.Value is not None:
return float(sensor.Value)
# If not available, the CPU Package temperature (usually same as max core temperature) will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
"CPU Package") and sensor.Value is not None:
return float(sensor.Value)
# Otherwise any sensor named "Core..." will be used
for sensor in cpu.Sensors:
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
"Core") and sensor.Value is not None:
return float(sensor.Value)
except:
pass

return math.nan

Expand All @@ -235,7 +246,7 @@ def fan_percent() -> float:
sh.Update()
for sensor in sh.Sensors:
if sensor.SensorType == Hardware.SensorType.Control and "#2" in str(
sensor.Name): # Is Motherboard #2 Fan always the CPU Fan ?
sensor.Name) and sensor.Value is not None: # Is Motherboard #2 Fan always the CPU Fan ?
return float(sensor.Value)
except:
pass
Expand Down Expand Up @@ -275,23 +286,28 @@ def stats(cls) -> Tuple[float, float, float, float]: # load (%) / used mem (%)
temp = math.nan

for sensor in gpu_to_use.Sensors:
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("GPU Core"):
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
"GPU Core") and sensor.Value is not None:
load = float(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("D3D 3D") and math.isnan(
load):
load) and sensor.Value is not None:
# Only use D3D usage if global "GPU Core" sensor is not available, because it is less
# precise and does not cover the entire GPU: https://www.hwinfo.com/forum/threads/what-is-d3d-usage.759/
load = float(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Used"):
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
"GPU Memory Used") and sensor.Value is not None:
used_mem = float(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
"D3D") and str(sensor.Name).endswith("Memory Used") and math.isnan(used_mem):
"D3D") and str(sensor.Name).endswith("Memory Used") and math.isnan(
used_mem) and sensor.Value is not None:
# Only use D3D memory usage if global "GPU Memory Used" sensor is not available, because it is less
# precise and does not cover the entire GPU: https://www.hwinfo.com/forum/threads/what-is-d3d-usage.759/
used_mem = float(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Total"):
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
"GPU Memory Total") and sensor.Value is not None:
total_mem = float(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("GPU Core"):
elif sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
"GPU Core") and sensor.Value is not None:
temp = float(sensor.Value)

return load, (used_mem / total_mem * 100.0), used_mem, temp
Expand All @@ -303,12 +319,16 @@ def fps(cls) -> int:
# GPU not supported
return -1

for sensor in gpu_to_use.Sensors:
if sensor.SensorType == Hardware.SensorType.Factor and "FPS" in str(sensor.Name):
# If a reading returns a value <= 0, returns old value instead
if int(sensor.Value) > 0:
cls.prev_fps = int(sensor.Value)
return cls.prev_fps
try:
for sensor in gpu_to_use.Sensors:
if sensor.SensorType == Hardware.SensorType.Factor and "FPS" in str(
sensor.Name) and sensor.Value is not None:
# If a reading returns a value <= 0, returns old value instead
if int(sensor.Value) > 0:
cls.prev_fps = int(sensor.Value)
return cls.prev_fps
except:
pass

# No FPS sensor for this GPU model
return -1
Expand All @@ -322,9 +342,8 @@ def fan_percent(cls) -> float:

try:
for sensor in gpu_to_use.Sensors:
if sensor.SensorType == Hardware.SensorType.Control:
if sensor.Value:
return float(sensor.Value)
if sensor.SensorType == Hardware.SensorType.Control and sensor.Value is not None:
return float(sensor.Value)
except:
pass

Expand All @@ -342,9 +361,8 @@ def frequency(cls) -> float:
for sensor in gpu_to_use.Sensors:
if sensor.SensorType == Hardware.SensorType.Clock:
# Keep only real core clocks, ignore effective core clocks
if "Core" in str(sensor.Name) and "Effective" not in str(sensor.Name):
if sensor.Value:
return float(sensor.Value)
if "Core" in str(sensor.Name) and "Effective" not in str(sensor.Name) and sensor.Value is not None:
return float(sensor.Value)
except:
pass

Expand All @@ -369,14 +387,17 @@ def swap_percent() -> float:

# Get virtual / physical memory stats
for sensor in memory.Sensors:
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Virtual Memory Used"):
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Virtual Memory Used") and sensor.Value is not None:
virtual_mem_used = int(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Used"):
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Memory Used") and sensor.Value is not None:
mem_used = int(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Virtual Memory Available"):
"Virtual Memory Available") and sensor.Value is not None:
virtual_mem_available = int(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Available"):
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Memory Available") and sensor.Value is not None:
mem_available = int(sensor.Value)

# Compute swap stats from virtual / physical memory stats
Expand All @@ -395,7 +416,8 @@ def swap_percent() -> float:
def virtual_percent() -> float:
memory = get_hw_and_update(Hardware.HardwareType.Memory)
for sensor in memory.Sensors:
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("Memory"):
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
"Memory") and sensor.Value is not None:
return float(sensor.Value)

return math.nan
Expand All @@ -404,7 +426,8 @@ def virtual_percent() -> float:
def virtual_used() -> int: # In bytes
memory = get_hw_and_update(Hardware.HardwareType.Memory)
for sensor in memory.Sensors:
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Used"):
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Memory Used") and sensor.Value is not None:
return int(sensor.Value * 1000000000.0)

return 0
Expand All @@ -413,7 +436,8 @@ def virtual_used() -> int: # In bytes
def virtual_free() -> int: # In bytes
memory = get_hw_and_update(Hardware.HardwareType.Memory)
for sensor in memory.Sensors:
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Available"):
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Memory Available") and sensor.Value is not None:
return int(sensor.Value * 1000000000.0)

return 0
Expand Down Expand Up @@ -449,16 +473,17 @@ def stats(if_name, interval) -> Tuple[
net_if = get_net_interface_and_update(if_name)
if net_if is not None:
for sensor in net_if.Sensors:
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Data Uploaded"):
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Data Uploaded") and sensor.Value is not None:
uploaded = int(sensor.Value * 1000000000.0)
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
"Data Downloaded"):
"Data Downloaded") and sensor.Value is not None:
downloaded = int(sensor.Value * 1000000000.0)
elif sensor.SensorType == Hardware.SensorType.Throughput and str(sensor.Name).startswith(
"Upload Speed"):
"Upload Speed") and sensor.Value is not None:
upload_rate = int(sensor.Value)
elif sensor.SensorType == Hardware.SensorType.Throughput and str(sensor.Name).startswith(
"Download Speed"):
"Download Speed") and sensor.Value is not None:
download_rate = int(sensor.Value)

return upload_rate, uploaded, download_rate, downloaded
Loading
Loading