Skip to content

Commit bacd047

Browse files
committed
Add same robustness for Python sensors
1 parent 1f5abca commit bacd047

File tree

2 files changed

+109
-58
lines changed

2 files changed

+109
-58
lines changed

library/sensors/sensors_librehardwaremonitor.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ class Cpu(sensors.Cpu):
176176
def percentage(interval: float) -> float:
177177
cpu = get_hw_and_update(Hardware.HardwareType.Cpu)
178178
for sensor in cpu.Sensors:
179-
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("CPU Total") and sensor.Value is not None:
179+
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
180+
"CPU Total") and sensor.Value is not None:
180181
return float(sensor.Value)
181182

182183
logger.error("CPU load cannot be read")
@@ -190,7 +191,8 @@ def frequency() -> float:
190191
for sensor in cpu.Sensors:
191192
if sensor.SensorType == Hardware.SensorType.Clock:
192193
# Keep only real core clocks, ignore effective core clocks
193-
if "Core #" in str(sensor.Name) and "Effective" not in str(sensor.Name) and sensor.Value is not None:
194+
if "Core #" in str(sensor.Name) and "Effective" not in str(
195+
sensor.Name) and sensor.Value is not None:
194196
frequencies.append(float(sensor.Value))
195197

196198
if frequencies:
@@ -213,19 +215,23 @@ def temperature() -> float:
213215
try:
214216
# By default, the average temperature of all CPU cores will be used
215217
for sensor in cpu.Sensors:
216-
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core Average") and sensor.Value is not None:
218+
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
219+
"Core Average") and sensor.Value is not None:
217220
return float(sensor.Value)
218221
# If not available, the max core temperature will be used
219222
for sensor in cpu.Sensors:
220-
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core Max") and sensor.Value is not None:
223+
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
224+
"Core Max") and sensor.Value is not None:
221225
return float(sensor.Value)
222226
# If not available, the CPU Package temperature (usually same as max core temperature) will be used
223227
for sensor in cpu.Sensors:
224-
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("CPU Package") and sensor.Value is not None:
228+
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
229+
"CPU Package") and sensor.Value is not None:
225230
return float(sensor.Value)
226231
# Otherwise any sensor named "Core..." will be used
227232
for sensor in cpu.Sensors:
228-
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("Core") and sensor.Value is not None:
233+
if sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
234+
"Core") and sensor.Value is not None:
229235
return float(sensor.Value)
230236
except:
231237
pass
@@ -280,23 +286,28 @@ def stats(cls) -> Tuple[float, float, float, float]: # load (%) / used mem (%)
280286
temp = math.nan
281287

282288
for sensor in gpu_to_use.Sensors:
283-
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("GPU Core") and sensor.Value is not None:
289+
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
290+
"GPU Core") and sensor.Value is not None:
284291
load = float(sensor.Value)
285292
elif sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("D3D 3D") and math.isnan(
286293
load) and sensor.Value is not None:
287294
# Only use D3D usage if global "GPU Core" sensor is not available, because it is less
288295
# precise and does not cover the entire GPU: https://www.hwinfo.com/forum/threads/what-is-d3d-usage.759/
289296
load = float(sensor.Value)
290-
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Used") and sensor.Value is not None:
297+
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
298+
"GPU Memory Used") and sensor.Value is not None:
291299
used_mem = float(sensor.Value)
292300
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
293-
"D3D") and str(sensor.Name).endswith("Memory Used") and math.isnan(used_mem) and sensor.Value is not None:
301+
"D3D") and str(sensor.Name).endswith("Memory Used") and math.isnan(
302+
used_mem) and sensor.Value is not None:
294303
# Only use D3D memory usage if global "GPU Memory Used" sensor is not available, because it is less
295304
# precise and does not cover the entire GPU: https://www.hwinfo.com/forum/threads/what-is-d3d-usage.759/
296305
used_mem = float(sensor.Value)
297-
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith("GPU Memory Total") and sensor.Value is not None:
306+
elif sensor.SensorType == Hardware.SensorType.SmallData and str(sensor.Name).startswith(
307+
"GPU Memory Total") and sensor.Value is not None:
298308
total_mem = float(sensor.Value)
299-
elif sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith("GPU Core") and sensor.Value is not None:
309+
elif sensor.SensorType == Hardware.SensorType.Temperature and str(sensor.Name).startswith(
310+
"GPU Core") and sensor.Value is not None:
300311
temp = float(sensor.Value)
301312

302313
return load, (used_mem / total_mem * 100.0), used_mem, temp
@@ -310,7 +321,8 @@ def fps(cls) -> int:
310321

