From c2d7ee1104effef090d894a0cb1ad771c7a70243 Mon Sep 17 00:00:00 2001 From: Vlad <427departament@gmail.com> Date: Thu, 25 Dec 2025 18:21:38 +0300 Subject: [PATCH 1/3] Add log export functionality with device detection and localization updates - Implemented a feature to export logs to a removable device. - Added a button in the UI for exporting logs. - Included error handling for missing devices and log files. - Updated Russian localization with new messages for log export success and errors. --- .../locales/ru/LC_MESSAGES/KlipperScreen.po | 9 + panels/system.py | 165 ++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po index 0c8b77ad9..d93ba682e 100644 --- a/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po @@ -1159,3 +1159,12 @@ msgstr "Истекло время ожидания при отмонтирова msgid "Error unmounting device" msgstr "Ошибка при отмонтировании устройства" + +msgid "No removable device found" +msgstr "Съемный носитель не найден" + +msgid "Logs saved successfully" +msgstr "Журналы успешно сохранены" + +msgid "Error exporting logs" +msgstr "Ошибка при экспорте журналов" \ No newline at end of file diff --git a/panels/system.py b/panels/system.py index ae301b19d..c77ad6ca1 100644 --- a/panels/system.py +++ b/panels/system.py @@ -1,4 +1,9 @@ import logging +import os +import subprocess +import shutil +import zipfile +from datetime import datetime import gi @@ -65,6 +70,14 @@ def create_layout(self): self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) self.current_row += 1 self.populate_info() + + # Add Export Logs button + self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) + self.current_row += 1 + export_button = self._gtk.Button("refresh", "Export Logs", "color4") + export_button.connect("clicked", self.export_logs) + self.grid.attach(export_button, 0, self.current_row, 2, 1) + self.current_row += 1 scroll = self._gtk.ScrolledWindow() scroll.add(self.grid) @@ -142,6 +155,158 @@ def populate_info(self): else: self.add_label_to_grid(f"{self.prettify(key)}: {value}", 1) + def find_mounted_device(self): + """Находит примонтированное устройство в /home/pi/printer_data/gcodes/""" + gcodes_base = "/home/pi/printer_data/gcodes" + + if not os.path.exists(gcodes_base): + return None + + # Проверяем все подкаталоги в gcodes + try: + for item in os.listdir(gcodes_base): + item_path = os.path.join(gcodes_base, item) + # Проверяем, является ли путь точкой монтирования + if os.path.isdir(item_path) and os.path.ismount(item_path): + return item_path + except OSError as e: + logging.error(f"Error scanning gcodes directory: {e}") + + return None + + def export_logs(self, widget): + """Экспортирует журналы на съемный носитель""" + # Ищем примонтированное устройство + mounted_device = self.find_mounted_device() + + if not mounted_device: + self._screen.show_popup_message(_("No removable device found"), level=3) + logging.warning("No mounted device found in /home/pi/printer_data/gcodes/") + return + + home_dir = os.path.expanduser("~") + temp_dir = os.path.join(home_dir, "printer_data", "logs_export_temp") + + try: + # Создаем временную директорию для файлов + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + os.makedirs(temp_dir) + + # Пути к файлам логов + logs_dir = os.path.join(home_dir, "printer_data", "logs") + log_files = [ + ("klippy.log", os.path.join(logs_dir, "klippy.log")), + ("moonraker.log", os.path.join(logs_dir, "moonraker.log")), + ("crowsnest.log", os.path.join(logs_dir, "crowsnest.log")), + ] + + # KlipperScreen.log может быть в разных местах + klipperscreen_log_paths = [ + os.path.join(logs_dir, "KlipperScreen.log"), + "/tmp/KlipperScreen.log", + ] + for log_path in klipperscreen_log_paths: + if os.path.exists(log_path): + log_files.append(("KlipperScreen.log", log_path)) + break + + # Копируем файлы логов, если они существуют + for dest_name, source_path in log_files: + if os.path.exists(source_path): + dest_path = os.path.join(temp_dir, dest_name) + shutil.copy2(source_path, dest_path) + logging.info(f"Copied {source_path} to {dest_path}") + else: + logging.warning(f"Log file not found: {source_path}") + + # Выполняем команду dmesg и сохраняем вывод + try: + dmesg_result = subprocess.run( + ["dmesg"], + capture_output=True, + text=True, + timeout=10 + ) + if dmesg_result.returncode == 0: + dmesg_file = os.path.join(temp_dir, "dmesg.txt") + with open(dmesg_file, "w", encoding="utf-8") as f: + f.write(dmesg_result.stdout) + logging.info("Saved dmesg output") + except Exception as e: + logging.error(f"Error running dmesg: {e}") + + # Выполняем команду df -h и сохраняем вывод + try: + df_result = subprocess.run( + ["df", "-h"], + capture_output=True, + text=True, + timeout=10 + ) + if df_result.returncode == 0: + df_file = os.path.join(temp_dir, "df_h.txt") + with open(df_file, "w", encoding="utf-8") as f: + f.write(df_result.stdout) + logging.info("Saved df -h output") + except Exception as e: + logging.error(f"Error running df -h: {e}") + + # Создаем ZIP архив + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + zip_filename = f"logs_export_{timestamp}.zip" + zip_path = os.path.join(temp_dir, zip_filename) + + with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(temp_dir): + for file in files: + if file != zip_filename: # Не добавляем сам архив + file_path = os.path.join(root, file) + arcname = os.path.basename(file_path) + zipf.write(file_path, arcname) + + # Копируем архив на съемный носитель + dest_zip_path = os.path.join(mounted_device, zip_filename) + shutil.copy2(zip_path, dest_zip_path) + logging.info(f"Copied archive to {dest_zip_path}") + + # Удаляем временную директорию + shutil.rmtree(temp_dir) + + # Показываем уведомление об успехе + self._screen.show_popup_message( + _("Logs saved successfully") + f"\n{zip_filename}", + level=1 + ) + + # Отмонтируем устройство + try: + result = subprocess.run( + ["sudo", "umount", mounted_device], + capture_output=True, + text=True, + timeout=10 + ) + if result.returncode == 0: + logging.info(f"Successfully unmounted {mounted_device}") + else: + logging.warning(f"Failed to unmount {mounted_device}: {result.stderr}") + except Exception as e: + logging.error(f"Error unmounting device: {e}") + + except Exception as e: + logging.error(f"Error exporting logs: {e}") + self._screen.show_popup_message( + _("Error exporting logs") + f": {str(e)}", + level=3 + ) + # Удаляем временную директорию в случае ошибки + if os.path.exists(temp_dir): + try: + shutil.rmtree(temp_dir) + except: + pass + def process_update(self, action, data): if not self.sysinfo: return From 537f51d078f6d511dd76cb8197834ca0988c915f Mon Sep 17 00:00:00 2001 From: Vlad <427departament@gmail.com> Date: Thu, 25 Dec 2025 18:27:58 +0300 Subject: [PATCH 2/3] Update Russian localization and add Export Logs button in the system panel --- .../locales/ru/LC_MESSAGES/KlipperScreen.mo | Bin 29624 -> 29970 bytes .../locales/ru/LC_MESSAGES/KlipperScreen.po | 7 +++++-- panels/system.py | 17 +++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.mo b/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.mo index ddcc9e6e6d1fe27c85b1bf9abc710a640604cdfe..82267de0e9972d509216940b5dd6cf94dc7a32aa 100644 GIT binary patch delta 8409 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 XbFoKJKyIjS(SSaky^78cNUHK*g9~Dz diff --git a/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po index d93ba682e..1128b1f47 100644 --- a/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-11-26 12:31-0300\n" -"PO-Revision-Date: 2025-12-25 18:00+0300\n" +"PO-Revision-Date: 2025-12-25 18:27+0300\n" "Last-Translator: gfbdrgng \n" "Language-Team: Russian \n" "Language: ru\n" @@ -1167,4 +1167,7 @@ msgid "Logs saved successfully" msgstr "Журналы успешно сохранены" msgid "Error exporting logs" -msgstr "Ошибка при экспорте журналов" \ No newline at end of file +msgstr "Ошибка при экспорте журналов" + +msgid "Export Logs" +msgstr "Экпорт журналов" diff --git a/panels/system.py b/panels/system.py index c77ad6ca1..9c07b30dc 100644 --- a/panels/system.py +++ b/panels/system.py @@ -41,6 +41,15 @@ def back(self): return False def create_layout(self): + # Add Export Logs button at the top + export_button = self._gtk.Button("refresh", "Export Logs", "color4") + export_button.connect("clicked", self.export_logs) + self.grid.attach(export_button, 0, self.current_row, 2, 1) + self.current_row += 1 + + self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) + self.current_row += 1 + self.cpu_count = int(self.sysinfo["cpu_info"]["cpu_count"]) self.labels["cpu_usage"] = Gtk.Label(label="", xalign=0) self.grid.attach(self.labels["cpu_usage"], 0, self.current_row, 1, 1) @@ -70,14 +79,6 @@ def create_layout(self): self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) self.current_row += 1 self.populate_info() - - # Add Export Logs button - self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) - self.current_row += 1 - export_button = self._gtk.Button("refresh", "Export Logs", "color4") - export_button.connect("clicked", self.export_logs) - self.grid.attach(export_button, 0, self.current_row, 2, 1) - self.current_row += 1 scroll = self._gtk.ScrolledWindow() scroll.add(self.grid) From 9a367814abe91f2f05bfe33438f7da9ea587712b Mon Sep 17 00:00:00 2001 From: Vlad <427departament@gmail.com> Date: Thu, 25 Dec 2025 18:29:08 +0300 Subject: [PATCH 3/3] 1 --- panels/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panels/system.py b/panels/system.py index 9c07b30dc..666c52719 100644 --- a/panels/system.py +++ b/panels/system.py @@ -42,7 +42,7 @@ def back(self): def create_layout(self): # Add Export Logs button at the top - export_button = self._gtk.Button("refresh", "Export Logs", "color4") + export_button = self._gtk.Button("refresh", _("Export Logs"), "color4") export_button.connect("clicked", self.export_logs) self.grid.attach(export_button, 0, self.current_row, 2, 1) self.current_row += 1