diff --git a/maselli_simulator_config.json b/maselli_simulator_config.json index 7ccd65f..e9539d8 100644 --- a/maselli_simulator_config.json +++ b/maselli_simulator_config.json @@ -8,9 +8,13 @@ "max_brix_map": "80", "adam_address": "01", "function_type": "Manual", - "cycle_time": "10.0", + "cycle_time": "3", "samples_per_cycle": "100", - "manual_brix": "10.0", - "netcom_com_port": "COM9", - "netcom_baud_rate": "9600" + "manual_input_type": "Brix", + "manual_value": "0.00", + "netcom_com_port": "COM11", + "netcom_baud_rate": "9600", + "netcom_rtscts": false, + "netcom_dsrdtr": false, + "netcom_xonxoff": false } \ No newline at end of file diff --git a/tabs/simulator_tab.py b/tabs/simulator_tab.py index bdee397..5a52b3d 100644 --- a/tabs/simulator_tab.py +++ b/tabs/simulator_tab.py @@ -30,6 +30,29 @@ class SimulatorTab: self.brix_data = deque(maxlen=self.max_points) self.ma_data = deque(maxlen=self.max_points) self.start_time = time.time() + + # Cargar configuración inicial para obtener valores por defecto para StringVars + # Esto es para asegurar que las StringVars tengan un valor inicial antes de que set_config sea llamado + # por maselli_app.py. + initial_config = self.shared_config['config_manager'].load_config() + + self.adam_address_var = tk.StringVar(value=initial_config.get('adam_address', '01')) + self.function_type_var = tk.StringVar(value=initial_config.get('function_type', 'Lineal')) + self.cycle_time_var = tk.StringVar(value=initial_config.get('cycle_time', '10.0')) + self.samples_per_cycle_var = tk.StringVar(value=initial_config.get('samples_per_cycle', '100')) + + self.manual_input_type_var = tk.StringVar(value=initial_config.get('manual_input_type', 'Brix')) + self.manual_value_var = tk.StringVar(value=initial_config.get('manual_value', '10.0')) + + try: + manual_value_float = float(initial_config.get('manual_value', '10.0')) + except ValueError: + manual_value_float = 10.0 # Fallback + self.manual_slider_var = tk.DoubleVar(value=manual_value_float) + + self.current_brix_var = tk.StringVar(value="---") + self.current_ma_var = tk.StringVar(value="--.-- mA") + self.current_voltage_var = tk.StringVar(value="-.-- V") # Nueva para voltaje self.create_widgets() @@ -41,13 +64,13 @@ class SimulatorTab: # Dirección ADAM ttk.Label(config_frame, text="ADAM Address (2c):").grid(row=0, column=0, padx=5, pady=5, sticky="w") - self.adam_address_var = tk.StringVar(value=self.shared_config.get('adam_address', '01')) + # self.adam_address_var inicializada en __init__ self.adam_address_entry = ttk.Entry(config_frame, textvariable=self.adam_address_var, width=5) self.adam_address_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew") # Función ttk.Label(config_frame, text="Función:").grid(row=0, column=2, padx=5, pady=5, sticky="w") - self.function_type_var = tk.StringVar(value=self.shared_config.get('function_type', 'Lineal')) + # self.function_type_var inicializada en __init__ self.function_type_combo = ttk.Combobox(config_frame, textvariable=self.function_type_var, values=["Lineal", "Sinusoidal", "Manual"], state="readonly", width=10) @@ -56,37 +79,45 @@ class SimulatorTab: # Tiempo de ciclo completo (nueva característica) ttk.Label(config_frame, text="Tiempo Ciclo (s):").grid(row=0, column=4, padx=5, pady=5, sticky="w") - self.cycle_time_var = tk.StringVar(value=self.shared_config.get('cycle_time', '10.0')) + # self.cycle_time_var inicializada en __init__ self.cycle_time_entry = ttk.Entry(config_frame, textvariable=self.cycle_time_var, width=8) self.cycle_time_entry.grid(row=0, column=5, padx=5, pady=5, sticky="ew") # Velocidad de muestreo (calculada automáticamente) ttk.Label(config_frame, text="Muestras/ciclo:").grid(row=0, column=6, padx=5, pady=5, sticky="w") - self.samples_per_cycle_var = tk.StringVar(value="100") + # self.samples_per_cycle_var inicializada en __init__ self.samples_per_cycle_entry = ttk.Entry(config_frame, textvariable=self.samples_per_cycle_var, width=8) self.samples_per_cycle_entry.grid(row=0, column=7, padx=5, pady=5, sticky="ew") - # Frame para modo Manual + # --- Frame para modo Manual (Modificado) --- manual_frame = ttk.LabelFrame(config_frame, text="Modo Manual") manual_frame.grid(row=1, column=0, columnspan=8, padx=5, pady=5, sticky="ew") - ttk.Label(manual_frame, text="Valor Brix:").grid(row=0, column=0, padx=5, pady=5, sticky="w") - self.manual_brix_var = tk.StringVar(value=self.shared_config.get('manual_brix', '10.0')) - self.manual_brix_entry = ttk.Entry(manual_frame, textvariable=self.manual_brix_var, width=10, state=tk.DISABLED) - self.manual_brix_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew") - self.manual_brix_entry.bind('', lambda e: self.update_slider_from_entry()) - self.manual_brix_entry.bind('', lambda e: self.update_slider_from_entry()) + ttk.Label(manual_frame, text="Entrada Por:").grid(row=0, column=0, padx=5, pady=5, sticky="w") + # self.manual_input_type_var inicializada en __init__ + self.manual_input_type_combo = ttk.Combobox(manual_frame, textvariable=self.manual_input_type_var, + values=["Brix", "mA", "Voltaje"], state="readonly", width=8) + self.manual_input_type_combo.grid(row=0, column=1, padx=5, pady=5, sticky="ew") + self.manual_input_type_combo.bind("<>", self.on_manual_input_type_change) + + self.manual_value_label = ttk.Label(manual_frame, text="Valor Brix:") # Se actualiza dinámicamente + self.manual_value_label.grid(row=1, column=0, padx=5, pady=5, sticky="w") + + # self.manual_value_var y self.manual_slider_var inicializadas en __init__ + self.manual_value_entry = ttk.Entry(manual_frame, textvariable=self.manual_value_var, width=10, state=tk.DISABLED) + self.manual_value_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew") + self.manual_value_entry.bind('', lambda e: self.update_slider_from_entry()) + self.manual_value_entry.bind('', lambda e: self.update_slider_from_entry()) # Slider - self.manual_slider_var = tk.DoubleVar(value=float(self.shared_config.get('manual_brix', '10.0'))) - self.manual_slider = ttk.Scale(manual_frame, from_=0, to=100, orient=tk.HORIZONTAL, + self.manual_slider = ttk.Scale(manual_frame, orient=tk.HORIZONTAL, # from_ y to_ se configuran dinámicamente variable=self.manual_slider_var, command=self.on_slider_change, state=tk.DISABLED, length=200) - self.manual_slider.grid(row=0, column=2, padx=5, pady=5, sticky="ew") + self.manual_slider.grid(row=1, column=2, padx=5, pady=5, sticky="ew") self.manual_send_button = ttk.Button(manual_frame, text="Enviar Manual", command=self.send_manual_value, state=tk.DISABLED) - self.manual_send_button.grid(row=0, column=3, padx=5, pady=5, sticky="ew") + self.manual_send_button.grid(row=1, column=3, padx=5, pady=5, sticky="ew") manual_frame.columnconfigure(2, weight=1) @@ -108,15 +139,20 @@ class SimulatorTab: display_frame.grid(row=1, column=1, padx=10, pady=5, sticky="ew") ttk.Label(display_frame, text="Brix:").grid(row=0, column=0, padx=5, pady=5, sticky="w") - self.current_brix_var = tk.StringVar(value="---") + # self.current_brix_var inicializada en __init__ ttk.Label(display_frame, textvariable=self.current_brix_var, font=("Courier", 14, "bold")).grid(row=0, column=1, padx=5, pady=5, sticky="w") ttk.Label(display_frame, text="mA:").grid(row=1, column=0, padx=5, pady=5, sticky="w") - self.current_ma_var = tk.StringVar(value="--.-- mA") + # self.current_ma_var inicializada en __init__ ttk.Label(display_frame, textvariable=self.current_ma_var, font=("Courier", 14, "bold")).grid(row=1, column=1, padx=5, pady=5, sticky="w") + ttk.Label(display_frame, text="Voltaje:").grid(row=2, column=0, padx=5, pady=5, sticky="w") + # self.current_voltage_var inicializada en __init__ + 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") @@ -127,7 +163,7 @@ class SimulatorTab: # Configurar pesos self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) - self.frame.rowconfigure(2, weight=1) + self.frame.rowconfigure(2, weight=1) # Log frame # Inicializar estado self.on_function_type_change() @@ -136,7 +172,7 @@ class SimulatorTab: """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") - self.frame.rowconfigure(3, weight=1) + self.frame.rowconfigure(3, weight=1) # Graph frame return graph_frame def on_function_type_change(self, event=None): @@ -146,7 +182,8 @@ class SimulatorTab: if self.simulating: self.stop_simulation() - self.manual_brix_entry.config(state=tk.NORMAL) + self.manual_input_type_combo.config(state=tk.NORMAL) + self.manual_value_entry.config(state=tk.NORMAL) self.manual_send_button.config(state=tk.NORMAL) self.manual_slider.config(state=tk.NORMAL) @@ -154,8 +191,10 @@ class SimulatorTab: self.samples_per_cycle_entry.config(state=tk.DISABLED) self.start_button.config(state=tk.DISABLED) self.stop_button.config(state=tk.DISABLED) + self.on_manual_input_type_change() # Configurar según el tipo actual else: - self.manual_brix_entry.config(state=tk.DISABLED) + self.manual_input_type_combo.config(state=tk.DISABLED) + self.manual_value_entry.config(state=tk.DISABLED) self.manual_send_button.config(state=tk.DISABLED) self.manual_slider.config(state=tk.DISABLED) @@ -165,46 +204,128 @@ class SimulatorTab: self.start_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.DISABLED) - def on_slider_change(self, value): + def on_manual_input_type_change(self, event=None): + """Maneja el cambio de tipo de entrada manual (Brix, mA, Voltaje)""" + input_type = self.manual_input_type_var.get() + min_val, max_val, default_val, label_text, precision = 0, 100, 10.0, "Valor Brix:", 2 + + if input_type == "Brix": + try: + min_val = float(self.shared_config['min_brix_map_var'].get()) + max_val = float(self.shared_config['max_brix_map_var'].get()) + if min_val >= max_val: min_val, max_val = 0.0, 80.0 # Fallback + 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 + label_text = "Valor Brix:" + precision = 2 + elif input_type == "mA": + min_val, max_val = 0.0, 20.0 + default_val = 12.0 + label_text = "Valor mA:" + precision = 3 + elif input_type == "Voltaje": + min_val, max_val = 0.0, 10.0 + default_val = 5.0 + label_text = "Valor Voltaje:" + precision = 2 + + self.manual_value_label.config(text=label_text) + self.manual_slider.config(from_=min_val, to=max_val) + + try: + current_numeric_val = float(self.manual_value_var.get()) + if not (min_val <= current_numeric_val <= max_val): + self.manual_value_var.set(f"{default_val:.{precision}f}") + self.manual_slider_var.set(default_val) + else: + self.manual_slider_var.set(current_numeric_val) + self.manual_value_var.set(f"{current_numeric_val:.{precision}f}") + except ValueError: + self.manual_value_var.set(f"{default_val:.{precision}f}") + self.manual_slider_var.set(default_val) + + def on_slider_change(self, value_str): """Actualiza el valor del entry cuando cambia el slider""" - self.manual_brix_var.set(f"{float(value):.1f}") + value = float(value_str) + input_type = self.manual_input_type_var.get() + precision = 2 + if input_type == "Brix": precision = 2 + elif input_type == "mA": precision = 3 + elif input_type == "Voltaje": precision = 2 + self.manual_value_var.set(f"{value:.{precision}f}") def update_slider_from_entry(self): """Actualiza el slider cuando cambia el entry""" try: - value = float(self.manual_brix_var.get()) - value = max(0, min(100, value)) + value = float(self.manual_value_var.get()) + input_type = self.manual_input_type_var.get() + min_val, max_val, precision = 0,100,2 + + if input_type == "Brix": + min_val = float(self.shared_config['min_brix_map_var'].get()) + 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 == "Voltaje": min_val, max_val, precision = 0.0, 10.0, 2 + + value = max(min_val, min(max_val, value)) # Clampear al rango self.manual_slider_var.set(value) - self.manual_brix_var.set(f"{value:.1f}") - except ValueError: - pass + self.manual_value_var.set(f"{value:.{precision}f}") + except (ValueError, KeyError, TypeError): + # Si el valor no es un número o shared_config no está listo, resetear al valor del slider + current_slider_val = self.manual_slider_var.get() + precision_fallback = 2 + if self.manual_input_type_var.get() == "mA": precision_fallback = 3 + self.manual_value_var.set(f"{current_slider_val:.{precision_fallback}f}") def send_manual_value(self): """Envía un valor manual único""" try: # Obtener valores de mapeo - min_brix = float(self.shared_config['min_brix_map_var'].get()) - max_brix = float(self.shared_config['max_brix_map_var'].get()) + min_brix_map = float(self.shared_config['min_brix_map_var'].get()) + max_brix_map = float(self.shared_config['max_brix_map_var'].get()) adam_address = self.adam_address_var.get() if len(adam_address) != 2: messagebox.showerror("Error", "La dirección ADAM debe tener 2 caracteres.") return - manual_brix = float(self.manual_brix_var.get()) + if min_brix_map >= max_brix_map: + messagebox.showerror("Error de Configuración", "Min Brix debe ser menor que Max Brix.") + return + + input_type = self.manual_input_type_var.get() + manual_numeric_value = float(self.manual_value_var.get()) - # Crear mensaje - message, ma_value = ProtocolHandler.create_adam_message(adam_address, manual_brix, min_brix, max_brix) + final_brix, final_ma, final_voltage = 0.0, 0.0, 0.0 + + if input_type == "Brix": + final_brix = manual_numeric_value + final_ma = ProtocolHandler.scale_to_ma(final_brix, min_brix_map, max_brix_map) + final_voltage = ProtocolHandler.ma_to_voltage(final_ma) + elif input_type == "mA": + final_ma = manual_numeric_value + final_brix = ProtocolHandler.ma_to_brix(final_ma, min_brix_map, max_brix_map) + final_voltage = ProtocolHandler.ma_to_voltage(final_ma) + elif input_type == "Voltaje": + final_voltage = manual_numeric_value + final_ma = ProtocolHandler.voltage_to_ma(final_voltage) + final_brix = ProtocolHandler.ma_to_brix(final_ma, min_brix_map, max_brix_map) + + message, calculated_ma_from_brix = ProtocolHandler.create_adam_message(adam_address, final_brix, min_brix_map, max_brix_map) # Actualizar display - self.current_brix_var.set(Utils.format_brix_display(manual_brix)) - self.current_ma_var.set(Utils.format_ma_display(ma_value)) + self.current_brix_var.set(Utils.format_brix_display(final_brix)) + self.current_ma_var.set(Utils.format_ma_display(final_ma)) + self.current_voltage_var.set(ProtocolHandler.format_voltage_display(final_voltage)) # Agregar al gráfico - self.add_data_point(manual_brix, ma_value) + self.add_data_point(final_brix, final_ma) # Enviar por conexión temporal - # Construct a dictionary of current config values for get_connection_params current_config_values = { 'connection_type': self.shared_config['connection_type_var'].get(), 'com_port': self.shared_config['com_port_var'].get(), @@ -223,14 +344,13 @@ class SimulatorTab: temp_conn.send_data(message) - # Intentar leer respuesta response = temp_conn.read_response(timeout=0.5) if response and response.strip(): Utils.log_message(self.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, max_brix) + brix_resp = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix_map, max_brix_map) Utils.log_message(self.log_text, f" -> Addr: {parsed['address']}, " f"mA: {parsed['ma']:.3f}, " @@ -243,8 +363,8 @@ class SimulatorTab: temp_conn.close_connection() Utils.log_message(self.log_text, "Conexión cerrada.") - except ValueError as e: - messagebox.showerror("Error", "Valores inválidos en la configuración.") + except (ValueError, KeyError, TypeError) as e: + messagebox.showerror("Error", f"Valores inválidos en la configuración o entrada: {e}") def start_simulation(self): """Inicia la simulación continua""" @@ -252,7 +372,6 @@ class SimulatorTab: messagebox.showwarning("Advertencia", "La simulación ya está en curso.") return - # Validar configuración try: adam_address = self.adam_address_var.get() if len(adam_address) != 2: @@ -269,13 +388,15 @@ class SimulatorTab: messagebox.showerror("Error", "Las muestras por ciclo deben ser mayor que 0.") return - except ValueError: - messagebox.showerror("Error", "Valores inválidos en la configuración.") + # Validar mapeo Brix + float(self.shared_config['min_brix_map_var'].get()) + float(self.shared_config['max_brix_map_var'].get()) + + except (ValueError, KeyError, TypeError): + messagebox.showerror("Error", "Valores inválidos en la configuración (ADAM, ciclo, muestras o mapeo Brix).") return - # Abrir conexión try: - # Construct a dictionary of current config values for get_connection_params current_config_values = { 'connection_type': self.shared_config['connection_type_var'].get(), 'com_port': self.shared_config['com_port_var'].get(), @@ -294,6 +415,7 @@ class SimulatorTab: self.simulating = True self.simulation_step = 0 + self.start_time = time.time() # Reset start time for graph self.start_button.config(state=tk.DISABLED) self.stop_button.config(state=tk.NORMAL) self._set_entries_state(tk.DISABLED) @@ -318,66 +440,59 @@ class SimulatorTab: self.start_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.DISABLED) self._set_entries_state(tk.NORMAL) - self.on_function_type_change() + self.on_function_type_change() # Re-evaluar estado de controles manuales Utils.log_message(self.log_text, "Simulación detenida.") self.current_brix_var.set("---") self.current_ma_var.set("--.-- mA") + self.current_voltage_var.set("-.-- V") def run_simulation(self): """Thread principal de simulación""" try: - # Obtener parámetros adam_address = self.adam_address_var.get() - min_brix = float(self.shared_config['min_brix_map_var'].get()) - max_brix = float(self.shared_config['max_brix_map_var'].get()) + min_brix_map = float(self.shared_config['min_brix_map_var'].get()) + max_brix_map = float(self.shared_config['max_brix_map_var'].get()) function_type = self.function_type_var.get() cycle_time = float(self.cycle_time_var.get()) samples_per_cycle = int(self.samples_per_cycle_var.get()) - # Calcular período entre muestras sample_period = cycle_time / samples_per_cycle while self.simulating: - # Calcular valor actual según la función + current_brix = 0.0 progress = (self.simulation_step % samples_per_cycle) / samples_per_cycle if function_type == "Lineal": - # Onda triangular cycle_progress = (self.simulation_step % (2 * samples_per_cycle)) / samples_per_cycle if cycle_progress > 1.0: cycle_progress = 2.0 - cycle_progress - current_brix = min_brix + (max_brix - min_brix) * cycle_progress + current_brix = min_brix_map + (max_brix_map - min_brix_map) * cycle_progress elif function_type == "Sinusoidal": phase = progress * 2 * math.pi sin_val = (math.sin(phase) + 1) / 2 - current_brix = min_brix + (max_brix - min_brix) * sin_val + current_brix = min_brix_map + (max_brix_map - min_brix_map) * sin_val - # Crear y enviar mensaje - message, ma_value = ProtocolHandler.create_adam_message(adam_address, current_brix, min_brix, max_brix) + message, ma_value = ProtocolHandler.create_adam_message(adam_address, current_brix, min_brix_map, max_brix_map) + voltage_value = ProtocolHandler.ma_to_voltage(ma_value) - # Actualizar display self.current_brix_var.set(Utils.format_brix_display(current_brix)) self.current_ma_var.set(Utils.format_ma_display(ma_value)) + self.current_voltage_var.set(ProtocolHandler.format_voltage_display(voltage_value)) - # Agregar al gráfico self.frame.after(0, lambda b=current_brix, m=ma_value: self.add_data_point(b, m)) - # Log y envío Utils.log_message(self.log_text, f"Enviando: {ProtocolHandler.format_for_display(message)}") try: self.connection_manager.send_data(message) - - # Leer respuesta sin bloquear demasiado 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)}") - parsed = ProtocolHandler.parse_adam_message(response) if parsed: - brix_resp = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix, max_brix) + brix_resp = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix_map, max_brix_map) Utils.log_message(self.log_text, f" -> Addr: {parsed['address']}, " f"mA: {parsed['ma']:.3f}, " @@ -385,21 +500,22 @@ class SimulatorTab: except Exception as e: Utils.log_message(self.log_text, f"Error en comunicación: {e}") - self.frame.after(0, self.stop_simulation_error) + self.frame.after(0, self.stop_simulation_error) # Schedule GUI update from main thread break self.simulation_step += 1 time.sleep(sample_period) - except Exception as e: + 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}") - self.frame.after(0, self.stop_simulation_error) + if self.simulating: # Ensure stop is called only if an error occurs while simulating + self.frame.after(0, self.stop_simulation_error) def stop_simulation_error(self): - """Detiene la simulación debido a un error""" - if self.simulating: - messagebox.showerror("Error", "Error durante la simulación. Simulación detenida.") - self.stop_simulation() + """Detiene la simulación debido a un error y muestra mensaje""" + if self.simulating: # Solo actuar si la simulación estaba activa + messagebox.showerror("Error de Simulación", "Error durante la simulación. Simulación detenida.") + self.stop_simulation() # Llama al método normal de parada def add_data_point(self, brix_value, ma_value): """Agrega un punto de datos al gráfico""" @@ -408,7 +524,6 @@ class SimulatorTab: self.brix_data.append(brix_value) self.ma_data.append(ma_value) - # Notificar a la aplicación principal para actualizar el gráfico if hasattr(self, 'graph_update_callback'): self.graph_update_callback() @@ -423,15 +538,15 @@ class SimulatorTab: def _set_entries_state(self, state): """Habilita/deshabilita los controles durante la simulación""" - widgets = [ + sim_specific_widgets = [ self.adam_address_entry, self.function_type_combo, self.cycle_time_entry, self.samples_per_cycle_entry ] - Utils.set_widgets_state(widgets, state) + # No deshabilitar controles de modo manual aquí, se manejan en on_function_type_change + Utils.set_widgets_state(sim_specific_widgets, state) - # También deshabilitar controles compartidos if 'shared_widgets' in self.shared_config: Utils.set_widgets_state(self.shared_config['shared_widgets'], state) @@ -442,7 +557,8 @@ class SimulatorTab: 'function_type': self.function_type_var.get(), 'cycle_time': self.cycle_time_var.get(), 'samples_per_cycle': self.samples_per_cycle_var.get(), - 'manual_brix': self.manual_brix_var.get() + 'manual_input_type': self.manual_input_type_var.get(), + 'manual_value': self.manual_value_var.get() } def set_config(self, config): @@ -451,11 +567,15 @@ class SimulatorTab: self.function_type_var.set(config.get('function_type', 'Lineal')) self.cycle_time_var.set(config.get('cycle_time', '10.0')) self.samples_per_cycle_var.set(config.get('samples_per_cycle', '100')) - self.manual_brix_var.set(config.get('manual_brix', '10.0')) + + self.manual_input_type_var.set(config.get('manual_input_type', 'Brix')) + self.manual_value_var.set(config.get('manual_value', '10.0')) try: - self.manual_slider_var.set(float(config.get('manual_brix', '10.0'))) - except: - pass + self.manual_slider_var.set(float(self.manual_value_var.get())) + except ValueError: + # Si el valor no es un float válido, intentar con un default o el valor del tipo + # Esto se manejará mejor en on_manual_input_type_change + pass - self.on_function_type_change() + self.on_function_type_change() # Esto llamará a on_manual_input_type_change si es necesario