311322
try:
312323
for sensor in gpu_to_use.Sensors:
313-
if sensor.SensorType == Hardware.SensorType.Factor and "FPS" in str(sensor.Name) and sensor.Value is not None:
324+
if sensor.SensorType == Hardware.SensorType.Factor and "FPS" in str(
325+
sensor.Name) and sensor.Value is not None:
314326
# If a reading returns a value <= 0, returns old value instead
315327
if int(sensor.Value) > 0:
316328
cls.prev_fps = int(sensor.Value)
@@ -375,14 +387,17 @@ def swap_percent() -> float:
375387

376388
# Get virtual / physical memory stats
377389
for sensor in memory.Sensors:
378-
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Virtual Memory Used") and sensor.Value is not None:
390+
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
391+
"Virtual Memory Used") and sensor.Value is not None:
379392
virtual_mem_used = int(sensor.Value)
380-
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Used") and sensor.Value is not None:
393+
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
394+
"Memory Used") and sensor.Value is not None:
381395
mem_used = int(sensor.Value)
382396
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
383397
"Virtual Memory Available") and sensor.Value is not None:
384398
virtual_mem_available = int(sensor.Value)
385-
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Available") and sensor.Value is not None:
399+
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
400+
"Memory Available") and sensor.Value is not None:
386401
mem_available = int(sensor.Value)
387402

388403
# Compute swap stats from virtual / physical memory stats
@@ -401,7 +416,8 @@ def swap_percent() -> float:
401416
def virtual_percent() -> float:
402417
memory = get_hw_and_update(Hardware.HardwareType.Memory)
403418
for sensor in memory.Sensors:
404-
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith("Memory") and sensor.Value is not None:
419+
if sensor.SensorType == Hardware.SensorType.Load and str(sensor.Name).startswith(
420+
"Memory") and sensor.Value is not None:
405421
return float(sensor.Value)
406422

407423
return math.nan
@@ -410,7 +426,8 @@ def virtual_percent() -> float:
410426
def virtual_used() -> int: # In bytes
411427
memory = get_hw_and_update(Hardware.HardwareType.Memory)
412428
for sensor in memory.Sensors:
413-
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Used") and sensor.Value is not None:
429+
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
430+
"Memory Used") and sensor.Value is not None:
414431
return int(sensor.Value * 1000000000.0)
415432

416433
return 0
@@ -419,7 +436,8 @@ def virtual_used() -> int: # In bytes
419436
def virtual_free() -> int: # In bytes
420437
memory = get_hw_and_update(Hardware.HardwareType.Memory)
421438
for sensor in memory.Sensors:
422-
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Memory Available") and sensor.Value is not None:
439+
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
440+
"Memory Available") and sensor.Value is not None:
423441
return int(sensor.Value * 1000000000.0)
424442

425443
return 0
@@ -455,7 +473,8 @@ def stats(if_name, interval) -> Tuple[
455473
net_if = get_net_interface_and_update(if_name)
456474
if net_if is not None:
457475
for sensor in net_if.Sensors:
458-
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith("Data Uploaded") and sensor.Value is not None:
476+
if sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
477+
"Data Uploaded") and sensor.Value is not None:
459478
uploaded = int(sensor.Value * 1000000000.0)
460479
elif sensor.SensorType == Hardware.SensorType.Data and str(sensor.Name).startswith(
461480
"Data Downloaded") and sensor.Value is not None:

library/sensors/sensors_python.py

Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,24 @@ def sensors_fans_percent():
9898
class Cpu(sensors.Cpu):
9999
@staticmethod
100100
def percentage(interval: float) -> float:
101-
return psutil.cpu_percent(interval=interval)
101+
try:
102+
return psutil.cpu_percent(interval=interval)
103+
except:
104+
return math.nan
102105

103106
@staticmethod
104107
def frequency() -> float:
105-
return psutil.cpu_freq().current
108+
try:
109+
return psutil.cpu_freq().current
110+
except:
111+
return math.nan
106112

107113
@staticmethod
108114
def load() -> Tuple[float, float, float]: # 1 / 5 / 15min avg (%):
109-
return psutil.getloadavg()
115+
try:
116+
return psutil.getloadavg()
117+
except:
118+
return math.nan, math.nan, math.nan
110119

111120
@staticmethod
112121
def temperature() -> float:
@@ -369,65 +378,88 @@ def is_available() -> bool:
369378
class Memory(sensors.Memory):
370379
@staticmethod
371380
def swap_percent() -> float:
372-
return psutil.swap_memory().percent
381+
try:
382+
return psutil.swap_memory().percent
383+
except:
384+
return math.nan
373385

