creation du package
This commit is contained in:
BIN
cpu-monitor_1.0_all.deb
Normal file
BIN
cpu-monitor_1.0_all.deb
Normal file
Binary file not shown.
@@ -13,14 +13,33 @@ def get_cpu_ram() -> tuple[float, float]:
|
||||
return cpu, ram
|
||||
|
||||
|
||||
def get_disk_usage() -> float:
|
||||
return psutil.disk_usage('/').percent
|
||||
|
||||
|
||||
def get_net_io() -> tuple[int, int]:
|
||||
counters = psutil.net_io_counters()
|
||||
return counters.bytes_sent, counters.bytes_recv
|
||||
|
||||
|
||||
def get_disk_io() -> tuple[int, int]:
|
||||
counters = psutil.disk_io_counters()
|
||||
if counters is None:
|
||||
return 0, 0
|
||||
return counters.read_bytes, counters.write_bytes
|
||||
|
||||
|
||||
def format_line() -> str:
|
||||
now = datetime.now().strftime("%H:%M:%S")
|
||||
cpu, ram = get_cpu_ram()
|
||||
return f"{now} | CPU: {cpu:5.1f}% | RAM: {ram:5.1f}%"
|
||||
disk = get_disk_usage()
|
||||
d_read, d_write = get_disk_io()
|
||||
sent, recv = get_net_io()
|
||||
return f"{now} | CPU: {cpu:5.1f}% | RAM: {ram:5.1f}% | Disk: {disk:5.1f}% | ↑{d_read:,} ↓{d_write:,} B | Net: ↑{sent:,} ↓{recv:,} B"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Monitoring CPU/RAM. Ctrl+C pour arrêter.")
|
||||
print("Monitoring CPU/RAM/Disk. Ctrl+C pour arrêter.")
|
||||
try:
|
||||
while True:
|
||||
print(format_line())
|
||||
|
||||
9
cpu_monitor_gui.desktop
Normal file
9
cpu_monitor_gui.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=/usr/bin/cpu-monitor
|
||||
Hidden=false
|
||||
NoDisplay=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
Name=CPU Monitor GUI
|
||||
Comment=CPU/RAM/Disk/Network monitor
|
||||
Icon=utilities-system-monitor
|
||||
131
cpu_monitor_gui.py
Normal file → Executable file
131
cpu_monitor_gui.py
Normal file → Executable file
@@ -14,37 +14,89 @@ MAX_POINTS = 60
|
||||
UPDATE_INTERVAL = 1000 # ms
|
||||
|
||||
|
||||
class CPUTracker:
|
||||
class Tracker:
|
||||
def __init__(self):
|
||||
self.cpu_data = deque(maxlen=MAX_POINTS)
|
||||
self.ram_data = deque(maxlen=MAX_POINTS)
|
||||
self.time_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_read_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_write_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_sent_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_recv_data = deque(maxlen=MAX_POINTS)
|
||||
self._last_cpu = None
|
||||
self._last_net_sent = None
|
||||
self._last_net_recv = None
|
||||
self._last_disk_read = None
|
||||
self._last_disk_write = None
|
||||
now = time.time()
|
||||
self.time_data = deque(maxlen=MAX_POINTS)
|
||||
self.time_data.append(now)
|
||||
|
||||
def _net_rate(self, curr, last):
|
||||
delta = curr - last
|
||||
rate = max(delta / 2.0, 0)
|
||||
return max(int(rate), 0)
|
||||
|
||||
def update(self):
|
||||
cpu = psutil.cpu_percent(interval=None)
|
||||
ram = psutil.virtual_memory().percent
|
||||
disk = psutil.disk_usage('/').percent
|
||||
self._last_cpu = cpu
|
||||
t = time.time()
|
||||
self.time_data.append(t)
|
||||
|
||||
self.cpu_data.append(cpu)
|
||||
self.ram_data.append(ram)
|
||||
self.time_data.append(t)
|
||||
self.disk_data.append(disk)
|
||||
|
||||
d_io = psutil.disk_io_counters()
|
||||
if d_io is not None:
|
||||
d_read = d_io.read_bytes
|
||||
d_write = d_io.write_bytes
|
||||
if self._last_disk_read is not None:
|
||||
self.disk_read_data.append(max(int((d_read - self._last_disk_read) / 2.0), 0))
|
||||
self.disk_write_data.append(max(int((d_write - self._last_disk_write) / 2.0), 0))
|
||||
self._last_disk_read = d_read
|
||||
self._last_disk_write = d_write
|
||||
|
||||
net = psutil.net_io_counters()
|
||||
sent = net.bytes_sent
|
||||
recv = net.bytes_recv
|
||||
if self._last_net_sent is not None:
|
||||
send_rate = self._net_rate(sent, self._last_net_sent)
|
||||
recv_rate = self._net_rate(recv, self._last_net_recv)
|
||||
self.net_sent_data.append(send_rate)
|
||||
self.net_recv_data.append(recv_rate)
|
||||
self._last_net_sent = sent
|
||||
self._last_net_recv = recv
|
||||
|
||||
def get_latest(self):
|
||||
if self._last_cpu is None:
|
||||
self.update()
|
||||
return self._last_cpu, self.ram_data[-1]
|
||||
|
||||
def get_disk(self):
|
||||
if not self.disk_data:
|
||||
return 0
|
||||
return self.disk_data[-1]
|
||||
|
||||
def get_disk_rates(self):
|
||||
if not self.disk_read_data or not self.disk_write_data:
|
||||
return 0, 0
|
||||
return self.disk_read_data[-1], self.disk_write_data[-1]
|
||||
|
||||
def get_net_rates(self):
|
||||
if not self.net_sent_data or not self.net_recv_data:
|
||||
return 0, 0
|
||||
return self.net_sent_data[-1], self.net_recv_data[-1]
|
||||
|
||||
|
||||
class App:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("CPU / RAM Monitor")
|
||||
|
||||
self.tracker = CPUTracker()
|
||||
self.tracker = Tracker()
|
||||
|
||||
# --- Header card ---
|
||||
card_bg = "#23272f"
|
||||
@@ -70,25 +122,56 @@ class App:
|
||||
)
|
||||
self.ram_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.net_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"Net: ↓ --",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground="#ffb74d",
|
||||
)
|
||||
self.net_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.disk_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"Disk: --%",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground="#ba68c8",
|
||||
)
|
||||
self.disk_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
# --- Plot ---
|
||||
fig = Figure(figsize=(8, 3), facecolor=card_bg)
|
||||
ax_cpu = fig.add_subplot(1, 2, 1, facecolor=card_bg)
|
||||
ax_ram = fig.add_subplot(1, 2, 2, facecolor=card_bg)
|
||||
fig = Figure(figsize=(14, 3), facecolor=card_bg)
|
||||
ax_cpu = fig.add_subplot(1, 4, 1, facecolor=card_bg)
|
||||
ax_ram = fig.add_subplot(1, 4, 2, facecolor=card_bg)
|
||||
ax_disk = fig.add_subplot(1, 4, 3, facecolor=card_bg)
|
||||
ax_net = fig.add_subplot(1, 4, 4, facecolor=card_bg)
|
||||
|
||||
ax_cpu.set_title("CPU %", color=card_fg, fontsize=11)
|
||||
ax_ram.set_title("RAM %", color=card_fg, fontsize=11)
|
||||
ax_disk.set_title("Disk %", color=card_fg, fontsize=11)
|
||||
ax_net.set_title("Réseau (B/s)", color=card_fg, fontsize=11)
|
||||
ax_cpu.set_ylim(0, 100)
|
||||
ax_ram.set_ylim(0, 100)
|
||||
ax_disk.set_ylim(0, 100)
|
||||
ax_net.set_ylim(0, 1)
|
||||
ax_cpu.set_ylabel("%")
|
||||
ax_ram.set_ylabel("%")
|
||||
ax_disk.set_ylabel("%")
|
||||
ax_net.set_ylabel("B/s")
|
||||
ax_cpu.tick_params(colors="#aaa")
|
||||
ax_ram.tick_params(colors="#aaa")
|
||||
ax_net.tick_params(colors="#aaa")
|
||||
for label in ax_cpu.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for label in ax_ram.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for label in ax_net.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for line in ax_cpu.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
for line in ax_ram.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
for line in ax_net.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
|
||||
self.cpu_line, = ax_cpu.plot(
|
||||
[], [], color="#ef5350", linewidth=1.5, marker="", markerfacecolor="#ef5350"
|
||||
@@ -96,14 +179,26 @@ class App:
|
||||
self.ram_line, = ax_ram.plot(
|
||||
[], [], color="#66bb6a", linewidth=1.5, marker="", markerfacecolor="#66bb6a"
|
||||
)
|
||||
self.disk_line, = ax_disk.plot(
|
||||
[], [], color="#ba68c8", linewidth=1.5, marker="", markerfacecolor="#ba68c8"
|
||||
)
|
||||
self.net_sent_line, = ax_net.plot(
|
||||
[], [], color="#ffb74d", linewidth=1.5, marker="", markerfacecolor="#ffb74d"
|
||||
)
|
||||
self.net_recv_line, = ax_net.plot(
|
||||
[], [], color="#90caf9", linewidth=1.5, marker="", markerfacecolor="#90caf9"
|
||||
)
|
||||
|
||||
ax_cpu.axhline(y=80, color="#ef5350", linestyle="--", alpha=0.4)
|
||||
ax_ram.axhline(y=80, color="#66bb6a", linestyle="--", alpha=0.4)
|
||||
ax_disk.axhline(y=80, color="#ba68c8", linestyle="--", alpha=0.4)
|
||||
ax_cpu.text(0.02, 0.02, "80%", fontsize=8, color="#ef5350", alpha=0.6, transform=ax_cpu.transAxes)
|
||||
|
||||
self.fig = fig
|
||||
self.ax_cpu = ax_cpu
|
||||
self.ax_ram = ax_ram
|
||||
self.ax_disk = ax_disk
|
||||
self.ax_net = ax_net
|
||||
|
||||
canvas = FigureCanvasTkAgg(fig, master=root)
|
||||
canvas.draw()
|
||||
@@ -140,17 +235,35 @@ class App:
|
||||
return
|
||||
self.tracker.update()
|
||||
cpu, ram = self.tracker.get_latest()
|
||||
disk = self.tracker.get_disk()
|
||||
send_rate, recv_rate = self.tracker.get_net_rates()
|
||||
self.cpu_label.config(text=f"CPU: {cpu:5.1f}%")
|
||||
self.ram_label.config(text=f"RAM: {ram:5.1f}%")
|
||||
self.disk_label.config(text=f"Disk: {disk:5.1f}%")
|
||||
|
||||
mb_sent = send_rate / (1024 * 1024)
|
||||
mb_recv = recv_rate / (1024 * 1024)
|
||||
self.net_label.config(text=f"Net: ↑{mb_sent:.2f} ↓{mb_recv:.2f} MB/s")
|
||||
|
||||
ax = self.ax_cpu
|
||||
cpu_arr = list(self.tracker.cpu_data)
|
||||
ram_arr = list(self.tracker.ram_data)
|
||||
disk_arr = list(self.tracker.disk_data)
|
||||
sent_arr = list(self.tracker.net_sent_data)
|
||||
recv_arr = list(self.tracker.net_recv_data)
|
||||
self.cpu_line.set_data(range(len(cpu_arr)), cpu_arr)
|
||||
self.ram_line.set_data(range(len(ram_arr)), ram_arr)
|
||||
self.disk_line.set_data(range(len(disk_arr)), disk_arr)
|
||||
self.net_sent_line.set_data(range(len(sent_arr)), sent_arr)
|
||||
self.net_recv_line.set_data(range(len(recv_arr)), recv_arr)
|
||||
|
||||
ax.set_xlim(0, MAX_POINTS)
|
||||
self.ax_cpu.set_xlim(0, MAX_POINTS)
|
||||
self.ax_ram.set_xlim(0, MAX_POINTS)
|
||||
self.ax_disk.set_xlim(0, MAX_POINTS)
|
||||
self.ax_net.set_xlim(0, MAX_POINTS)
|
||||
|
||||
max_net = max(max(sent_arr) if sent_arr else 0, max(recv_arr) if recv_arr else 0)
|
||||
if max_net > 0:
|
||||
self.ax_net.set_ylim(0, max_net * 1.2)
|
||||
|
||||
self.fig.canvas.draw_idle()
|
||||
self.root.after(UPDATE_INTERVAL, self._refresh)
|
||||
|
||||
4
cpu_monitor_gui.sh
Executable file
4
cpu_monitor_gui.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
export DISPLAY=:1
|
||||
export GDK_BACKEND=wayland,x11
|
||||
/home/tmzf5455/projects/continue-lab/.venv/bin/python /home/tmzf5455/projects/continue-lab/cpu_monitor_gui.py
|
||||
252
cpu_monitor_native.py
Normal file
252
cpu_monitor_native.py
Normal file
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env python3
|
||||
# Lancement: python cpu_monitor_native.py
|
||||
# Intégrable dans GNOME via /etc/xdg/autostart/resource-monitor.desktop
|
||||
|
||||
from collections import deque
|
||||
import time
|
||||
|
||||
from gi.repository import Gtk, GLib
|
||||
import psutil
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk4agg import FigureCanvasGTK4Agg as FigureCanvas
|
||||
|
||||
MAX_POINTS = 60
|
||||
UPDATE_INTERVAL = 1000 # ms
|
||||
|
||||
|
||||
class Tracker:
|
||||
def __init__(self):
|
||||
self.cpu_data = deque(maxlen=MAX_POINTS)
|
||||
self.ram_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_read_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_write_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_sent_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_recv_data = deque(maxlen=MAX_POINTS)
|
||||
self._last_cpu = None
|
||||
self._last_net_sent = None
|
||||
self._last_net_recv = None
|
||||
self._last_disk_read = None
|
||||
self._last_disk_write = None
|
||||
self.time_data = deque(maxlen=MAX_POINTS)
|
||||
self.time_data.append(time.time())
|
||||
|
||||
def _rate(self, curr, last):
|
||||
delta = curr - last
|
||||
return max(int(delta / 2.0), 0)
|
||||
|
||||
def update(self):
|
||||
cpu = psutil.cpu_percent(interval=None)
|
||||
ram = psutil.virtual_memory().percent
|
||||
disk = psutil.disk_usage('/').percent
|
||||
self._last_cpu = cpu
|
||||
t = time.time()
|
||||
self.time_data.append(t)
|
||||
|
||||
self.cpu_data.append(cpu)
|
||||
self.ram_data.append(ram)
|
||||
self.disk_data.append(disk)
|
||||
|
||||
d_io = psutil.disk_io_counters()
|
||||
if d_io is not None:
|
||||
d_read = d_io.read_bytes
|
||||
d_write = d_io.write_bytes
|
||||
if self._last_disk_read is not None:
|
||||
self.disk_read_data.append(self._rate(d_read, self._last_disk_read))
|
||||
self.disk_write_data.append(self._rate(d_write, self._last_disk_write))
|
||||
self._last_disk_read = d_read
|
||||
self._last_disk_write = d_write
|
||||
|
||||
net = psutil.net_io_counters()
|
||||
sent = net.bytes_sent
|
||||
recv = net.bytes_recv
|
||||
if self._last_net_sent is not None:
|
||||
self.net_sent_data.append(self._rate(sent, self._last_net_sent))
|
||||
self.net_recv_data.append(self._rate(recv, self._last_net_recv))
|
||||
self._last_net_sent = sent
|
||||
self._last_net_recv = recv
|
||||
|
||||
def get_latest(self):
|
||||
if self._last_cpu is None:
|
||||
self.update()
|
||||
return self._last_cpu, self.ram_data[-1]
|
||||
|
||||
def get_disk(self):
|
||||
if not self.disk_data:
|
||||
return 0
|
||||
return self.disk_data[-1]
|
||||
|
||||
def get_net_rates(self):
|
||||
if not self.net_sent_data or not self.net_recv_data:
|
||||
return 0, 0
|
||||
return self.net_sent_data[-1], self.net_recv_data[-1]
|
||||
|
||||
|
||||
class MonitorWindow(Gtk.ApplicationWindow):
|
||||
def __init__(self, app):
|
||||
super().__init__(application=app, title="Resource Monitor")
|
||||
self.set_default_size(1100, 360)
|
||||
self.set_icon_name("org.gnome.SystemMonitor")
|
||||
|
||||
self.tracker = Tracker()
|
||||
self._running = True
|
||||
|
||||
# Dark palette
|
||||
self.DARK_BG = "#1e1e2e"
|
||||
self.DARK_SURFACE = "#313244"
|
||||
self.DARK_BORDER = "#45475a"
|
||||
self.TEXT = "#cdd6f4"
|
||||
self.TEXT_DIM = "#a6adc8"
|
||||
self.CPU_COLOR = "#f38ba8"
|
||||
self.RAM_COLOR = "#a6e3a1"
|
||||
self.DISK_COLOR = "#cba6f7"
|
||||
self.NET_UP_COLOR = "#fab387"
|
||||
self.NET_DOWN_COLOR = "#89b4fa"
|
||||
self.ALPHA_40 = 0.4
|
||||
|
||||
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||
self.add(box)
|
||||
|
||||
# --- Top bar with values ---
|
||||
header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
|
||||
header.set_css_classes(["sourcing-frame"])
|
||||
header.get_style_context().add_class("card")
|
||||
header.add_to_css_styleclass("monitor-header")
|
||||
|
||||
self.cpu_label = Gtk.Label()
|
||||
self.cpu_label.set_css_classes(["stat-label"])
|
||||
header.append(self.cpu_label)
|
||||
|
||||
self.ram_label = Gtk.Label()
|
||||
self.ram_label.set_css_classes(["stat-label"])
|
||||
header.append(self.ram_label)
|
||||
|
||||
self.disk_label = Gtk.Label()
|
||||
self.disk_label.set_css_classes(["stat-label"])
|
||||
header.append(self.disk_label)
|
||||
|
||||
self.net_label = Gtk.Label()
|
||||
self.net_label.set_css_classes(["stat-label"])
|
||||
header.append(self.net_label)
|
||||
|
||||
box.append(header)
|
||||
|
||||
# --- Plots ---
|
||||
fig = Figure(figsize=(13, 3.2), facecolor=self.DARK_BG)
|
||||
fig.set_tight_layout({"pad": 8})
|
||||
|
||||
axes = []
|
||||
titles = ["CPU %", "RAM %", "Disk %", "Réseau (B/s)"]
|
||||
for i, title in enumerate(titles):
|
||||
ax = fig.add_subplot(1, 4, i + 1)
|
||||
ax.set_facecolor(self.DARK_BG)
|
||||
ax.set_title(title, color=self.TEXT, fontsize=11, fontweight="medium")
|
||||
ax.set_ylim(0, 100)
|
||||
ax.set_ylabel("%" if i < 3 else "B/s", color=self.TEXT_DIM, fontsize=9)
|
||||
ax.tick_params(colors=self.TEXT_DIM)
|
||||
ax.spines["bottom"].set_color(self.DARK_BORDER)
|
||||
ax.spines["top"].set_color(self.DARK_BORDER)
|
||||
ax.spines["left"].set_color(self.DARK_BORDER)
|
||||
ax.spines["right"].set_color(self.DARK_BORDER)
|
||||
axes.append(ax)
|
||||
|
||||
self.cpu_line, = axes[0].plot([], [], color=self.CPU_COLOR, linewidth=1.5)
|
||||
self.ram_line, = axes[1].plot([], [], color=self.RAM_COLOR, linewidth=1.5)
|
||||
self.disk_line, = axes[2].plot([], [], color=self.DISK_COLOR, linewidth=1.5)
|
||||
self.net_up_line, = axes[3].plot([], [], color=self.NET_UP_COLOR, linewidth=1.5, label="↑")
|
||||
self.net_down_line, = axes[3].plot([], [], color=self.NET_DOWN_COLOR, linewidth=1.5, label="↓")
|
||||
|
||||
for ax in axes[:3]:
|
||||
ax.axhline(y=80, color=ax.get_lines()[0].get_color(), linestyle="--", alpha=self.ALPHA_40)
|
||||
|
||||
canvas = FigureCanvas(fig)
|
||||
canvas.set_css_classes(["plot-canvas"])
|
||||
box.append(canvas)
|
||||
|
||||
# --- Footer ---
|
||||
footer = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
|
||||
footer.set_valign(Gtk.Align.END)
|
||||
footer.get_style_context().add_class("linked")
|
||||
|
||||
self.status_label = Gtk.Label(label="Monitoring...")
|
||||
self.status_label.set_css_classes(["dim-label"])
|
||||
footer.append(self.status_label)
|
||||
|
||||
self.stop_btn = Gtk.Button(label="Arrêter")
|
||||
self.stop_btn.set_css_classes(["destructive-action"])
|
||||
self.stop_btn.connect("clicked", lambda *_: self._stop())
|
||||
footer.append(self.stop_btn)
|
||||
|
||||
box.append(footer)
|
||||
|
||||
self.fig = fig
|
||||
self.axes = axes
|
||||
self.canvas = canvas
|
||||
|
||||
GLib.timeout_add(UPDATE_INTERVAL, self._refresh)
|
||||
|
||||
def _update_plot(self):
|
||||
cpu_arr = list(self.tracker.cpu_data)
|
||||
ram_arr = list(self.tracker.ram_data)
|
||||
disk_arr = list(self.tracker.disk_data)
|
||||
sent_arr = list(self.tracker.net_sent_data)
|
||||
recv_arr = list(self.tracker.net_recv_data)
|
||||
|
||||
self.cpu_line.set_data(range(len(cpu_arr)), cpu_arr)
|
||||
self.ram_line.set_data(range(len(ram_arr)), ram_arr)
|
||||
self.disk_line.set_data(range(len(disk_arr)), disk_arr)
|
||||
self.net_up_line.set_data(range(len(sent_arr)), sent_arr)
|
||||
self.net_down_line.set_data(range(len(recv_arr)), recv_arr)
|
||||
|
||||
for i, ax in enumerate(self.axes[:3]):
|
||||
ax.set_xlim(0, MAX_POINTS)
|
||||
|
||||
max_net = max(max(sent_arr) if sent_arr else 0, max(recv_arr) if recv_arr else 0)
|
||||
self.axes[3].set_xlim(0, MAX_POINTS)
|
||||
if max_net > 0:
|
||||
self.axes[3].set_ylim(0, max_net * 1.2)
|
||||
|
||||
self.fig.canvas.draw()
|
||||
|
||||
def _refresh(self):
|
||||
if not self._running:
|
||||
return GLib.SOURCE_REMOVE
|
||||
|
||||
self.tracker.update()
|
||||
cpu, ram = self.tracker.get_latest()
|
||||
disk = self.tracker.get_disk()
|
||||
send_rate, recv_rate = self.tracker.get_net_rates()
|
||||
|
||||
self.cpu_label.set_label(f"CPU: {cpu:5.1f}%")
|
||||
self.ram_label.set_label(f"RAM: {ram:5.1f}%")
|
||||
self.disk_label.set_label(f"Disk: {disk:5.1f}%")
|
||||
|
||||
mb_up = send_rate / (1024 * 1024)
|
||||
mb_dn = recv_rate / (1024 * 1024)
|
||||
self.net_label.set_label(f"Net: ↑{mb_up:.2f} ↓{mb_dn:.2f} MB/s")
|
||||
|
||||
self._update_plot()
|
||||
return GLib.SOURCE_CONTINUE
|
||||
|
||||
def _stop(self, *_):
|
||||
self._running = False
|
||||
self.status_label.set_label("Arrêté.")
|
||||
self.stop_btn.set_sensitive(False)
|
||||
|
||||
|
||||
class MonitorApplication(Gtk.Application):
|
||||
def __init__(self):
|
||||
super().__init__(application_id="com.local.resource-monitor")
|
||||
|
||||
def do_activate(self):
|
||||
win = MonitorWindow(self)
|
||||
win.present()
|
||||
|
||||
|
||||
def main():
|
||||
app = MonitorApplication()
|
||||
app.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
5
debian/.debhelper/generated/cpu-monitor/dh_installchangelogs.dch.trimmed
vendored
Normal file
5
debian/.debhelper/generated/cpu-monitor/dh_installchangelogs.dch.trimmed
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
cpu-monitor (1.0) stable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- tmzf5455 <tmzf5455> Sat, 09 May 2026 10:00:00 +0000
|
||||
0
debian/.debhelper/generated/cpu-monitor/installed-by-dh_installdocs
vendored
Normal file
0
debian/.debhelper/generated/cpu-monitor/installed-by-dh_installdocs
vendored
Normal file
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
cpu-monitor (1.0) stable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- tmzf5455 <tmzf5455> Sat, 09 May 2026 10:00:00 +0000
|
||||
13
debian/control
vendored
Normal file
13
debian/control
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
Source: cpu-monitor
|
||||
Section: python
|
||||
Priority: optional
|
||||
Maintainer: tmzf5455 <tmzf5455>
|
||||
Build-Depends: debhelper-compat (= 13)
|
||||
Standards-Version: 4.1.4
|
||||
|
||||
Package: cpu-monitor
|
||||
Maintainer: tmzf5455 <tmzf5455>
|
||||
Architecture: all
|
||||
Depends: python3, python3-psutil, python3-matplotlib, python3-tk, x11-utils, ${misc:Depends}
|
||||
Description: CPU Monitor GUI
|
||||
A Python GUI application for monitoring CPU usage in real-time.
|
||||
2
debian/cpu-monitor.substvars
vendored
Normal file
2
debian/cpu-monitor.substvars
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
misc:Depends=
|
||||
misc:Pre-Depends=
|
||||
10
debian/cpu-monitor/DEBIAN/control
vendored
Normal file
10
debian/cpu-monitor/DEBIAN/control
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
Package: cpu-monitor
|
||||
Version: 1.0
|
||||
Architecture: all
|
||||
Maintainer: tmzf5455 <tmzf5455>
|
||||
Installed-Size: 20
|
||||
Depends: python3, python3-psutil, python3-matplotlib, python3-tk, x11-utils
|
||||
Section: python
|
||||
Priority: optional
|
||||
Description: CPU Monitor GUI
|
||||
A Python GUI application for monitoring CPU usage in real-time.
|
||||
3
debian/cpu-monitor/DEBIAN/md5sums
vendored
Normal file
3
debian/cpu-monitor/DEBIAN/md5sums
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
3bb2a78f10db731e82226d58d83c7d31 usr/bin/cpu-monitor
|
||||
b40607068b416aad76a36519e068e13a usr/share/applications/cpu-monitor.desktop
|
||||
417d73b9352097d7166b96829dc5a863 usr/share/doc/cpu-monitor/changelog.gz
|
||||
283
debian/cpu-monitor/usr/bin/cpu-monitor
vendored
Executable file
283
debian/cpu-monitor/usr/bin/cpu-monitor
vendored
Executable file
@@ -0,0 +1,283 @@
|
||||
#!/usr/bin/env python3
|
||||
# Lancement: python cpu_monitor_gui.py
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
|
||||
from matplotlib.figure import Figure
|
||||
from collections import deque
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
MAX_POINTS = 60
|
||||
UPDATE_INTERVAL = 1000 # ms
|
||||
|
||||
|
||||
class Tracker:
|
||||
def __init__(self):
|
||||
self.cpu_data = deque(maxlen=MAX_POINTS)
|
||||
self.ram_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_read_data = deque(maxlen=MAX_POINTS)
|
||||
self.disk_write_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_sent_data = deque(maxlen=MAX_POINTS)
|
||||
self.net_recv_data = deque(maxlen=MAX_POINTS)
|
||||
self._last_cpu = None
|
||||
self._last_net_sent = None
|
||||
self._last_net_recv = None
|
||||
self._last_disk_read = None
|
||||
self._last_disk_write = None
|
||||
now = time.time()
|
||||
self.time_data = deque(maxlen=MAX_POINTS)
|
||||
self.time_data.append(now)
|
||||
|
||||
def _net_rate(self, curr, last):
|
||||
delta = curr - last
|
||||
rate = max(delta / 2.0, 0)
|
||||
return max(int(rate), 0)
|
||||
|
||||
def update(self):
|
||||
cpu = psutil.cpu_percent(interval=None)
|
||||
ram = psutil.virtual_memory().percent
|
||||
disk = psutil.disk_usage('/').percent
|
||||
self._last_cpu = cpu
|
||||
t = time.time()
|
||||
self.time_data.append(t)
|
||||
|
||||
self.cpu_data.append(cpu)
|
||||
self.ram_data.append(ram)
|
||||
self.disk_data.append(disk)
|
||||
|
||||
d_io = psutil.disk_io_counters()
|
||||
if d_io is not None:
|
||||
d_read = d_io.read_bytes
|
||||
d_write = d_io.write_bytes
|
||||
if self._last_disk_read is not None:
|
||||
self.disk_read_data.append(max(int((d_read - self._last_disk_read) / 2.0), 0))
|
||||
self.disk_write_data.append(max(int((d_write - self._last_disk_write) / 2.0), 0))
|
||||
self._last_disk_read = d_read
|
||||
self._last_disk_write = d_write
|
||||
|
||||
net = psutil.net_io_counters()
|
||||
sent = net.bytes_sent
|
||||
recv = net.bytes_recv
|
||||
if self._last_net_sent is not None:
|
||||
send_rate = self._net_rate(sent, self._last_net_sent)
|
||||
recv_rate = self._net_rate(recv, self._last_net_recv)
|
||||
self.net_sent_data.append(send_rate)
|
||||
self.net_recv_data.append(recv_rate)
|
||||
self._last_net_sent = sent
|
||||
self._last_net_recv = recv
|
||||
|
||||
def get_latest(self):
|
||||
if self._last_cpu is None:
|
||||
self.update()
|
||||
return self._last_cpu, self.ram_data[-1]
|
||||
|
||||
def get_disk(self):
|
||||
if not self.disk_data:
|
||||
return 0
|
||||
return self.disk_data[-1]
|
||||
|
||||
def get_disk_rates(self):
|
||||
if not self.disk_read_data or not self.disk_write_data:
|
||||
return 0, 0
|
||||
return self.disk_read_data[-1], self.disk_write_data[-1]
|
||||
|
||||
def get_net_rates(self):
|
||||
if not self.net_sent_data or not self.net_recv_data:
|
||||
return 0, 0
|
||||
return self.net_sent_data[-1], self.net_recv_data[-1]
|
||||
|
||||
|
||||
class App:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("CPU / RAM Monitor")
|
||||
|
||||
self.tracker = Tracker()
|
||||
|
||||
# --- Header card ---
|
||||
card_bg = "#23272f"
|
||||
card_fg = "#ffffff"
|
||||
accent = "#4fc3f7"
|
||||
|
||||
header_frame = ttk.Frame(root)
|
||||
header_frame.pack(fill=tk.X, padx=10, pady=(10, 0))
|
||||
|
||||
self.cpu_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"CPU: --%",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground=accent,
|
||||
)
|
||||
self.cpu_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.ram_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"RAM: --%",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground="#81c784",
|
||||
)
|
||||
self.ram_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.net_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"Net: ↓ --",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground="#ffb74d",
|
||||
)
|
||||
self.net_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
self.disk_label = ttk.Label(
|
||||
header_frame,
|
||||
text=f"Disk: --%",
|
||||
font=("Segoe UI", 20, "bold"),
|
||||
foreground="#ba68c8",
|
||||
)
|
||||
self.disk_label.pack(side=tk.LEFT, padx=20)
|
||||
|
||||
# --- Plot ---
|
||||
fig = Figure(figsize=(14, 3), facecolor=card_bg)
|
||||
ax_cpu = fig.add_subplot(1, 4, 1, facecolor=card_bg)
|
||||
ax_ram = fig.add_subplot(1, 4, 2, facecolor=card_bg)
|
||||
ax_disk = fig.add_subplot(1, 4, 3, facecolor=card_bg)
|
||||
ax_net = fig.add_subplot(1, 4, 4, facecolor=card_bg)
|
||||
|
||||
ax_cpu.set_title("CPU %", color=card_fg, fontsize=11)
|
||||
ax_ram.set_title("RAM %", color=card_fg, fontsize=11)
|
||||
ax_disk.set_title("Disk %", color=card_fg, fontsize=11)
|
||||
ax_net.set_title("Réseau (B/s)", color=card_fg, fontsize=11)
|
||||
ax_cpu.set_ylim(0, 100)
|
||||
ax_ram.set_ylim(0, 100)
|
||||
ax_disk.set_ylim(0, 100)
|
||||
ax_net.set_ylim(0, 1)
|
||||
ax_cpu.set_ylabel("%")
|
||||
ax_ram.set_ylabel("%")
|
||||
ax_disk.set_ylabel("%")
|
||||
ax_net.set_ylabel("B/s")
|
||||
ax_cpu.tick_params(colors="#aaa")
|
||||
ax_ram.tick_params(colors="#aaa")
|
||||
ax_net.tick_params(colors="#aaa")
|
||||
for label in ax_cpu.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for label in ax_ram.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for label in ax_net.get_yticklabels():
|
||||
label.set_color("#aaa")
|
||||
for line in ax_cpu.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
for line in ax_ram.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
for line in ax_net.spines.values():
|
||||
line.set_color("#3a3f4a")
|
||||
|
||||
self.cpu_line, = ax_cpu.plot(
|
||||
[], [], color="#ef5350", linewidth=1.5, marker="", markerfacecolor="#ef5350"
|
||||
)
|
||||
self.ram_line, = ax_ram.plot(
|
||||
[], [], color="#66bb6a", linewidth=1.5, marker="", markerfacecolor="#66bb6a"
|
||||
)
|
||||
self.disk_line, = ax_disk.plot(
|
||||
[], [], color="#ba68c8", linewidth=1.5, marker="", markerfacecolor="#ba68c8"
|
||||
)
|
||||
self.net_sent_line, = ax_net.plot(
|
||||
[], [], color="#ffb74d", linewidth=1.5, marker="", markerfacecolor="#ffb74d"
|
||||
)
|
||||
self.net_recv_line, = ax_net.plot(
|
||||
[], [], color="#90caf9", linewidth=1.5, marker="", markerfacecolor="#90caf9"
|
||||
)
|
||||
|
||||
ax_cpu.axhline(y=80, color="#ef5350", linestyle="--", alpha=0.4)
|
||||
ax_ram.axhline(y=80, color="#66bb6a", linestyle="--", alpha=0.4)
|
||||
ax_disk.axhline(y=80, color="#ba68c8", linestyle="--", alpha=0.4)
|
||||
ax_cpu.text(0.02, 0.02, "80%", fontsize=8, color="#ef5350", alpha=0.6, transform=ax_cpu.transAxes)
|
||||
|
||||
self.fig = fig
|
||||
self.ax_cpu = ax_cpu
|
||||
self.ax_ram = ax_ram
|
||||
self.ax_disk = ax_disk
|
||||
self.ax_net = ax_net
|
||||
|
||||
canvas = FigureCanvasTkAgg(fig, master=root)
|
||||
canvas.draw()
|
||||
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||
|
||||
toolbar = NavigationToolbar2Tk(canvas, root)
|
||||
toolbar.update()
|
||||
|
||||
# --- Footer status ---
|
||||
status_frame = ttk.Frame(root)
|
||||
status_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
|
||||
|
||||
self.status_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Monitoring...",
|
||||
font=("Segoe UI", 9),
|
||||
foreground="#888",
|
||||
)
|
||||
self.status_label.pack(side=tk.LEFT)
|
||||
|
||||
stop_btn = ttk.Button(
|
||||
status_frame,
|
||||
text="Stop",
|
||||
command=self._stop,
|
||||
width=10,
|
||||
)
|
||||
stop_btn.pack(side=tk.RIGHT, padx=(10, 0))
|
||||
|
||||
self._running = True
|
||||
self._refresh()
|
||||
|
||||
def _refresh(self):
|
||||
if not self._running:
|
||||
return
|
||||
self.tracker.update()
|
||||
cpu, ram = self.tracker.get_latest()
|
||||
disk = self.tracker.get_disk()
|
||||
send_rate, recv_rate = self.tracker.get_net_rates()
|
||||
self.cpu_label.config(text=f"CPU: {cpu:5.1f}%")
|
||||
self.ram_label.config(text=f"RAM: {ram:5.1f}%")
|
||||
self.disk_label.config(text=f"Disk: {disk:5.1f}%")
|
||||
|
||||
mb_sent = send_rate / (1024 * 1024)
|
||||
mb_recv = recv_rate / (1024 * 1024)
|
||||
self.net_label.config(text=f"Net: ↑{mb_sent:.2f} ↓{mb_recv:.2f} MB/s")
|
||||
|
||||
cpu_arr = list(self.tracker.cpu_data)
|
||||
ram_arr = list(self.tracker.ram_data)
|
||||
disk_arr = list(self.tracker.disk_data)
|
||||
sent_arr = list(self.tracker.net_sent_data)
|
||||
recv_arr = list(self.tracker.net_recv_data)
|
||||
self.cpu_line.set_data(range(len(cpu_arr)), cpu_arr)
|
||||
self.ram_line.set_data(range(len(ram_arr)), ram_arr)
|
||||
self.disk_line.set_data(range(len(disk_arr)), disk_arr)
|
||||
self.net_sent_line.set_data(range(len(sent_arr)), sent_arr)
|
||||
self.net_recv_line.set_data(range(len(recv_arr)), recv_arr)
|
||||
|
||||
self.ax_cpu.set_xlim(0, MAX_POINTS)
|
||||
self.ax_ram.set_xlim(0, MAX_POINTS)
|
||||
self.ax_disk.set_xlim(0, MAX_POINTS)
|
||||
self.ax_net.set_xlim(0, MAX_POINTS)
|
||||
|
||||
max_net = max(max(sent_arr) if sent_arr else 0, max(recv_arr) if recv_arr else 0)
|
||||
if max_net > 0:
|
||||
self.ax_net.set_ylim(0, max_net * 1.2)
|
||||
|
||||
self.fig.canvas.draw_idle()
|
||||
self.root.after(UPDATE_INTERVAL, self._refresh)
|
||||
|
||||
def _stop(self):
|
||||
self._running = False
|
||||
self.status_label.config(text="Stopped.")
|
||||
|
||||
|
||||
def main():
|
||||
root = tk.Tk()
|
||||
app = App(root)
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
debian/cpu-monitor/usr/share/applications/cpu-monitor.desktop
vendored
Normal file
9
debian/cpu-monitor/usr/share/applications/cpu-monitor.desktop
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=/usr/bin/cpu-monitor
|
||||
Hidden=false
|
||||
NoDisplay=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
Name=CPU Monitor GUI
|
||||
Comment=CPU/RAM/Disk/Network monitor
|
||||
Icon=utilities-system-monitor
|
||||
BIN
debian/cpu-monitor/usr/share/doc/cpu-monitor/changelog.gz
vendored
Normal file
BIN
debian/cpu-monitor/usr/share/doc/cpu-monitor/changelog.gz
vendored
Normal file
Binary file not shown.
1
debian/debhelper-build-stamp
vendored
Normal file
1
debian/debhelper-build-stamp
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cpu-monitor
|
||||
2
debian/files
vendored
Normal file
2
debian/files
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
cpu-monitor_1.0_all.deb python optional
|
||||
cpu-monitor_1.0_arm64.buildinfo python optional
|
||||
8
debian/rules
vendored
Executable file
8
debian/rules
vendored
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_install:
|
||||
install -D -m 0755 cpu_monitor_gui.py $(CURDIR)/debian/cpu-monitor/usr/bin/cpu-monitor
|
||||
install -D -m 0644 cpu_monitor_gui.desktop $(CURDIR)/debian/cpu-monitor/usr/share/applications/cpu-monitor.desktop
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3.0 (native)
|
||||
Reference in New Issue
Block a user