Fix temperature parsing to handle multiple SMART formats

Temperature parsing now correctly handles:
- SATA Temperature_Celsius attribute (extracts last numeric value)
- Simple "Temperature: XX Celsius" format
- "Current Temperature: XX Celsius" format
- NVMe temperature reporting

Also improved device type detection for NVMe, SSD (including 0 RPM),
and fixed serial number parsing to capture full serial with spaces.

Fixes: #2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 11:24:54 -05:00
parent 94c5c7c3b3
commit 90055bec81

View File

@@ -272,16 +272,84 @@ build_drive_map() {
fi fi
} }
#------------------------------------------------------------------------------
# get_drive_smart_info
#
# Retrieves SMART data for a given device.
#
# Args:
# $1 - Device name (e.g., sda, nvme0n1)
#
# Returns: Pipe-delimited string: TYPE|TEMP|HEALTH|MODEL|SERIAL
# TYPE: SSD, HDD, or NVMe
# TEMP: Temperature in Celsius (or "-" if unavailable)
# HEALTH: ✓ for passed, ✗ for failed
# MODEL: Drive model string
# SERIAL: Drive serial number
#------------------------------------------------------------------------------
get_drive_smart_info() { get_drive_smart_info() {
local device=$1 local device="$1"
local smart_info=$(sudo smartctl -A -i -H /dev/$device 2>/dev/null) local smart_info
local temp=$(echo "$smart_info" | grep "Temperature" | awk '{print $10}' | head -1) local temp="-"
local type=$(echo "$smart_info" | grep "Rotation Rate" | grep -q "Solid State" && echo "SSD" || echo "HDD") local type="HDD"
local health=$(echo "$smart_info" | grep "SMART overall-health" | grep -q "PASSED" && echo "✓" || echo "✗") local health="✗"
local model=$(echo "$smart_info" | grep "Device Model\|Model Number" | cut -d: -f2 | xargs) local model="-"
local serial=$(echo "$smart_info" | grep "Serial Number" | awk '{print $3}') local serial="-"
echo "$type|$temp°C|$health|$model|$serial" smart_info="$(sudo smartctl -A -i -H "/dev/$device" 2>/dev/null)"
# Temperature parsing - handles multiple formats:
# - SATA: "194 Temperature_Celsius ... 35" (value at end of line)
# - SATA: "Temperature: 42 Celsius"
# - SATA: "Current Temperature: 35 Celsius"
# - NVMe: "Temperature: 42 Celsius"
if echo "$smart_info" | grep -q "Temperature_Celsius"; then
# SMART attribute format - temperature is typically the 10th field (raw value)
# But we use the last numeric field before any parentheses for reliability
temp="$(echo "$smart_info" | grep "Temperature_Celsius" | head -1 | awk '{for(i=NF;i>0;i--) if($i ~ /^[0-9]+$/) {print $i; exit}}')"
elif echo "$smart_info" | grep -qE "^(Current )?Temperature:"; then
# Simple "Temperature: XX Celsius" format
temp="$(echo "$smart_info" | grep -E "^(Current )?Temperature:" | head -1 | awk '{print $2}')"
fi
# Device type detection - handles SSD, HDD, and NVMe
if [[ "$device" == nvme* ]]; then
type="NVMe"
elif echo "$smart_info" | grep -q "Rotation Rate"; then
if echo "$smart_info" | grep "Rotation Rate" | grep -qiE "solid state|0 rpm"; then
type="SSD"
else
type="HDD"
fi
elif echo "$smart_info" | grep -qiE "SSD|Solid State"; then
type="SSD"
fi
# Health status
if echo "$smart_info" | grep -q "SMART overall-health.*PASSED"; then
health="✓"
elif echo "$smart_info" | grep -q "SMART Health Status.*OK"; then
# NVMe format
health="✓"
fi
# Model - try multiple field names
model="$(echo "$smart_info" | grep -E "^(Device Model|Model Number|Product):" | head -1 | cut -d: -f2 | xargs)"
[[ -z "$model" ]] && model="-"
# Serial number - capture everything after the colon to handle spaces
serial="$(echo "$smart_info" | grep -E "^Serial [Nn]umber:" | head -1 | cut -d: -f2 | xargs)"
[[ -z "$serial" ]] && serial="-"
# Format temperature with unit if we have a value
local temp_display
if [[ -n "$temp" && "$temp" != "-" ]]; then
temp_display="${temp}°C"
else
temp_display="-"
fi
echo "${type}|${temp_display}|${health}|${model}|${serial}"
} }
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------