# monitor_logic.py import psutil import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure import os # --- Variables Globales y Estado Inicial --- MAX_SAMPLES = 60 historical_data = { 'time': list(range(1, MAX_SAMPLES + 1)), 'cpu': [0] * MAX_SAMPLES, 'memory': [0] * MAX_SAMPLES, 'disk': [0] * MAX_SAMPLES, 'net_sent': [0] * MAX_SAMPLES, 'net_recv': [0] * MAX_SAMPLES } LAST_NET_COUNTERS = psutil.net_io_counters() CURRENT_PROCESS = psutil.Process(os.getpid()) def initialize_monitor_figures(): """ Define y devuelve los objetos de figura, ejes y líneas de Matplotlib. Esto permite inicializar el monitor una sola vez al inicio. """ # --- Gráfico de Uso del Sistema (CPU, Memoria, Disco) --- fig_usage = Figure(figsize=(4, 6), dpi=100) fig_usage.subplots_adjust(hspace=0.5) ax1 = fig_usage.add_subplot(311) line_cpu, = ax1.plot(historical_data['time'], historical_data['cpu'], 'r-') ax1.set_title("Uso de CPU (%)", fontsize=10); ax1.set_ylabel("CPU (%)", fontsize=8); ax1.set_ylim(0, 100); ax1.set_xlim(1, MAX_SAMPLES); ax1.grid(True); ax1.tick_params(axis='x', labelbottom=False) ax2 = fig_usage.add_subplot(312, sharex=ax1) line_mem, = ax2.plot(historical_data['time'], historical_data['memory'], 'b-') ax2.set_title("Uso de Memoria (%)", fontsize=10); ax2.set_ylabel("Memoria (%)", fontsize=8); ax2.set_ylim(0, 100); ax2.set_xlim(1, MAX_SAMPLES); ax2.grid(True); ax2.tick_params(axis='x', labelbottom=False) ax3 = fig_usage.add_subplot(313, sharex=ax1) line_disk, = ax3.plot(historical_data['time'], historical_data['disk'], 'g-') ax3.set_title("Uso de Disco (%)", fontsize=10); ax3.set_xlabel("Tiempo (segundos)", fontsize=8); ax3.set_ylabel("Disco (%)", fontsize=8); ax3.set_ylim(0, 100); ax3.set_xlim(1, MAX_SAMPLES); ax3.grid(True) fig_usage.tight_layout(pad=1.5) # --- Gráfico de Red (Bytes Enviados/Recibidos) --- fig_net = Figure(figsize=(4, 6), dpi=100) fig_net.subplots_adjust(hspace=0.5) ax_net = fig_net.add_subplot(111) line_net_sent, = ax_net.plot(historical_data['time'], historical_data['net_sent'], 'm-', label='Enviado') line_net_recv, = ax_net.plot(historical_data['time'], historical_data['net_recv'], 'c-', label='Recibido') ax_net.set_title("Tráfico de Red (Bytes/s)", fontsize=10); ax_net.set_xlabel("Tiempo (segundos)", fontsize=8); ax_net.set_ylabel("Bytes/s", fontsize=8); ax_net.set_ylim(0, 500000); ax_net.set_xlim(1, MAX_SAMPLES); ax_net.legend(loc='upper left', fontsize=8); ax_net.grid(True) fig_net.tight_layout(pad=1.5) # Devuelve todos los elementos que se necesitan para la actualización return { 'fig_usage': fig_usage, 'fig_net': fig_net, 'lines': { 'cpu': line_cpu, 'mem': line_mem, 'disk': line_disk, 'net_sent': line_net_sent, 'net_recv': line_net_recv }, 'ax_net': ax_net # Para auto-escalado } def update_monitor(root, lines, ax_net, mpl_canvas_usage, mpl_canvas_net, label_load, label_threads): """ Obtiene los datos de psutil y actualiza todos los gráficos. Esta función debe ser llamada por root.after() """ global LAST_NET_COUNTERS # 1. Obtener los nuevos datos del sistema cpu_percent = psutil.cpu_percent(interval=None) mem_percent = psutil.virtual_memory().percent disk_percent = psutil.disk_usage('/').percent load_avg = os.getloadavg() if hasattr(os, 'getloadavg') else (0.0, 0.0, 0.0) thread_count = CURRENT_PROCESS.num_threads() # 2. Calcular el Tráfico de Red (Bytes/s) current_net_counters = psutil.net_io_counters() bytes_sent_rate = (current_net_counters.bytes_sent - LAST_NET_COUNTERS.bytes_sent) / 1.0 bytes_recv_rate = (current_net_counters.bytes_recv - LAST_NET_COUNTERS.bytes_recv) / 1.0 LAST_NET_COUNTERS = current_net_counters # 3. Actualizar los Labels label_load.config(text=f"Carga (1m/5m/15m): {load_avg[0]:.2f} / {load_avg[1]:.2f} / {load_avg[2]:.2f}") label_threads.config(text=f"Hilos del Proceso: {thread_count}") # 4. Actualizar datos históricos historical_data['cpu'].pop(0); historical_data['cpu'].append(cpu_percent) historical_data['memory'].pop(0); historical_data['memory'].append(mem_percent) historical_data['disk'].pop(0); historical_data['disk'].append(disk_percent) historical_data['net_sent'].pop(0); historical_data['net_sent'].append(bytes_sent_rate) historical_data['net_recv'].pop(0); historical_data['net_recv'].append(bytes_recv_rate) # 5. Actualizar las líneas de los gráficos lines['cpu'].set_ydata(historical_data['cpu']) lines['mem'].set_ydata(historical_data['memory']) lines['disk'].set_ydata(historical_data['disk']) lines['net_sent'].set_ydata(historical_data['net_sent']) lines['net_recv'].set_ydata(historical_data['net_recv']) # Auto-escalado de red max_net = max(max(historical_data['net_sent']), max(historical_data['net_recv'])) if max_net * 1.1 > ax_net.get_ylim()[1]: ax_net.set_ylim(0, max_net * 1.1) # 6. Redibujar los canvases mpl_canvas_usage.draw_idle() mpl_canvas_net.draw_idle() # 7. Llamada recursiva # Importante: se llama a sí misma en el hilo principal de Tkinter root.after(1000, update_monitor, root, lines, ax_net, mpl_canvas_usage, mpl_canvas_net, label_load, label_threads)