From 874ab093d56c5a495def83dfa9db60545f052034 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Mon, 6 Oct 2025 16:40:14 +0200 Subject: [PATCH] Update AppImage --- AppImage/components/hardware.tsx | 376 ++++++++++++++++++----------- AppImage/scripts/build_appimage.sh | 11 - AppImage/scripts/flask_server.py | 108 +++++---- AppImage/types/hardware.ts | 11 + 4 files changed, 299 insertions(+), 207 deletions(-) diff --git a/AppImage/components/hardware.tsx b/AppImage/components/hardware.tsx index 4e7ee1c..10d3afe 100644 --- a/AppImage/components/hardware.tsx +++ b/AppImage/components/hardware.tsx @@ -14,6 +14,7 @@ import { FanIcon, PowerIcon, Battery, + Cpu, } from "lucide-react" import useSWR from "swr" import { useState } from "react" @@ -45,6 +46,115 @@ export default function Hardware() { return (
+ {/* CPU & Motherboard Info */} + {(hardwareData?.cpu || hardwareData?.motherboard) && ( + +
+ +

System Information

+
+ +
+ {/* CPU Info */} + {hardwareData?.cpu && Object.keys(hardwareData.cpu).length > 0 && ( +
+

Processor

+
+ {hardwareData.cpu.model && ( +
+ Model + {hardwareData.cpu.model} +
+ )} + {hardwareData.cpu.sockets && ( +
+ Sockets + {hardwareData.cpu.sockets} +
+ )} + {hardwareData.cpu.cores_per_socket && ( +
+ Cores per Socket + {hardwareData.cpu.cores_per_socket} +
+ )} + {hardwareData.cpu.total_threads && ( +
+ Total Threads + {hardwareData.cpu.total_threads} +
+ )} + {hardwareData.cpu.current_mhz && ( +
+ Current Speed + {hardwareData.cpu.current_mhz.toFixed(0)} MHz +
+ )} + {hardwareData.cpu.max_mhz && ( +
+ Max Speed + {hardwareData.cpu.max_mhz.toFixed(0)} MHz +
+ )} +
+
+ )} + + {/* Motherboard Info */} + {hardwareData?.motherboard && Object.keys(hardwareData.motherboard).length > 0 && ( +
+

Motherboard

+
+ {hardwareData.motherboard.manufacturer && ( +
+ Manufacturer + {hardwareData.motherboard.manufacturer} +
+ )} + {hardwareData.motherboard.model && ( +
+ Model + {hardwareData.motherboard.model} +
+ )} + {hardwareData.motherboard.version && ( +
+ Version + {hardwareData.motherboard.version} +
+ )} + {hardwareData.motherboard.bios && ( + <> +
+ BIOS +
+ {hardwareData.motherboard.bios.vendor && ( +
+ Vendor + {hardwareData.motherboard.bios.vendor} +
+ )} + {hardwareData.motherboard.bios.version && ( +
+ Version + {hardwareData.motherboard.bios.version} +
+ )} + {hardwareData.motherboard.bios.date && ( +
+ Date + {hardwareData.motherboard.bios.date} +
+ )} + + )} +
+
+ )} +
+
+ )} + {/* Thermal Monitoring */} {hardwareData?.temperatures && hardwareData.temperatures.length > 0 && ( @@ -81,87 +191,6 @@ export default function Hardware() { )} - {hardwareData?.power_meter && ( - -
- -

Power Consumption

-
- -
-
-
-

{hardwareData.power_meter.name}

- {hardwareData.power_meter.adapter && ( -

{hardwareData.power_meter.adapter}

- )} -
-
-

{hardwareData.power_meter.watts.toFixed(1)} W

-

Current Draw

-
-
-
-
- )} - - {/* Storage Summary */} - {hardwareData?.storage_devices && hardwareData.storage_devices.length > 0 && ( - -
- -

Storage Summary

- - {hardwareData.storage_devices.length} devices - -
- -
- {hardwareData.storage_devices.map((device, index) => ( -
-
- {device.name} - {device.type} -
- {device.size &&

{device.size}

} - {device.model &&

{device.model}

} -
- ))} -
-
- )} - - {/* Network Summary */} - {hardwareData?.pci_devices && - hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length > 0 && ( - -
- -

Network Summary

- - {hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length} interfaces - -
- -
- {hardwareData.pci_devices - .filter((d) => d.type.toLowerCase().includes("network")) - .map((device, index) => ( -
-
- {device.device} - Ethernet -
-

{device.vendor}

-
- ))} -
-

- For detailed network information, see the Network section -

-
- )} - {/* PCI Devices */} {hardwareData?.pci_devices && hardwareData.pci_devices.length > 0 && ( @@ -229,7 +258,7 @@ export default function Hardware() { {device.driver && (
Driver - {device.driver} + {device.driver}
)} @@ -239,40 +268,6 @@ export default function Hardware() { {device.kernel_module}
)} - - {device.irq && ( -
- IRQ - {device.irq} -
- )} - - {device.memory_address && ( -
- Memory Address - {device.memory_address} -
- )} - - {device.link_speed && ( -
- Link Speed - {device.link_speed} -
- )} - - {device.capabilities && device.capabilities.length > 0 && ( -
- Capabilities -
- {device.capabilities.map((cap, idx) => ( - - {cap} - - ))} -
-
- )} )} @@ -282,6 +277,31 @@ export default function Hardware() { )} + {/* Power Consumption */} + {hardwareData?.power_meter && ( + +
+ +

Power Consumption

+
+ +
+
+
+

{hardwareData.power_meter.name}

+ {hardwareData.power_meter.adapter && ( +

{hardwareData.power_meter.adapter}

+ )} +
+
+

{hardwareData.power_meter.watts.toFixed(1)} W

+

Current Draw

+
+
+
+
+ )} + {/* Fans */} {hardwareData?.fans && hardwareData.fans.length > 0 && ( @@ -294,17 +314,22 @@ export default function Hardware() {
- {hardwareData.fans.map((fan, index) => ( -
-
- {fan.name} - - {fan.speed.toFixed(1)} {fan.unit} - + {hardwareData.fans.map((fan, index) => { + const maxRPM = 5000 + const percentage = Math.min((fan.speed / maxRPM) * 100, 100) + + return ( +
+
+ {fan.name} + + {fan.speed.toFixed(0)} {fan.unit} + +
+
- -
- ))} + ) + })}
)} @@ -325,7 +350,9 @@ export default function Hardware() {
{psu.name} - {psu.status && {psu.status}} + {psu.status && ( + {psu.status} + )}

{psu.watts} W

Current Output

@@ -335,8 +362,8 @@ export default function Hardware() { )} - {/* UPS */} - {hardwareData?.ups && ( + {/* UPS - Solo mostrar si hay datos */} + {hardwareData?.ups && Object.keys(hardwareData.ups).length > 0 && (
@@ -346,51 +373,47 @@ export default function Hardware() {
- {hardwareData.ups.name} + {hardwareData.ups.model || "UPS"} {hardwareData.ups.status}
- {hardwareData.ups.battery_charge !== undefined && ( + {hardwareData.ups.battery_charge && (
Battery Charge - {hardwareData.ups.battery_charge}% + {hardwareData.ups.battery_charge}
- +
)} - {hardwareData.ups.load !== undefined && ( + {hardwareData.ups.load_percent && (
Load - {hardwareData.ups.load}% + {hardwareData.ups.load_percent}
- +
)} - {hardwareData.ups.battery_runtime !== undefined && ( + {hardwareData.ups.time_left && (
Runtime -

{Math.floor(hardwareData.ups.battery_runtime / 60)} min

+

{hardwareData.ups.time_left}

)} - {hardwareData.ups.input_voltage !== undefined && ( + {hardwareData.ups.line_voltage && (
Input Voltage -

{hardwareData.ups.input_voltage} V

-
- )} - - {hardwareData.ups.output_voltage !== undefined && ( -
- Output Voltage -

{hardwareData.ups.output_voltage} V

+

{hardwareData.ups.line_voltage}

)}
@@ -398,6 +421,65 @@ export default function Hardware() {
)} + + {/* Network Summary */} + {hardwareData?.pci_devices && + hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length > 0 && ( + +
+ +

Network Summary

+ + {hardwareData.pci_devices.filter((d) => d.type.toLowerCase().includes("network")).length} interfaces + +
+ +
+ {hardwareData.pci_devices + .filter((d) => d.type.toLowerCase().includes("network")) + .map((device, index) => ( +
+
+ {device.device} + Ethernet +
+

{device.vendor}

+
+ ))} +
+

+ For detailed network information, see the Network section +

+
+ )} + + {/* Storage Summary */} + {hardwareData?.storage_devices && hardwareData.storage_devices.length > 0 && ( + +
+ +

Storage Summary

+ + {hardwareData.storage_devices.length} devices + +
+ +
+ {hardwareData.storage_devices.map((device, index) => ( +
+
+ {device.name} + + {device.type} + +
+ {device.size &&

{device.size}

} + {device.model &&

{device.model}

} +
+ ))} +
+
+ )}
) } diff --git a/AppImage/scripts/build_appimage.sh b/AppImage/scripts/build_appimage.sh index f3a38d9..b733f53 100644 --- a/AppImage/scripts/build_appimage.sh +++ b/AppImage/scripts/build_appimage.sh @@ -351,17 +351,6 @@ download_deb() { # Try to download packages (non-fatal if they fail) download_deb "http://deb.debian.org/debian/pool/main/i/ipmitool/ipmitool_1.8.19-4+deb12u2_amd64.deb" "ipmitool.deb" "ipmitool" || true download_deb "http://deb.debian.org/debian/pool/main/f/freeipmi/libfreeipmi17_1.6.10-3_amd64.deb" "libfreeipmi17.deb" "libfreeipmi17" || true - -if [ ! -f "libfreeipmi17.deb" ]; then - echo " Fallback: apt-get download libfreeipmi17" - apt-get update -qq || true - apt-get download -y libfreeipmi17 || true - # renombra al nombre esperado si hace falta - for f in libfreeipmi17_*_amd64.deb; do - [ -f "$f" ] && mv "$f" libfreeipmi17.deb - done -fi - download_deb "http://deb.debian.org/debian/pool/main/l/lm-sensors/lm-sensors_3.6.0-7.1_amd64.deb" "lm-sensors.deb" "lm-sensors" || true download_deb "http://deb.debian.org/debian/pool/main/n/nut/nut-client_2.8.0-7_amd64.deb" "nut-client.deb" "nut-client" || true download_deb "http://deb.debian.org/debian/pool/main/n/nut/libupsclient6_2.8.0-7_amd64.deb" "libupsclient6.deb" "libupsclient6" || true diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py index a6ed297..a9ee901 100644 --- a/AppImage/scripts/flask_server.py +++ b/AppImage/scripts/flask_server.py @@ -1708,7 +1708,8 @@ def get_hardware_info(): print(f"[v0] Error getting graphics cards: {e}") try: - print("[v0] Getting all PCI devices...") + print("[v0] Getting PCI devices with driver information...") + # First get basic device info with lspci -vmm result = subprocess.run(['lspci', '-vmm'], capture_output=True, text=True, timeout=10) if result.returncode == 0: current_device = {} @@ -1721,6 +1722,7 @@ def get_hardware_info(): device_class = current_device.get('Class', '') device_name = current_device.get('Device', '') vendor = current_device.get('Vendor', '') + slot = current_device.get('Slot', 'Unknown') # Categorize and add important devices device_type = 'Other' @@ -1730,88 +1732,79 @@ def get_hardware_info(): if any(keyword in device_class for keyword in ['VGA', 'Display', '3D']): device_type = 'Graphics Card' include_device = True - # Also add to graphics_cards list - gpu_vendor = 'Unknown' - if 'NVIDIA' in vendor or 'NVIDIA' in device_name: - gpu_vendor = 'NVIDIA' - elif 'AMD' in vendor or 'AMD' in device_name or 'ATI' in vendor: - gpu_vendor = 'AMD' - elif 'Intel' in vendor or 'Intel' in device_name: - gpu_vendor = 'Intel' - - # Check if not already in graphics_cards - already_exists = False - for existing_gpu in hardware_data['graphics_cards']: - if device_name in existing_gpu['name'] or existing_gpu['name'] in device_name: - already_exists = True - break - - if not already_exists: - hardware_data['graphics_cards'].append({ - 'name': device_name, - 'vendor': gpu_vendor - }) - # Storage controllers elif any(keyword in device_class for keyword in ['SATA', 'RAID', 'Mass storage', 'Non-Volatile memory']): device_type = 'Storage Controller' include_device = True - # Network controllers elif 'Ethernet' in device_class or 'Network' in device_class: device_type = 'Network Controller' include_device = True - # Also add to network_cards if not already there - already_exists = False - for existing_nic in hardware_data['network_cards']: - if device_name in existing_nic['name'] or existing_nic['name'] in device_name: - already_exists = True - break - - if not already_exists: - hardware_data['network_cards'].append({ - 'name': device_name, - 'type': 'Ethernet' if 'Ethernet' in device_class else 'Network' - }) - # USB controllers elif 'USB' in device_class: device_type = 'USB Controller' include_device = True - # Audio devices elif 'Audio' in device_class or 'Multimedia' in device_class: device_type = 'Audio Controller' include_device = True - # Special devices (Coral TPU, etc.) elif any(keyword in device_name.lower() for keyword in ['coral', 'tpu', 'edge']): device_type = 'AI Accelerator' include_device = True - # PCI bridges (usually not interesting for users) elif 'Bridge' in device_class: include_device = False if include_device: pci_device = { - 'slot': current_device.get('Slot', 'Unknown'), + 'slot': slot, 'type': device_type, 'vendor': vendor, 'device': device_name, 'class': device_class } hardware_data['pci_devices'].append(pci_device) - print(f"[v0] PCI Device: {device_type} - {device_name}") current_device = {} elif ':' in line: key, value = line.split(':', 1) current_device[key.strip()] = value.strip() + + # Now get driver information with lspci -k + result_k = subprocess.run(['lspci', '-k'], capture_output=True, text=True, timeout=10) + if result_k.returncode == 0: + current_slot = None + current_driver = None + current_module = None - print(f"[v0] Total PCI devices found: {len(hardware_data['pci_devices'])}") - print(f"[v0] Graphics cards: {len(hardware_data['graphics_cards'])}") - print(f"[v0] Network cards: {len(hardware_data['network_cards'])}") + for line in result_k.stdout.split('\n'): + # Match PCI slot line (e.g., "00:1f.2 SATA controller: ...") + if line and not line.startswith('\t'): + parts = line.split(' ', 1) + if parts: + current_slot = parts[0] + current_driver = None + current_module = None + # Match driver lines (indented with tab) + elif line.startswith('\t'): + line = line.strip() + if line.startswith('Kernel driver in use:'): + current_driver = line.split(':', 1)[1].strip() + elif line.startswith('Kernel modules:'): + current_module = line.split(':', 1)[1].strip() + + # Update the corresponding PCI device + if current_slot and (current_driver or current_module): + for device in hardware_data['pci_devices']: + if device['slot'] == current_slot: + if current_driver: + device['driver'] = current_driver + if current_module: + device['kernel_module'] = current_module + break + + print(f"[v0] Total PCI devices found: {len(hardware_data['pci_devices'])}") except Exception as e: print(f"[v0] Error getting PCI devices: {e}") @@ -2047,12 +2040,29 @@ def api_hardware(): """Get comprehensive hardware information""" hardware_info = get_hardware_info() - network_info = get_network_info() - hardware_info['network_interfaces'] = network_info.get('physical_interfaces', []) + network_info.get('bridge_interfaces', []) + # Format data for frontend + formatted_data = { + 'cpu': hardware_info.get('cpu', {}), + 'motherboard': hardware_info.get('motherboard', {}), + 'memory_modules': hardware_info.get('memory_modules', []), + 'storage_devices': hardware_info.get('storage_devices', []), + 'pci_devices': hardware_info.get('pci_devices', []), + 'temperatures': hardware_info.get('sensors', {}).get('temperatures', []), + 'fans': hardware_info.get('ipmi_fans', []), + 'power_supplies': hardware_info.get('ipmi_power', {}).get('power_supplies', []), + 'power_meter': hardware_info.get('power_meter'), + 'ups': hardware_info.get('ups') if hardware_info.get('ups') else None + } - print(f"[v0] /api/hardware returning {len(hardware_info.get('network_interfaces', []))} network interfaces") + print(f"[v0] /api/hardware returning data") + print(f"[v0] - CPU: {formatted_data['cpu'].get('model', 'Unknown')}") + print(f"[v0] - Temperatures: {len(formatted_data['temperatures'])} sensors") + print(f"[v0] - Fans: {len(formatted_data['fans'])} fans") + print(f"[v0] - Power supplies: {len(formatted_data['power_supplies'])} PSUs") + print(f"[v0] - Power meter: {'Yes' if formatted_data['power_meter'] else 'No'}") + print(f"[v0] - UPS: {'Yes' if formatted_data['ups'] else 'No'}") - return jsonify(hardware_info) + return jsonify(formatted_data) @app.route('/api/vms/', methods=['GET']) def api_vm_details(vmid): diff --git a/AppImage/types/hardware.ts b/AppImage/types/hardware.ts index e55043a..6a0a8d9 100644 --- a/AppImage/types/hardware.ts +++ b/AppImage/types/hardware.ts @@ -38,6 +38,17 @@ export interface PCIDevice { memory_address?: string link_speed?: string capabilities?: string[] + gpu_memory?: string + gpu_driver_version?: string + gpu_cuda_version?: string + gpu_compute_capability?: string + gpu_power_draw?: string + gpu_temperature?: number + gpu_utilization?: number + gpu_memory_used?: string + gpu_memory_total?: string + gpu_clock_speed?: string + gpu_memory_clock?: string } export interface Fan {