374386
@staticmethod
375387
def virtual_percent() -> float:
376-
return psutil.virtual_memory().percent
388+
try:
389+
return psutil.virtual_memory().percent
390+
except:
391+
return math.nan
377392

378393
@staticmethod
379394
def virtual_used() -> int: # In bytes
380-
# Do not use psutil.virtual_memory().used: from https://psutil.readthedocs.io/en/latest/#memory
381-
# "It is calculated differently depending on the platform and designed for informational purposes only"
382-
return psutil.virtual_memory().total - psutil.virtual_memory().available
395+
try:
396+
# Do not use psutil.virtual_memory().used: from https://psutil.readthedocs.io/en/latest/#memory
397+
# "It is calculated differently depending on the platform and designed for informational purposes only"
398+
return psutil.virtual_memory().total - psutil.virtual_memory().available
399+
except:
400+
return -1
383401

384402
@staticmethod
385403
def virtual_free() -> int: # In bytes
386-
# Do not use psutil.virtual_memory().free: from https://psutil.readthedocs.io/en/latest/#memory
387-
# "note that this doesn’t reflect the actual memory available (use available instead)."
388-
return psutil.virtual_memory().available
389-
404+
try:
405+
# Do not use psutil.virtual_memory().free: from https://psutil.readthedocs.io/en/latest/#memory
406+
# "note that this doesn’t reflect the actual memory available (use available instead)."
407+
return psutil.virtual_memory().available
408+
except:
409+
return -1
390410

391411
class Disk(sensors.Disk):
392412
@staticmethod
393413
def disk_usage_percent() -> float:
394-
return psutil.disk_usage("/").percent
414+
try:
415+
return psutil.disk_usage("/").percent
416+
except:
417+
return math.nan
395418

396419
@staticmethod
397420
def disk_used() -> int: # In bytes
398-
return psutil.disk_usage("/").used
421+
try:
422+
return psutil.disk_usage("/").used
423+
except:
424+
return -1
399425

400426
@staticmethod
401427
def disk_free() -> int: # In bytes
402-
return psutil.disk_usage("/").free
428+
try:
429+
return psutil.disk_usage("/").free
430+
except:
431+
return -1
403432

404433

405434
class Net(sensors.Net):
406435
@staticmethod
407436
def stats(if_name, interval) -> Tuple[
408437
int, int, int, int]: # up rate (B/s), uploaded (B), dl rate (B/s), downloaded (B)
409438
global PNIC_BEFORE
410-
# Get current counters
411-
pnic_after = psutil.net_io_counters(pernic=True)
412-
413-
upload_rate = 0
414-
uploaded = 0
415-
download_rate = 0
416-
downloaded = 0
417-
418-
if if_name != "":
419-
if if_name in pnic_after:
420-
try:
421-
upload_rate = (pnic_after[if_name].bytes_sent - PNIC_BEFORE[if_name].bytes_sent) / interval
422-
uploaded = pnic_after[if_name].bytes_sent
423-
download_rate = (pnic_after[if_name].bytes_recv - PNIC_BEFORE[if_name].bytes_recv) / interval
424-
downloaded = pnic_after[if_name].bytes_recv
425-
except:
426-
# Interface might not be in PNIC_BEFORE for now
427-
pass
428-
429-
PNIC_BEFORE.update({if_name: pnic_after[if_name]})
430-
else:
431-
logger.warning("Network interface '%s' not found. Check names in config.yaml." % if_name)
432-
433-
return upload_rate, uploaded, download_rate, downloaded
439+
try:
440+
# Get current counters
441+
pnic_after = psutil.net_io_counters(pernic=True)
442+
443+
upload_rate = 0
444+
uploaded = 0
445+
download_rate = 0
446+
downloaded = 0
447+
448+
if if_name != "":
449+
if if_name in pnic_after:
450+
try:
451+
upload_rate = (pnic_after[if_name].bytes_sent - PNIC_BEFORE[if_name].bytes_sent) / interval
452+
uploaded = pnic_after[if_name].bytes_sent
453+
download_rate = (pnic_after[if_name].bytes_recv - PNIC_BEFORE[if_name].bytes_recv) / interval
454+
downloaded = pnic_after[if_name].bytes_recv
455+
except:
456+
# Interface might not be in PNIC_BEFORE for now
457+
pass
458+
459+
PNIC_BEFORE.update({if_name: pnic_after[if_name]})
460+
else:
461+
logger.warning("Network interface '%s' not found. Check names in config.yaml." % if_name)
462+
463+
return upload_rate, uploaded, download_rate, downloaded
464+
except:
465+
return -1, -1, -1, -1

0 commit comments

Comments
 (0)