feat: improve SMART temperature parsing with multi-command fallback and enhanced line-based extraction logic

Replace regex pattern matching with extract() helper that iterates through output lines, filters for temperature/airflow keywords, and extracts values using explicit unit patterns (°C/Celsius/degrees C) with 0-150 range validation or fallback to last plausible number in line. Add smartctl -x/-x -d sat commands to fallback chain after -A/-A -d sat attempts with early return on first successful
This commit is contained in:
2026-08-16 20:08:29 +02:00
parent 310b36317e
commit 9373e93e7f
+23 -11
View File
@@ -357,17 +357,29 @@ def smart_temperature(device):
if not SMART_ENABLED or not shutil.which("smartctl"): if not SMART_ENABLED or not shutil.which("smartctl"):
return "Nicht verfügbar" return "Nicht verfügbar"
smart_device = device.replace("/dev/", f"{HOST_DEVICE_PATH.rstrip('/')}/", 1) smart_device = device.replace("/dev/", f"{HOST_DEVICE_PATH.rstrip('/')}/", 1)
output, error = _read_command(["smartctl", "-A", smart_device], timeout=6, warn_on_nonzero=False) def extract(output):
if not output: for line in output.splitlines():
output, error = _read_command(["smartctl", "-A", "-d", "sat", smart_device], timeout=6, warn_on_nonzero=False) if not re.search(r"temperature|airflow", line, re.IGNORECASE):
patterns = ( continue
r"(?:Temperature_Celsius|Airflow_Temperature_Cel|Drive_Temperature|Current Drive Temperature)\s+.*?\s(\d{1,3})(?:\s*°?C)?\s*$", explicit = re.search(r"(\d{1,3})\s*(?:°\s*C|Celsius|degrees?\s*C)\b", line, re.IGNORECASE)
r"^\s*Temperature:\s*(\d{1,3})\s*(?:C|°C|Celsius)?\s*$", if explicit and 0 < int(explicit.group(1)) < 150:
) return f"{int(explicit.group(1))} °C"
for pattern in patterns: numbers = [int(value) for value in re.findall(r"\b\d{1,3}\b", line)]
match = re.search(pattern, output, re.IGNORECASE | re.MULTILINE) plausible = [value for value in numbers if 0 < value < 150]
if match: if plausible:
return f"{int(match.group(1))} °C" return f"{plausible[-1]} °C"
return None
for command in (
["smartctl", "-A", smart_device],
["smartctl", "-A", "-d", "sat", smart_device],
["smartctl", "-x", smart_device],
["smartctl", "-x", "-d", "sat", smart_device],
):
output, _ = _read_command(command, timeout=6, warn_on_nonzero=False)
temperature = extract(output)
if temperature:
return temperature
return "Nicht verfügbar" return "Nicht verfügbar"
def raid_status(): def raid_status():