diff --git a/maselli_app.py b/maselli_app.py index 270b046..ef88282 100644 --- a/maselli_app.py +++ b/maselli_app.py @@ -186,7 +186,9 @@ class MaselliApp: def create_graphs(self): """Crea los gráficos para simulador y trace""" # Gráfico del simulador - sim_graph_frame = self.simulator_tab.get_graph_frame() + # get_graph_frame() ahora devuelve el contenedor LabelFrame donde debe ir el canvas. + # Este contenedor ya está posicionado por SimulatorTab.create_widgets(). + sim_graph_canvas_parent = self.simulator_tab.get_graph_frame() self.sim_fig = Figure(figsize=(8, 3.5), dpi=100) self.sim_ax1 = self.sim_fig.add_subplot(111) @@ -202,9 +204,13 @@ class MaselliApp: self.sim_line_brix, = self.sim_ax1.plot([], [], 'b-', label='Brix', linewidth=2) self.sim_line_ma, = self.sim_ax2.plot([], [], 'r-', label='mA', linewidth=2) - self.sim_canvas = FigureCanvasTkAgg(self.sim_fig, master=sim_graph_frame) + self.sim_canvas = FigureCanvasTkAgg(self.sim_fig, master=sim_graph_canvas_parent) # sim_graph_canvas_parent es un LabelFrame self.sim_canvas.draw() - self.sim_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + sim_canvas_widget = self.sim_canvas.get_tk_widget() + sim_canvas_widget.grid(row=0, column=0, sticky="nsew", padx=5, pady=5) + # Configurar el LabelFrame (sim_graph_canvas_parent) para que el canvas (su hijo) se expanda + sim_graph_canvas_parent.rowconfigure(0, weight=1) + sim_graph_canvas_parent.columnconfigure(0, weight=1) # Gráfico del trace (ahora con doble eje Y) trace_graph_frame = self.trace_tab.get_graph_frame() @@ -223,9 +229,13 @@ class MaselliApp: self.trace_line_brix, = self.trace_ax1.plot([], [], 'b-', label='Brix', linewidth=2, marker='o', markersize=4) self.trace_line_ma, = self.trace_ax2.plot([], [], 'r-', label='mA', linewidth=2, marker='s', markersize=3) - self.trace_canvas = FigureCanvasTkAgg(self.trace_fig, master=trace_graph_frame) + self.trace_canvas = FigureCanvasTkAgg(self.trace_fig, master=trace_graph_frame) # trace_graph_frame es un LabelFrame self.trace_canvas.draw() - self.trace_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + trace_canvas_widget = self.trace_canvas.get_tk_widget() + trace_canvas_widget.grid(row=0, column=0, sticky="nsew", padx=5, pady=5) + # Configurar el LabelFrame (trace_graph_frame) para que el canvas (su hijo) se expanda + trace_graph_frame.rowconfigure(0, weight=1) + trace_graph_frame.columnconfigure(0, weight=1) def update_sim_graph(self, frame=None): """Actualiza el gráfico del simulador""" diff --git a/tabs/simulator_tab.py b/tabs/simulator_tab.py index fcd3871..8edd780 100644 --- a/tabs/simulator_tab.py +++ b/tabs/simulator_tab.py @@ -64,8 +64,9 @@ class SimulatorTab: self.random_error_interval_var = tk.StringVar(value=initial_config.get('random_error_interval', '10.0')) self.error_details_for_replacement = None # (message_bytes, log_suffix, error_type_str) + self.actual_graph_frame_container = None # Inicializar ANTES de create_widgets self.create_widgets() - + # La línea anterior que asignaba None aquí ha sido eliminada. def create_widgets(self): """Crea los widgets del tab simulador""" # Frame de configuración del simulador @@ -137,12 +138,15 @@ class SimulatorTab: self.stop_button = ttk.Button(controls_frame, text="Detener", command=self.stop_simulation, state=tk.DISABLED) self.stop_button.pack(side=tk.LEFT, padx=5) + self.clear_comm_log_button = ttk.Button(controls_frame, text="Limpiar Log Com.", command=self.clear_comm_log) + self.clear_comm_log_button.pack(side=tk.LEFT, padx=5) + self.clear_graph_button = ttk.Button(controls_frame, text="Limpiar Gráfico", command=self.clear_graph) self.clear_graph_button.pack(side=tk.LEFT, padx=5) # Display Frame display_frame = ttk.LabelFrame(self.frame, text="Valores Actuales") - display_frame.grid(row=1, column=1, padx=10, pady=5, sticky="ew") + display_frame.grid(row=1, column=1, padx=10, pady=5, sticky="nsew") ttk.Label(display_frame, text="Brix:").grid(row=0, column=0, padx=5, pady=5, sticky="w") # self.current_brix_var inicializada en __init__ @@ -159,12 +163,33 @@ class SimulatorTab: ttk.Label(display_frame, textvariable=self.current_voltage_var, font=("Courier", 14, "bold")).grid(row=2, column=1, padx=5, pady=5, sticky="w") - # Log Frame - log_frame = ttk.LabelFrame(self.frame, text="Log de Comunicación") - log_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=5, sticky="nsew") + # Event Log Frame (antes era el log principal) + event_log_frame = ttk.LabelFrame(self.frame, text="Log de Eventos") + event_log_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=5, sticky="nsew") - self.log_text = scrolledtext.ScrolledText(log_frame, height=8, width=70, wrap=tk.WORD, state=tk.DISABLED) - self.log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) + self.event_log_text = scrolledtext.ScrolledText(event_log_frame, height=8, width=70, wrap=tk.WORD, state=tk.DISABLED) + self.event_log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) + + # --- Frame para Comunicación y Gráfico --- + comm_and_graph_parent_frame = ttk.Frame(self.frame) + comm_and_graph_parent_frame.grid(row=3, column=0, columnspan=2, padx=10, pady=5, sticky="nsew") + comm_and_graph_parent_frame.columnconfigure(0, weight=1) # Comm log + comm_and_graph_parent_frame.columnconfigure(1, weight=1) # Graph + comm_and_graph_parent_frame.rowconfigure(0, weight=1) # Ambos toman la altura completa de esta fila + + # Comm Log Frame (Nuevo) + comm_log_frame = ttk.LabelFrame(comm_and_graph_parent_frame, text="Log de Comunicación (Simulador)") + comm_log_frame.grid(row=0, column=0, padx=(0, 5), pady=0, sticky="nsew") + comm_log_frame.rowconfigure(0, weight=1) + comm_log_frame.columnconfigure(0, weight=1) + + self.comm_log_text = scrolledtext.ScrolledText(comm_log_frame, height=10, width=70, wrap=tk.WORD, state=tk.DISABLED) + self.comm_log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) + + # Graph Frame Container (el gráfico se insertará aquí por MaselliApp) + # self.get_graph_frame() ahora devuelve este contenedor. + self.actual_graph_frame_container = ttk.LabelFrame(comm_and_graph_parent_frame, text="Gráfico Simulador") + self.actual_graph_frame_container.grid(row=0, column=1, padx=(5, 0), pady=0, sticky="nsew") # --- Frame para Simulación de Errores --- self._setup_error_simulation_ui() # Se añade al final de create_widgets @@ -172,18 +197,16 @@ class SimulatorTab: # Configurar pesos self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) - self.frame.rowconfigure(2, weight=1) # Log frame + self.frame.rowconfigure(2, weight=1) # Event log frame + self.frame.rowconfigure(3, weight=3) # Comm and Graph parent frame (más altura) + self.frame.rowconfigure(4, weight=0) # Error frame no se expande tanto # Inicializar estado self.on_function_type_change() def get_graph_frame(self): - """Crea y retorna el frame para el gráfico""" - graph_frame = ttk.LabelFrame(self.frame, text="Gráfico Simulador") - graph_frame.grid(row=3, column=0, columnspan=2, padx=10, pady=5, sticky="nsew") - # El rowconfigure para el gráfico se hace aquí, y el de errores abajo - self.frame.rowconfigure(3, weight=1) # Graph frame (se mueve una fila abajo) - return graph_frame + """Retorna el frame contenedor donde se debe dibujar el gráfico del simulador.""" + return self.actual_graph_frame_container def _setup_error_simulation_ui(self): """Crea los controles para la simulación de errores.""" @@ -293,7 +316,7 @@ class SimulatorTab: min_b = float(self.shared_config['min_brix_map_var'].get()) max_b = float(self.shared_config['max_brix_map_var'].get()) base_ma_value = ProtocolHandler.scale_to_ma(manual_val, min_b, max_b) - elif input_type == "mA": + elif input_type == "mA": # noqa: E721 base_ma_value = manual_val elif input_type == "Voltaje": base_ma_value = ProtocolHandler.voltage_to_ma(manual_val) @@ -354,10 +377,10 @@ class SimulatorTab: default_val = min_val + (max_val - min_val) / 4 except (ValueError, KeyError, TypeError): min_val, max_val = 0.0, 80.0 - default_val = 10.0 + default_val = 10.0 # noqa: F841 label_text = "Valor Brix:" precision = 2 - elif input_type == "mA": + elif input_type == "mA": # noqa: E721 min_val, max_val = 0.0, 20.0 default_val = 12.0 label_text = "Valor mA:" @@ -388,7 +411,7 @@ class SimulatorTab: value = float(value_str) input_type = self.manual_input_type_var.get() precision = 2 - if input_type == "Brix": precision = 2 + if input_type == "Brix": precision = 2 # noqa: E701 elif input_type == "mA": precision = 3 elif input_type == "Voltaje": precision = 2 self.manual_value_var.set(f"{value:.{precision}f}") @@ -405,7 +428,7 @@ class SimulatorTab: max_val = float(self.shared_config['max_brix_map_var'].get()) if min_val >= max_val: min_val, max_val = 0.0, 80.0 precision = 2 - elif input_type == "mA": min_val, max_val, precision = 0.0, 20.0, 3 + elif input_type == "mA": min_val, max_val, precision = 0.0, 20.0, 3 # noqa: E701 elif input_type == "Voltaje": min_val, max_val, precision = 0.0, 10.0, 2 value = max(min_val, min(max_val, value)) # Clampear al rango @@ -464,9 +487,9 @@ class SimulatorTab: _, listening_details = self.connection_manager.open_connection(conn_type, conn_params) if conn_type == "TCP-Server": - Utils.log_message(self.log_text, f"{listening_details} para simulación.") + Utils.log_message(self.comm_log_text, f"{listening_details} para simulación.") elif conn_type != "TCP-Server": # Para otros tipos, el mensaje genérico - Utils.log_message(self.log_text, f"Conexión {conn_type} abierta para simulación.") + Utils.log_message(self.comm_log_text, f"Conexión {conn_type} abierta para simulación.") except Exception as e: messagebox.showerror("Error de Conexión", str(e)) return @@ -482,8 +505,8 @@ class SimulatorTab: self.shared_config['client_connected_var'].set("Esperando...") self.simulation_thread = threading.Thread(target=self.run_simulation, daemon=True) - self.simulation_thread.start() - Utils.log_message(self.log_text, "Simulación iniciada.") + self.simulation_thread.start() # noqa: E701 + Utils.log_message(self.event_log_text, "Simulación iniciada.") def stop_simulation(self): """Detiene la simulación""" @@ -504,14 +527,14 @@ class SimulatorTab: self.simulation_thread.join(timeout=2.0) self.connection_manager.close_connection() - Utils.log_message(self.log_text, "Conexión cerrada.") + Utils.log_message(self.comm_log_text, "Conexión cerrada.") self._set_entries_state(tk.NORMAL) self.on_function_type_change() # Re-evaluar estado de controles manuales if self.connection_manager.connection_type == "TCP-Server": # Limpiar info del cliente self.shared_config['client_connected_var'].set("Ninguno") - Utils.log_message(self.log_text, "Simulación detenida.") + Utils.log_message(self.event_log_text, "Simulación detenida.") self.current_brix_var.set("---") self.current_ma_var.set("--.-- mA") self.current_voltage_var.set("-.-- V") @@ -561,7 +584,7 @@ class SimulatorTab: try: manual_numeric_value = float(self.manual_value_var.get()) except ValueError: - Utils.log_message(self.log_text, f"Valor manual inválido: '{self.manual_value_var.get()}'. Usando valor por defecto.") + Utils.log_message(self.event_log_text, f"Valor manual inválido: '{self.manual_value_var.get()}'. Usando valor por defecto.") if manual_input_type == "Brix": manual_numeric_value = min_brix_map elif manual_input_type == "mA": manual_numeric_value = 4.0 elif manual_input_type == "Voltaje": manual_numeric_value = ProtocolHandler.ma_to_voltage(4.0) @@ -641,10 +664,10 @@ class SimulatorTab: if not self.connection_manager.is_client_connected(): if not hasattr(self, '_waiting_for_client_logged') or not self._waiting_for_client_logged: port_to_log = self.shared_config['config_manager'].get_connection_params(current_config_values)['port'] - Utils.log_message(self.log_text, f"TCP Server: Esperando cliente en puerto {port_to_log}...") + Utils.log_message(self.comm_log_text, f"TCP Server: Esperando cliente en puerto {port_to_log}...") self._waiting_for_client_logged = True if self.connection_manager.accept_client(timeout=0.05): - Utils.log_message(self.log_text, f"TCP Server: Cliente conectado desde {self.connection_manager.client_address}") + Utils.log_message(self.comm_log_text, f"TCP Server: Cliente conectado desde {self.connection_manager.client_address}") client_info = f"{self.connection_manager.client_address[0]}:{self.connection_manager.client_address[1]}" self.shared_config['client_connected_var'].set(client_info) self._waiting_for_client_logged = False @@ -654,41 +677,41 @@ class SimulatorTab: log_content = ProtocolHandler.format_for_display(message_to_send, hex_non_printable=True) if actual_error_type_sent != "Normal" and log_prefix_for_send.startswith("Error Sim (Reemplazo Programado)"): - Utils.log_message(self.log_text, f"{log_prefix_for_send}: Trama '{actual_error_type_sent}'{log_suffix_for_send} -> {log_content}") + Utils.log_message(self.comm_log_text, f"{log_prefix_for_send}: Trama '{actual_error_type_sent}'{log_suffix_for_send} -> {log_content}") else: - Utils.log_message(self.log_text, f"{log_prefix_for_send}: {log_content}") + Utils.log_message(self.comm_log_text, f"{log_prefix_for_send}: {log_content}") self.connection_manager.send_data(message_to_send) if conn_type != "TCP-Server": # No leer respuesta en modo servidor response = self.connection_manager.read_response(timeout=0.1) if response and response.strip(): - Utils.log_message(self.log_text, f"Respuesta: {ProtocolHandler.format_for_display(response)}") + Utils.log_message(self.comm_log_text, f"Respuesta: {ProtocolHandler.format_for_display(response)}") parsed = ProtocolHandler.parse_adam_message(response) if parsed: brix_resp = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix_map, max_brix_map) - Utils.log_message(self.log_text, + Utils.log_message(self.comm_log_text, f" -> Addr: {parsed['address']}, " f"mA: {parsed['ma']:.3f}, " f"Brix: {brix_resp:.3f}") except self.connection_manager.ClientDisconnectedError: - Utils.log_message(self.log_text, "TCP Server: Cliente desconectado. Esperando nueva conexión.") + Utils.log_message(self.comm_log_text, "TCP Server: Cliente desconectado. Esperando nueva conexión.") if conn_type == "TCP-Server": self.shared_config['client_connected_var'].set("Esperando...") self._waiting_for_client_logged = False except Exception as e: - Utils.log_message(self.log_text, f"Error en comunicación ({conn_type}): {e}") + Utils.log_message(self.comm_log_text, f"Error en comunicación ({conn_type}): {e}") self.frame.after(0, self.stop_simulation_error) break elif actual_error_type_sent == "Trama Faltante (Omitir Envío)" and log_prefix_for_send.startswith("Error Sim (Reemplazo Programado)"): # Loguear que se omitió una trama debido al reemplazo por "Trama Faltante" - Utils.log_message(self.log_text, f"{log_prefix_for_send}: Simulación de '{actual_error_type_sent}'{log_suffix_for_send}. No se envió trama.") + Utils.log_message(self.comm_log_text, f"{log_prefix_for_send}: Simulación de '{actual_error_type_sent}'{log_suffix_for_send}. No se envió trama.") self.simulation_step += 1 time.sleep(sample_period) except Exception as e: # Catches errors in parameter fetching or main loop logic - Utils.log_message(self.log_text, f"Error en simulación: {e}") + Utils.log_message(self.event_log_text, f"Error en simulación: {e}") if self.simulating: # Ensure stop is called only if an error occurs while simulating self.frame.after(0, self.stop_simulation_error) @@ -736,7 +759,7 @@ class SimulatorTab: message_bytes, _ = ProtocolHandler.create_adam_message_from_ma(adam_address, base_ma_value) log_message_suffix = " (trama normal)" else: - Utils.log_message(self.log_text, f"Error Sim: Tipo de error '{error_type}' desconocido.") + Utils.log_message(self.comm_log_text, f"Error Sim: Tipo de error '{error_type}' desconocido.") return None, f" (tipo de error '{error_type}' desconocido)" return message_bytes, log_message_suffix @@ -748,7 +771,7 @@ class SimulatorTab: return if not self.connection_manager.is_client_connected(): - Utils.log_message(self.log_text, "Error Sim: No hay cliente conectado para enviar trama errónea.") + Utils.log_message(self.comm_log_text, "Error Sim: No hay cliente conectado para enviar trama errónea.") # messagebox.showinfo("Sin Cliente", "No hay cliente conectado para enviar la trama errónea.") # return # Permitir enviar aunque no haya cliente, el log lo indicará @@ -762,21 +785,21 @@ class SimulatorTab: self.error_details_for_replacement = (message_bytes, log_suffix_from_gen, error_type) self.next_frame_is_error_event.set() if error_type == "Trama Faltante (Omitir Envío)": - Utils.log_message(self.log_text, f"Error Sim Manual: Programada OMISIÓN de trama '{error_type}'{log_suffix_from_gen} para reemplazo.") + Utils.log_message(self.comm_log_text, f"Error Sim Manual: Programada OMISIÓN de trama '{error_type}'{log_suffix_from_gen} para reemplazo.") elif message_bytes: - Utils.log_message(self.log_text, f"Error Sim Manual: Programada trama '{error_type}'{log_suffix_from_gen} para reemplazo.") + Utils.log_message(self.comm_log_text, f"Error Sim Manual: Programada trama '{error_type}'{log_suffix_from_gen} para reemplazo.") else: # Error en generación o tipo desconocido - Utils.log_message(self.log_text, f"Error Sim Manual: No se pudo programar trama '{error_type}'{log_suffix_from_gen} para reemplazo.") + Utils.log_message(self.comm_log_text, f"Error Sim Manual: No se pudo programar trama '{error_type}'{log_suffix_from_gen} para reemplazo.") else: # Enviar inmediatamente como trama adicional if message_bytes: try: self.connection_manager.send_data(message_bytes) - Utils.log_message(self.log_text, f"Error Sim Manual (Adicional): Trama '{error_type}'{log_suffix_from_gen} -> {ProtocolHandler.format_for_display(message_bytes, hex_non_printable=True)}") + Utils.log_message(self.comm_log_text, f"Error Sim Manual (Adicional): Trama '{error_type}'{log_suffix_from_gen} -> {ProtocolHandler.format_for_display(message_bytes, hex_non_printable=True)}") except Exception as e: - Utils.log_message(self.log_text, f"Error Sim Manual (Adicional): Fallo al enviar trama: {e}") + Utils.log_message(self.comm_log_text, f"Error Sim Manual (Adicional): Fallo al enviar trama: {e}") elif error_type == "Trama Faltante (Omitir Envío)": - Utils.log_message(self.log_text, f"Error Sim Manual (Adicional): Simulación de '{error_type}'{log_suffix_from_gen}. No se envió trama adicional.") + Utils.log_message(self.comm_log_text, f"Error Sim Manual (Adicional): Simulación de '{error_type}'{log_suffix_from_gen}. No se envió trama adicional.") # else: Ya logueado por generate_erroneous_message_logic si message_bytes es None y no es "Trama Faltante" def toggle_random_errors(self): @@ -787,7 +810,7 @@ class SimulatorTab: if self.random_error_var.get(): # Si el usuario intenta activar los errores aleatorios if not can_actually_start_random_errors: - Utils.log_message(self.log_text, "Error Sim: Errores aleatorios solo en TCP-Server con simulación activa.") + Utils.log_message(self.event_log_text, "Error Sim: Errores aleatorios solo en TCP-Server con simulación activa.") self.random_error_var.set(False) # Forzar a False ya que las condiciones no se cumplen # El timer no se iniciará. update_error_controls_state() al final se encargará. else: # Las condiciones se cumplen, iniciar el timer si no está ya activo @@ -811,7 +834,7 @@ class SimulatorTab: self.random_error_timer.start() else: # Si el usuario intenta desactivar los errores aleatorios (el checkbox ahora está desmarcado) if self.random_error_timer and self.random_error_timer.is_alive(): - Utils.log_message(self.log_text, "Error Sim: Deteniendo envío de errores aleatorios.") + Utils.log_message(self.event_log_text, "Error Sim: Deteniendo envío de errores aleatorios.") self.random_error_timer_stop_event.set() # No es necesario join aquí, se hará en stop_simulation o al cerrar. @@ -824,7 +847,7 @@ class SimulatorTab: if not possible_error_types: return current_interval = initial_interval_s - Utils.log_message(self.log_text, f"Error Sim: Hilo de errores aleatorios iniciado con intervalo {current_interval:.2f}s.") + Utils.log_message(self.event_log_text, f"Error Sim: Hilo de errores aleatorios iniciado con intervalo {current_interval:.2f}s.") while not self.random_error_timer_stop_event.is_set(): if not (self.shared_config['connection_type_var'].get() == "TCP-Server" and self.simulating and self.connection_manager.is_client_connected()): @@ -840,29 +863,29 @@ class SimulatorTab: self.error_details_for_replacement = (message_bytes, log_suffix, selected_random_error) self.next_frame_is_error_event.set() # El log de este envío se hará en run_simulation cuando efectivamente se envíe/omita - Utils.log_message(self.log_text, f"Error Sim Aleatorio: Programada trama '{selected_random_error}'{log_suffix} para reemplazo.") + Utils.log_message(self.comm_log_text, f"Error Sim Aleatorio: Programada trama '{selected_random_error}'{log_suffix} para reemplazo.") else: # Enviar el error inmediatamente, además de las tramas normales if message_bytes: try: self.connection_manager.send_data(message_bytes) - Utils.log_message(self.log_text, f"Error Sim Aleatorio (Adicional): Trama '{selected_random_error}'{log_suffix} -> {ProtocolHandler.format_for_display(message_bytes, hex_non_printable=True)}") + Utils.log_message(self.comm_log_text, f"Error Sim Aleatorio (Adicional): Trama '{selected_random_error}'{log_suffix} -> {ProtocolHandler.format_for_display(message_bytes, hex_non_printable=True)}") except Exception as e: - Utils.log_message(self.log_text, f"Error Sim Aleatorio (Adicional): Fallo al enviar: {e}") + Utils.log_message(self.comm_log_text, f"Error Sim Aleatorio (Adicional): Fallo al enviar: {e}") elif selected_random_error == "Trama Faltante (Omitir Envío)": - Utils.log_message(self.log_text, f"Error Sim Aleatorio (Adicional): Simulación de '{selected_random_error}'{log_suffix}. No se envió trama adicional.") + Utils.log_message(self.comm_log_text, f"Error Sim Aleatorio (Adicional): Simulación de '{selected_random_error}'{log_suffix}. No se envió trama adicional.") # Permitir que el intervalo se actualice dinámicamente try: new_interval = float(self.random_error_interval_var.get()) if new_interval > 0 and new_interval != current_interval: current_interval = new_interval - Utils.log_message(self.log_text, f"Error Sim: Intervalo de errores aleatorios actualizado a {current_interval:.2f}s.") + Utils.log_message(self.event_log_text, f"Error Sim: Intervalo de errores aleatorios actualizado a {current_interval:.2f}s.") except ValueError: pass # Mantener el intervalo actual si el nuevo valor es inválido self.random_error_timer_stop_event.wait(timeout=current_interval) - Utils.log_message(self.log_text, "Error Sim: Hilo de errores aleatorios detenido.") + Utils.log_message(self.event_log_text, "Error Sim: Hilo de errores aleatorios detenido.") def add_data_point(self, brix_value, ma_value): """Agrega un punto de datos al gráfico""" @@ -877,11 +900,16 @@ class SimulatorTab: def clear_graph(self): """Limpia los datos del gráfico""" Utils.clear_graph_data(self.time_data, self.brix_data, self.ma_data) - self.start_time = time.time() - Utils.log_message(self.log_text, "Gráfico limpiado.") + self.start_time = time.time() # noqa: F841 + Utils.log_message(self.event_log_text, "Gráfico del simulador limpiado.") if hasattr(self, 'graph_update_callback'): self.graph_update_callback() + + def clear_comm_log(self): + """Limpia el log de comunicación del simulador.""" + Utils.clear_log_widget(self.comm_log_text) + Utils.log_message(self.event_log_text, "Log de comunicación del simulador limpiado.") def _set_entries_state(self, state): """Habilita/deshabilita los controles durante la simulación"""