Grüße,
ich würde sagen, legen sofort los und beginnen mit einer Bestandsaufnahme.
Die Tabelle zeigt, dass wir 8 von 16 Funktionen schon implementiert haben, wobei es 3 gibt, die noch Nacharbeitung benötigen.
Zu erledigen sind noch Distro Logo, Uptime, Packages, DE, WM, WM-Theme, Icons und Terminal.
Distro Logo | Nur Platzhalter | |
USER & HOST | Check | Sollte keine Probleme machen |
OS | Check | Sollte keine Probleme machen |
Host | Check | Muss angepasst werden |
Kernel | Check | Sollte keine Probleme machen |
Uptime | ||
Packages | ||
Shell | Check | Muss angepasst werden |
Resolution | Check | Sollte keine Probleme machen |
DE | ||
WM | ||
WM-Theme | ||
Icons | ||
Terminal | ||
CPU | Check | Sollte keine Probleme machen |
Memory | Check | Sollte keine Probleme machen |
Rückmeldungen
Mir ist natürlich von Anfang an bewusst gewesen, dass dieses Tutorial nicht alle Linux-Nutzer abholen kann. Das ist dem Grund geschuldet, dass ich hier teils Debian-Befehlen arbeite. Es besteht ja die Möglichkeit eine virtuelle Python Umgebung zu schaffen, die ohne die Bibliotheken einer bestimmten Distro funktioniert. Natürlich will ich niemanden ausschließen.
Die Debian-Basis ist nun mal am weitesten verbreitet und kein Python-Einsteiger-Tutorial der Welt fängt an mit der Erklärung, wie man den Python-Paket-Manager nutzt. Ich werde mir aber in der Sommerpause Gedanken machen, wie/wann ich diesen am besten einführe.
Uptime
Wir wollen also herausfinden, wie lange unser PC schon an ist. Da hier wieder Mathematik und tiefergehendes Verständnis nötig ist, legen wir ein Test-File an.
Wir importieren:
import psutil import datetimeNur machen wir den Zeitpunkt, an dem der PC gestartet ist. Von psutil nutzen wir die Methode boot_time.
import psutil import datetime unix_timestamp = psutil.boot_time() print(unix_timestamp)Das Ergebnis sieht bei mir so aus:
1720781358.0psutil.boot_time() gibt die Zeit als Unix-Zeitstempel zurück, zu der das System gestartet wurde. Um diese Zahl besser verständlich auszudrücken, nutzen wir datetime.
boot_time = datetime.datetime.fromtimestamp(unix_timestamp)Dieses Modul ist etwas verwirrend. Man nutzt die Methode frometimestamp aus Methode datetime des Moduls datetime und geb unseren unix_timestamp hinein.
Das Resultat
import psutil import datetime unix_timestamp = psutil.boot_time() boot_time = datetime.datetime.fromtimestamp(unix_timestamp) print(boot_time) >>> 2024-07-12 12:49:18Jetzt wissen wir genau, wann ich meinen PC angeschaltet habe. Nun müssen wir noch herausfinden welches Datum um wie viel Uhr es gerade in diesem Augenblick sind.
now = datetime.datetime.now()Jetzt kommt ganz simple Subtraktion zum Einsatz
uptime = now - boot_time[Jetzt] - (MINUS) [Wann wurde der PC angeschaltet]
Der ganze Test-Code
import psutil import datetime unix_timestamp = psutil.boot_time() boot_time = datetime.datetime.fromtimestamp(unix_timestamp) now = datetime.datetime.now() uptime = now - boot_time print(f"Startzeit: {boot_time}") print(f"Jetzt: {now}") print(f"Uptime: {uptime}") >>> Startzeit: 2024-07-12 12:49:18 Jetzt: 2024-07-12 17:49:43.825505 Uptime: 5:00:25.825505In Main einbinden
Wie auch im Test-Skript importieren wir datetime
import datetimeDa wir ja irgendwann Live-Daten auslesen wollen, habe ich die UPTIME in eine Funktion gepackt und ein paar Änderungen vorgenommen, um die Lesbarkeit zu verbessern.
def get_sys_uptime(): # System-Startzeit ermitteln boot_time_timestamp = psutil.boot_time() boot_time = datetime.datetime.fromtimestamp(boot_time_timestamp) # Aktuelle Zeit now = datetime.datetime.now() # Uptime berechnen uptime = now - boot_time # Uptime in Stunden und Minuten umrechnen uptime_hours, remainder = divmod(uptime.total_seconds(), 3600) uptime_minutes = remainder // 60 return f"{int(uptime_hours)} h , {int(uptime_minutes)} m"Es wird mal wieder etwas komplexer. Der Wert aus uptime wird hier in Stunden und Minuten umgewandelt. Was übrigbleibt, wird durch 60 geteilt. Wird die Funktion abgerufen, soll "X h, X m" ausgegeben werden.
uptime_hours, remainder = divmod(uptime.total_seconds(), 3600) uptime_minutes = remainder // 60 return f"{int(uptime_hours)} h , {int(uptime_minutes)} m"Logik
- Eine Stunde hat 3600 Sekunden.
- divmod Teil den Wert aus uptime._total_seconds.
- Was bleibt sind Stunde und ein Rest
- Der Rest wird durch 60 geteilt
- Ergibt der Rest eine oder mehrere ganze Minuten, landet in uptime_minutes
- über return findet die Ausgabe statt
- Da wir ganze Zahlen wollen, aber eine Kommazahl bekommen(float), nutzen wir int um die Zahlen zu konvertieren
- Das geht aber nur, weil wir durch divmod ganze Zahlen z. B. 10.0 zurückbekommen
Unter dem kernel_label machen wir etwas Platz frei und schreiben wie gewohnt ein Label, dessen Text den Inhalt der Funktion wiedergibt.
uptime_label = tk.Label(stat_frame,text=f"Uptime: {get_sys_uptime()}") uptime_label.pack(anchor=tk.NW)Der ganze Code in Main
## Teil 8 ### import tkinter as tk from PIL import Image, ImageTk import os import socket import distro import platform import psutil import datetime def get_size(bytes, suffix="B"): """ Scale bytes to its proper format e.g: 1253656 => '1.20MB' 1253656678 => '1.17GB' """ factor = 1024 for unit in ["", "K", "M", "G", "T", "P"]: if bytes < factor: return f"{bytes:.2f}{unit}{suffix}" bytes /= factor def get_screen_size(): screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() return f"{screen_width}x{screen_height}" def get_sys_uptime(): # System-Startzeit ermitteln boot_time_timestamp = psutil.boot_time() boot_time = datetime.datetime.fromtimestamp(boot_time_timestamp) # Aktuelle Zeit now = datetime.datetime.now() # Uptime berechnen uptime = now - boot_time # Uptime in Stunden und Minuten umrechnen uptime_hours, remainder = divmod(uptime.total_seconds(), 3600) uptime_minutes = remainder // 60 return f"{int(uptime_hours)} h , {int(uptime_minutes)} m" user = os.environ["USER"] hostname = socket.gethostname() os_release_pretty = distro.name(pretty=True) kernel_release = platform.release() svmem = psutil.virtual_memory() cpu_freq = psutil.cpu_freq() cpu_core_count = psutil.cpu_count(logical=False) active_shell = os.environ["SHELL"] # Erstelle das Hauptfenster root = tk.Tk() root.title("Neofetch-Tk") root.geometry("800x500") distro_logo = tk.PhotoImage(file="images/test.png") # Einen Frame Zeichen logo_frame = tk.Frame(root,background="yellow") logo_frame.pack(fill="both",expand=False,side='left',padx=10,pady=10) # Distro-Logo-Label distro_icon = tk.Label(logo_frame,text="DISTRO LOGO",image=distro_logo,background="yellow") distro_icon.pack(anchor=tk.NW) # Einen Frame Zeichen stat_frame = tk.Frame(root,background="cyan") stat_frame.pack(fill="both",expand=True,side='left',padx=10,pady=10) # Label mit Text USER@HOST user_host_label = tk.Label(stat_frame,text=f"{user}@{hostname}") user_host_label.pack(anchor=tk.NW) # Label mit Text OS: os_label = tk.Label(stat_frame,text=f"OS: {os_release_pretty}") os_label.pack(anchor=tk.NW) host_label = tk.Label(stat_frame,text=f"Host: {hostname}") host_label.pack(anchor=tk.NW) kernel_label = tk.Label(stat_frame,text=f"Kernel: {kernel_release}") kernel_label.pack(anchor=tk.NW) uptime_label = tk.Label(stat_frame,text=f"Uptime: {get_sys_uptime()}") uptime_label.pack(anchor=tk.NW) shell_label = tk.Label(stat_frame,text=f"Shell: {active_shell}") shell_label.pack(anchor=tk.NW) res_label = tk.Label(stat_frame,text=f"Resolution: {get_screen_size()}") res_label.pack(anchor=tk.NW) cpu_label = tk.Label(stat_frame,text=f"CPU: ({cpu_core_count}) @ {cpu_freq.max:.2f} Mhz") cpu_label.pack(anchor=tk.NW) mem_label = tk.Label(stat_frame,text=f"Memory: {(get_size(svmem.used))}/{get_size(svmem.total)}") mem_label.pack(anchor=tk.NW) # Starte die Hauptschleife root.mainloop()
Bye, Bye Platzhalter-Logo
Auch hier gehen wir es langsam an. Wir möchten ja das korrekte Logo unterer Distribution angezeigt bekommen. Wie stellen wir das jetzt an? Um die Basis herauszufinden, können wir wieder ein Modul nutzen.
sudo apt install python3-distroIn manchen Fällen ist distro aber auch schon vorinstalliert. Nutzen können wir es wie folgt.
import distro print(f"id: {distro.id()}") print(f"name: {distro.name()}") print(f"version: {distro.version()}") print(f"codename: {distro.codename()}") >>> id: ubuntu name: Ubuntu version: 24.04 codename: nobleIch habe bei Distrosea so einige Distributionen durchgesehen und leider stand in den release-Files immer nur die Basis. Würden wir den obigen Code so nutzen könnten wir also nur auslesen, dass wir ein Ubuntu nutzen aber nicht ein Kubuntu oder Xubuntu. Linux Mint bildet übrigens eine Ausnahme. Sucht man die ID steht dort nicht ubuntu, sondern linuxmint.
Natürlich ist es schöner gleich das korrekte Logo zu sehen, um zu lernen, wie wir das überhaupt anstellen, gehen wir erstmal nur mit den Logos der Distro-Basis.
Ach und Siduction habe ich nicht vergessen! Das ist aber ein Sonderfall. Hier müssen wir den Inhalt einer Datei auslesen. Dazu benötigt man with open. Das muss ich auch erst erklären. (nach der Pause).
Zunächst brauchen wir überhaupt mal Logos. Ich habe uns welche vorbereitet. Ihr könnt sie einfach auf Github herunterladen.
Die PNGs sollten wie folgt in die Ordnerstruktur eingegliedert werden.
~/neofetch-tk$ tree . ├── images │ ├── arch_logo_350.png │ ├── debian_logo_350.png │ ├── fedora_logo_350.png │ ├── mint_logo_350.png │ ├── osuse_logo_350.png │ ├── test.png │ └── ubuntu_logo_350.png └── main.pyWir gehen in unser main.py-File und importieren distro und fügen folgenden Code zu den anderen Variablen hinzu.
distro_id = distro.id()Nach dem Vorbild unseres Platzhalters erstellen wir nun Variablen, die Logos beinhalten.
distro_logo = tk.PhotoImage(file="images/test.png")Neue Logos:
distro_logo = tk.PhotoImage(file="images/test.png") arch_logo = tk.PhotoImage(file="images/arch_logo_350.png") debian_logo = tk.PhotoImage(file="images/debian_logo_350.png") mint_logo = tk.PhotoImage(file="images/mint_logo_350.png") suse_logo = tk.PhotoImage(file="images/osuse_logo_350.png") ubuntu_logo = tk.PhotoImage(file="images/ubuntu_logo_350.png") fedora_logo = tk.PhotoImage(file="images/fedora_logo_350.png")Der Übersichtlichkeit halber bauen wir für die Nutzung eine Funktion, diese soll am Ende des Scripts ausgeführt werden.
def get_distro_logo(): if distro_id == "debian": distro_icon.configure(image=debian_logo) elif distro_id == "arch": distro_icon.configure(image=arch_logo) elif distro_id == "linuxmint": distro_icon.configure(image=mint_logo) elif distro_id == "ubuntu": distro_icon.configure(image=ubuntu_logo) elif distro_id == "opensuse": distro_icon.configure(image=osuse_logo) else: distro_icon.configure(image=distro_logo)[...]
get_distro_logo() # Starte die Hauptschleife root.mainloop()Logik
- Wenn(if) distro_id genau "debian" entspricht, wird mit der Methode configure das image durch debian_logo ersetzt
- Ist dem nicht so, werden die anderen Fälle(elif) durchgegangen, bis etwas Passendes gefunden wird
- Ist keine Annahme zutreffen (else:) wird unser Testbild gesetzt.
Der ganze Code(Mit aktualisierten Kommentaren)
## Teil 8 ### import tkinter as tk from PIL import Image, ImageTk import os import socket import distro import platform import psutil import datetime import distro # Macht die RAM-Größe lesbar def get_size(bytes, suffix="B"): """ Scale bytes to its proper format e.g: 1253656 => '1.20MB' 1253656678 => '1.17GB' """ factor = 1024 for unit in ["", "K", "M", "G", "T", "P"]: if bytes < factor: return f"{bytes:.2f}{unit}{suffix}" bytes /= factor # Findet die Auflösung heraus def get_screen_size(): screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() return f"{screen_width}x{screen_height}" def get_sys_uptime(): # System-Startzeit ermitteln boot_time_timestamp = psutil.boot_time() boot_time = datetime.datetime.fromtimestamp(boot_time_timestamp) # Aktuelle Zeit now = datetime.datetime.now() # Uptime berechnen uptime = now - boot_time # Uptime in Stunden und Minuten umrechnen uptime_hours, remainder = divmod(uptime.total_seconds(), 3600) uptime_minutes = remainder // 60 # Weist an das diese Funktion Stunden und Minuten ausgeben soll return f"{int(uptime_hours)} h , {int(uptime_minutes)} m" # Setzt das korrekte Logo für die Distro def get_distro_logo(): if distro_id == "debian": distro_icon.configure(image=debian_logo) elif distro_id == "arch": distro_icon.configure(image=arch_logo) elif distro_id == "linuxmint": distro_icon.configure(image=mint_logo) elif distro_id == "ubuntu": distro_icon.configure(image=ubuntu_logo) elif distro_id == "opensuse": distro_icon.configure(image=osuse_logo) elif distro_id == "fedora": distro_icon.configure(image=fedora_logo) else: distro_icon.configure(image=distro_logo) # Vars für die Labels # Ließt den User aus user = os.environ["USER"] # Ließt den Host aus hostname = socket.gethostname() # Ließt den Pretty Name aus os_release_pretty = distro.name(pretty=True) # Ließt den Kernel aus kernel_release = platform.release() # Basis um den RAM auszulesen svmem = psutil.virtual_memory() # Basis um CPU-Werte auszulesen cpu_freq = psutil.cpu_freq() # Ließt Anzahl der CPU-Kerne aus cpu_core_count = psutil.cpu_count(logical=False) # Gibt die aktuelle Shell aus active_shell = os.environ["SHELL"] # Gibt die Distro-ID aus distro_id = distro.id() # Erstelle das Hauptfenster root = tk.Tk() root.title("Neofetch-Tk") root.geometry("800x500") # Distro Logos distro_logo = tk.PhotoImage(file="images/test.png") arch_logo = tk.PhotoImage(file="images/arch_logo_350.png") debian_logo = tk.PhotoImage(file="images/debian_logo_350.png") mint_logo = tk.PhotoImage(file="images/mint_logo_350.png") suse_logo = tk.PhotoImage(file="images/osuse_logo_350.png") ubuntu_logo = tk.PhotoImage(file="images/ubuntu_logo_350.png") fedora_logo = tk.PhotoImage(file="images/fedora_logo_350.png") # Einen Frame Zeichen logo_frame = tk.Frame(root,background="yellow") logo_frame.pack(fill="both",expand=False,side='left',padx=10,pady=10) # Distro-Logo-Label distro_icon = tk.Label(logo_frame,text="DISTRO LOGO",image=distro_logo,background="yellow") distro_icon.pack(anchor=tk.NW) # Einen Frame Zeichen stat_frame = tk.Frame(root,background="cyan") stat_frame.pack(fill="both",expand=True,side='left',padx=10,pady=10) # Label mit Text USER@HOST user_host_label = tk.Label(stat_frame,text=f"{user}@{hostname}") user_host_label.pack(anchor=tk.NW) # Label mit Text OS: os_label = tk.Label(stat_frame,text=f"OS: {os_release_pretty}") os_label.pack(anchor=tk.NW) # Label mit Text Host: host_label = tk.Label(stat_frame,text=f"Host: {hostname}") host_label.pack(anchor=tk.NW) # Label mit Text Kernel: kernel_label = tk.Label(stat_frame,text=f"Kernel: {kernel_release}") kernel_label.pack(anchor=tk.NW) # Label mit Text Uptime: uptime_label = tk.Label(stat_frame,text=f"Uptime: {get_sys_uptime()}") uptime_label.pack(anchor=tk.NW) # Label mit Text Shell: shell_label = tk.Label(stat_frame,text=f"Shell: {active_shell}") shell_label.pack(anchor=tk.NW) # Label mit Text Resolution: res_label = tk.Label(stat_frame,text=f"Resolution: {get_screen_size()}") res_label.pack(anchor=tk.NW) # Label mit Text CPU: cpu_label = tk.Label(stat_frame,text=f"CPU: ({cpu_core_count}) @ {cpu_freq.max:.2f} Mhz") cpu_label.pack(anchor=tk.NW) # Label mit Text Memory: mem_label = tk.Label(stat_frame,text=f"Memory: {(get_size(svmem.used))}/{get_size(svmem.total)}") mem_label.pack(anchor=tk.NW) # Führt get_distro_logo aus get_distro_logo() # Starte die Hauptschleife root.mainloop()Das war's für heute. Nächstes Mal machen wir alles "schön".
Bis nächste Woche.
GNU/Linux.ch ist ein Community-Projekt. Bei uns kannst du nicht nur mitlesen, sondern auch selbst aktiv werden. Wir freuen uns, wenn du mit uns über die Artikel in unseren Chat-Gruppen oder im Fediverse diskutierst. Auch du selbst kannst Autor werden. Reiche uns deinen Artikelvorschlag über das Formular auf unserer Webseite ein.