diff --git a/hwmonDaemon.py b/hwmonDaemon.py index debe18b..9898f19 100644 --- a/hwmonDaemon.py +++ b/hwmonDaemon.py @@ -567,23 +567,24 @@ class SystemHealthMonitor: last_test_date = smart_data.get('last_test_date', 'N/A') age = f"{int(power_on_hours/24/365) if isinstance(power_on_hours, (int, float)) else 'N/A'} years" if power_on_hours != 'N/A' else 'N/A' - description += """ - ┏━ DRIVE SPECIFICATIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Device Path │ {:<60} ┃ - ┃ Model │ {:<60} ┃ - ┃ Serial │ {:<60} ┃ - ┃ Capacity │ {:<60} ┃ - ┃ Type │ {:<60} ┃ - ┃ Firmware │ {:<60} ┃ - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - """.format( - device, - drive_details.get('model', 'N/A'), - drive_details.get('serial', 'N/A'), - drive_details.get('capacity', 'N/A'), - drive_details.get('type', 'N/A'), - drive_details.get('firmware', 'N/A') - ) + # Fix the formatting issue by ensuring all values are strings and not None + device_safe = device or 'N/A' + model_safe = drive_details.get('model') or 'N/A' + serial_safe = drive_details.get('serial') or 'N/A' + capacity_safe = drive_details.get('capacity') or 'N/A' + type_safe = drive_details.get('type') or 'N/A' + firmware_safe = drive_details.get('firmware') or 'N/A' + + description += f""" +┏━ DRIVE SPECIFICATIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Device Path │ {device_safe:<60} ┃ +┃ Model │ {model_safe:<60} ┃ +┃ Serial │ {serial_safe:<60} ┃ +┃ Capacity │ {capacity_safe:<60} ┃ +┃ Type │ {type_safe:<60} ┃ +┃ Firmware │ {firmware_safe:<60} ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +""" if drive_info: perf_metrics = { @@ -593,34 +594,34 @@ class SystemHealthMonitor: 'iops': drive_info.get('performance_metrics', {}).get('iops', 'N/A') } - description += """ - ┏━ DRIVE TIMELINE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Power-On Hours │ {:<56} ┃ - ┃ Last SMART Test │ {:<56} ┃ - ┃ Drive Age │ {:<56} ┃ - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - """.format( - f"{power_on_hours} hours" if power_on_hours != 'N/A' else 'N/A', - last_test_date, - age - ) + power_on_safe = f"{power_on_hours} hours" if power_on_hours != 'N/A' else 'N/A' + last_test_safe = last_test_date or 'N/A' + age_safe = age or 'N/A' - description += """ - ┏━ SMART STATUS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Status │ {:<60} ┃ - ┃ Temperature │ {:<60} ┃ - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - """.format( - drive_info.get('smart_status', 'N/A'), - f"{drive_info.get('temperature')}°C" if drive_info.get('temperature') else 'N/A' - ) + description += f""" +┏━ DRIVE TIMELINE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Power-On Hours │ {power_on_safe:<56} ┃ +┃ Last SMART Test │ {last_test_safe:<56} ┃ +┃ Drive Age │ {age_safe:<56} ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +""" + + smart_status_safe = drive_info.get('smart_status') or 'N/A' + temp_safe = f"{drive_info.get('temperature')}°C" if drive_info.get('temperature') else 'N/A' + + description += f""" +┏━ SMART STATUS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Status │ {smart_status_safe:<60} ┃ +┃ Temperature │ {temp_safe:<60} ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +""" if drive_info.get('smart_attributes'): description += "\n┏━ SMART ATTRIBUTES " + "━" * 48 + "┓\n" for attr, value in drive_info['smart_attributes'].items(): - description += "┃ {:<25} │ {:<37} ┃\n".format( - attr.replace('_', ' '), value - ) + attr_safe = str(attr).replace('_', ' ') if attr else 'Unknown' + value_safe = str(value) if value is not None else 'N/A' + description += f"┃ {attr_safe:<25} │ {value_safe:<37} ┃\n" description += "┗" + "━" * 71 + "┛\n" if drive_info.get('partitions'): @@ -629,30 +630,29 @@ class SystemHealthMonitor: blocks = int(usage_percent / 5) # 20 blocks total = 100% usage_meter = '█' * blocks + '░' * (20 - blocks) - description += """ - ┏━ PARTITION [{:<60}] ━┓ - ┃ Filesystem │ {:<60} ┃ - ┃ Usage Meter │ [{:<58}] ┃ - ┃ Total Space │ {:<60} ┃ - ┃ Used Space │ {:<60} ┃ - ┃ Free Space │ {:<60} ┃ - ┃ Usage │ {:<60} ┃ - ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - """.format( - partition.get('mountpoint', 'N/A'), - partition.get('fstype', 'N/A'), - usage_meter, - partition.get('total_space', 'N/A'), - partition.get('used_space', 'N/A'), - partition.get('free_space', 'N/A'), - f"{usage_percent}%" - ) + mountpoint_safe = partition.get('mountpoint') or 'N/A' + fstype_safe = partition.get('fstype') or 'N/A' + total_space_safe = partition.get('total_space') or 'N/A' + used_space_safe = partition.get('used_space') or 'N/A' + free_space_safe = partition.get('free_space') or 'N/A' + + description += f""" +┏━ PARTITION [{mountpoint_safe:<60}] ━┓ +┃ Filesystem │ {fstype_safe:<60} ┃ +┃ Usage Meter │ [{usage_meter:<58}] ┃ +┃ Total Space │ {total_space_safe:<60} ┃ +┃ Used Space │ {used_space_safe:<60} ┃ +┃ Free Space │ {free_space_safe:<60} ┃ +┃ Usage │ {usage_percent}%{'':<57} ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +""" firmware_info = self._check_disk_firmware(device) if firmware_info['is_problematic']: description += "\n┏━ FIRMWARE ALERTS " + "━" * 48 + "┓\n" - for issue in firmware_info['known_issues']: - description += "┃ ⚠ {:<67} ┃\n".format(issue) + for issue_item in firmware_info['known_issues']: + issue_safe = str(issue_item) if issue_item else 'Unknown issue' + description += f"┃ ⚠ {issue_safe:<67} ┃\n" description += "┗" + "━" * 71 + "┛\n" except Exception as e: description += f"\nError generating drive details: {str(e)}\n"