mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-10-03 16:46:18 +00:00
Update flask_server.py
This commit is contained in:
@@ -469,57 +469,131 @@ def get_smart_data(disk_name):
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to get SMART data using smartctl
|
# Try to get SMART data using smartctl with JSON output for better parsing
|
||||||
result = subprocess.run(['smartctl', '-a', f'/dev/{disk_name}'],
|
result = subprocess.run(['smartctl', '-a', '-j', f'/dev/{disk_name}'],
|
||||||
capture_output=True, text=True, timeout=10)
|
capture_output=True, text=True, timeout=10)
|
||||||
|
|
||||||
if result.returncode in [0, 4]: # 0 = success, 4 = some SMART values exceeded threshold
|
if result.returncode in [0, 4]: # 0 = success, 4 = some SMART values exceeded threshold
|
||||||
output = result.stdout
|
try:
|
||||||
|
# Try JSON parsing first (newer smartctl versions)
|
||||||
# Parse SMART status
|
data = json.loads(result.stdout)
|
||||||
if 'SMART overall-health self-assessment test result: PASSED' in output:
|
|
||||||
smart_data['smart_status'] = 'passed'
|
|
||||||
smart_data['health'] = 'healthy'
|
|
||||||
elif 'SMART overall-health self-assessment test result: FAILED' in output:
|
|
||||||
smart_data['smart_status'] = 'failed'
|
|
||||||
smart_data['health'] = 'critical'
|
|
||||||
|
|
||||||
# Parse temperature
|
|
||||||
for line in output.split('\n'):
|
|
||||||
if 'Temperature_Celsius' in line or 'Temperature' in line:
|
|
||||||
parts = line.split()
|
|
||||||
for i, part in enumerate(parts):
|
|
||||||
if part.isdigit() and int(part) > 0 and int(part) < 100:
|
|
||||||
smart_data['temperature'] = int(part)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Parse power on hours
|
# Get model and serial
|
||||||
if 'Power_On_Hours' in line:
|
if 'model_name' in data:
|
||||||
parts = line.split()
|
smart_data['model'] = data['model_name']
|
||||||
for part in parts:
|
elif 'model_family' in data:
|
||||||
if part.isdigit() and int(part) > 0:
|
smart_data['model'] = data['model_family']
|
||||||
smart_data['power_on_hours'] = int(part)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Parse model
|
if 'serial_number' in data:
|
||||||
if 'Device Model:' in line or 'Model Number:' in line:
|
smart_data['serial'] = data['serial_number']
|
||||||
smart_data['model'] = line.split(':', 1)[1].strip()
|
|
||||||
|
|
||||||
# Parse serial
|
# Get SMART status
|
||||||
if 'Serial Number:' in line or 'Serial number:' in line:
|
if 'smart_status' in data and 'passed' in data['smart_status']:
|
||||||
smart_data['serial'] = line.split(':', 1)[1].strip()
|
smart_data['smart_status'] = 'passed' if data['smart_status']['passed'] else 'failed'
|
||||||
|
smart_data['health'] = 'healthy' if data['smart_status']['passed'] else 'critical'
|
||||||
# Determine health based on temperature and SMART status
|
|
||||||
if smart_data['temperature'] > 0:
|
# Get temperature
|
||||||
if smart_data['temperature'] > 60:
|
if 'temperature' in data and 'current' in data['temperature']:
|
||||||
smart_data['health'] = 'warning'
|
smart_data['temperature'] = data['temperature']['current']
|
||||||
elif smart_data['temperature'] > 70:
|
|
||||||
|
# Get power on hours from SMART attributes
|
||||||
|
if 'ata_smart_attributes' in data and 'table' in data['ata_smart_attributes']:
|
||||||
|
for attr in data['ata_smart_attributes']['table']:
|
||||||
|
if attr['id'] == 9: # Power_On_Hours
|
||||||
|
smart_data['power_on_hours'] = attr['raw']['value']
|
||||||
|
elif attr['id'] == 194 and smart_data['temperature'] == 0: # Temperature_Celsius
|
||||||
|
smart_data['temperature'] = attr['raw']['value']
|
||||||
|
|
||||||
|
# For NVMe drives
|
||||||
|
if 'nvme_smart_health_information_log' in data:
|
||||||
|
nvme_data = data['nvme_smart_health_information_log']
|
||||||
|
if 'temperature' in nvme_data:
|
||||||
|
smart_data['temperature'] = nvme_data['temperature']
|
||||||
|
if 'power_on_hours' in nvme_data:
|
||||||
|
smart_data['power_on_hours'] = nvme_data['power_on_hours']
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
# Fallback to text parsing if JSON not available
|
||||||
|
output = result.stdout
|
||||||
|
|
||||||
|
# Parse SMART status
|
||||||
|
if 'SMART overall-health self-assessment test result: PASSED' in output:
|
||||||
|
smart_data['smart_status'] = 'passed'
|
||||||
|
smart_data['health'] = 'healthy'
|
||||||
|
elif 'SMART Health Status: OK' in output: # NVMe
|
||||||
|
smart_data['smart_status'] = 'passed'
|
||||||
|
smart_data['health'] = 'healthy'
|
||||||
|
elif 'SMART overall-health self-assessment test result: FAILED' in output:
|
||||||
|
smart_data['smart_status'] = 'failed'
|
||||||
smart_data['health'] = 'critical'
|
smart_data['health'] = 'critical'
|
||||||
|
|
||||||
|
# Parse model and serial
|
||||||
|
for line in output.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if line.startswith('Device Model:') or line.startswith('Model Number:'):
|
||||||
|
smart_data['model'] = line.split(':', 1)[1].strip()
|
||||||
|
elif line.startswith('Serial Number:') or line.startswith('Serial number:'):
|
||||||
|
smart_data['serial'] = line.split(':', 1)[1].strip()
|
||||||
|
elif line.startswith('Model Family:') and smart_data['model'] == 'Unknown':
|
||||||
|
smart_data['model'] = line.split(':', 1)[1].strip()
|
||||||
|
|
||||||
|
# Parse SMART attributes table
|
||||||
|
in_attributes = False
|
||||||
|
for line in output.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if 'ID# ATTRIBUTE_NAME' in line:
|
||||||
|
in_attributes = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if in_attributes and line:
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 10:
|
||||||
|
attr_id = parts[0]
|
||||||
|
attr_name = parts[1]
|
||||||
|
raw_value = parts[9]
|
||||||
|
|
||||||
|
# Power On Hours (attribute 9)
|
||||||
|
if attr_id == '9' and 'Power_On_Hours' in attr_name:
|
||||||
|
try:
|
||||||
|
smart_data['power_on_hours'] = int(raw_value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Temperature (attribute 194)
|
||||||
|
elif attr_id == '194' and 'Temperature' in attr_name:
|
||||||
|
try:
|
||||||
|
# Raw value might be like "32 (Min/Max 18/45)"
|
||||||
|
temp_str = raw_value.split()[0]
|
||||||
|
smart_data['temperature'] = int(temp_str)
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# For NVMe drives, look for temperature in different format
|
||||||
|
if smart_data['temperature'] == 0:
|
||||||
|
for line in output.split('\n'):
|
||||||
|
if 'Temperature:' in line:
|
||||||
|
try:
|
||||||
|
# Format: "Temperature: 45 Celsius"
|
||||||
|
temp_str = line.split(':')[1].strip().split()[0]
|
||||||
|
smart_data['temperature'] = int(temp_str)
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Determine health based on temperature
|
||||||
|
if smart_data['temperature'] > 0:
|
||||||
|
if smart_data['temperature'] >= 70:
|
||||||
|
smart_data['health'] = 'critical'
|
||||||
|
elif smart_data['temperature'] >= 60:
|
||||||
|
smart_data['health'] = 'warning'
|
||||||
elif smart_data['smart_status'] == 'passed':
|
elif smart_data['smart_status'] == 'passed':
|
||||||
smart_data['health'] = 'healthy'
|
smart_data['health'] = 'healthy'
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"smartctl not found - install smartmontools package")
|
print(f"smartctl not found - install smartmontools package")
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print(f"Timeout getting SMART data for {disk_name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting SMART data for {disk_name}: {e}")
|
print(f"Error getting SMART data for {disk_name}: {e}")
|
||||||
|
|
||||||
@@ -530,7 +604,7 @@ def get_network_info():
|
|||||||
try:
|
try:
|
||||||
network_data = {
|
network_data = {
|
||||||
'interfaces': [],
|
'interfaces': [],
|
||||||
'traffic': {'incoming': 0, 'outgoing': 0}
|
'traffic': {'bytes_sent': 0, 'bytes_recv': 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get network interfaces
|
# Get network interfaces
|
||||||
|
Reference in New Issue
Block a user