profesionaliza este codigo:
```
import tkinter as tk
from tkinter import messagebox, simpledialog, ttk
import serial
import serial.tools.list_ports
import threading
import time


class ESP32Interface:
    """Handles serial communication with the ESP32."""

    def __init__(self, port, baud):
        try:
            self.ser = serial.Serial(port, baud, timeout=1)
            time.sleep(2)  # Wait for the connection to establish
        except serial.SerialException as e:
            messagebox.showerror("Error de Conexión", f"No se puede abrir el puerto {port}.\n{e}")
            exit()

    def send_command(self, command):
        """Sends a command to the ESP32."""
        try:
            self.ser.write(f"{command}\n".encode())
        except serial.SerialException as e:
            messagebox.showerror("Error de Serial", f"Error al enviar comando: {e}")

    def read_response(self, callback):
        """Continuously reads responses from the ESP32 and passes them to the callback."""
        while True:
            try:
                if self.ser.in_waiting:
                    line = self.ser.readline().decode(errors='ignore').strip()
                    if line:
                        callback(line)
                time.sleep(0.1)
            except serial.SerialException:
                break  # Exit the thread if connection is lost

    def close(self):
        """Closes the serial connection."""
        if self.ser.is_open:
            self.ser.close()


class AddGestureDialog(simpledialog.Dialog):
    """Dialog window to add a new gesture with multiple actions."""

    def body(self, master):
        self.title("Agregar Gesto")
        self.geometry("600x500")
        self.resizable(False, False)

        # Secuencia de Pines
        ttk.Label(master, text="Secuencia de Pines:", font=("Helvetica", 12, "bold")).grid(row=0, column=0, sticky=tk.W, pady=10, padx=10)
        self.pins_entry = ttk.Entry(master, width=40, font=("Helvetica", 12))
        self.pins_entry.grid(row=0, column=1, pady=10, padx=10, sticky=tk.W)

        # Acciones
        self.actions = []
        self.actions_frame = ttk.LabelFrame(master, text="Acciones", padding="10")
        self.actions_frame.grid(row=1, column=0, columnspan=2, pady=10, padx=10, sticky=tk.EW)

        self.add_action_button = ttk.Button(self.actions_frame, text="Agregar Acción", command=self.add_action)
        self.add_action_button.grid(row=0, column=0, pady=5, padx=5, sticky=tk.W)

        self.actions_listbox = tk.Listbox(self.actions_frame, height=10, width=70, font=("Helvetica", 10))
        self.actions_listbox.grid(row=1, column=0, pady=5, padx=5, sticky=tk.EW)

        self.remove_action_button = ttk.Button(self.actions_frame, text="Eliminar Acción", command=self.remove_action)
        self.remove_action_button.grid(row=2, column=0, pady=5, padx=5, sticky=tk.W)

        # Configure grid expansion
        self.actions_frame.columnconfigure(0, weight=1)

        return self.pins_entry

    def add_action(self):
        """Opens a dialog to add a new action."""
        action_window = tk.Toplevel(self)
        action_window.title("Agregar Acción")
        action_window.geometry("400x250")
        action_window.resizable(False, False)
        action_window.grab_set()

        ttk.Label(action_window, text="Tipo de Acción:", font=("Helvetica", 10)).grid(row=0, column=0, sticky=tk.W, pady=10, padx=10)
        tipo_var = tk.StringVar()
        tipo_combo = ttk.Combobox(action_window, textvariable=tipo_var, state="readonly", width=20)
        tipo_combo['values'] = ("0",)  # Actualmente solo tipo 0: debug
        tipo_combo.current(0)
        tipo_combo.grid(row=0, column=1, pady=10, padx=10, sticky=tk.W)

        ttk.Label(action_window, text="Delay Antes (ms):", font=("Helvetica", 10)).grid(row=1, column=0, sticky=tk.W, pady=10, padx=10)
        delay_entry = ttk.Entry(action_window, width=22, font=("Helvetica", 10))
        delay_entry.grid(row=1, column=1, pady=10, padx=10, sticky=tk.W)

        ttk.Label(action_window, text="Tarea:", font=("Helvetica", 10)).grid(row=2, column=0, sticky=tk.W, pady=10, padx=10)
        tarea_entry = ttk.Entry(action_window, width=22, font=("Helvetica", 10))
        tarea_entry.grid(row=2, column=1, pady=10, padx=10, sticky=tk.W)

        def save_action():
            tipo = tipo_var.get()
            delay = delay_entry.get()
            tarea = tarea_entry.get()
            if not delay.isdigit() or not tarea.isdigit():
                messagebox.showerror("Entrada Inválida", "Delay y Tarea deben ser números.")
                return
            action = f"Tipo: {tipo}, Delay: {delay} ms, Tarea: {tarea}"
            self.actions.append((tipo, delay, tarea))
            self.actions_listbox.insert(tk.END, action)
            action_window.destroy()

        save_button = ttk.Button(action_window, text="Guardar", command=save_action)
        save_button.grid(row=3, column=0, columnspan=2, pady=20)

    def remove_action(self):
        """Removes the selected action from the list."""
        selected = self.actions_listbox.curselection()
        if selected:
            index = selected[0]
            self.actions.pop(index)
            self.actions_listbox.delete(index)
        else:
            messagebox.showwarning("Seleccionar Acción", "Por favor, selecciona una acción para eliminar.")

    def apply(self):
        """Sets the result with the entered pins and actions."""
        self.result = {
            "pins": self.pins_entry.get(),
            "actions": self.actions
        }


class App:
    """Main application class for the ESP32 configuration interface."""

    def __init__(self, root):
        self.root = root
        self.root.title("Configuración ESP32")
        self.root.geometry("900x650")
        self.root.resizable(False, False)

        # Style Configuration
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("Helvetica", 10))
        self.style.configure("TButton", font=("Helvetica", 10))
        self.style.configure("TCombobox", font=("Helvetica", 10))
        self.style.configure("TLabelframe.Label", font=("Helvetica", 12, "bold"))

        # Variables
        self.esp = None

        # Main Frame
        main_frame = ttk.Frame(root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # Serial Connection Frame
        connection_frame = ttk.Labelframe(main_frame, text="Conexión Serial", padding="20")
        connection_frame.pack(fill=tk.X, pady=10)

        ttk.Label(connection_frame, text="Puerto Serial:").grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
        self.port_var = tk.StringVar()
        self.port_combo = ttk.Combobox(connection_frame, textvariable=self.port_var, state="readonly", width=30)
        self.port_combo['values'] = self.get_serial_ports()
        self.port_combo.grid(row=0, column=1, pady=5, padx=5, sticky=tk.W)

        self.refresh_button = ttk.Button(connection_frame, text="Refrescar", command=self.refresh_ports)
        self.refresh_button.grid(row=0, column=2, pady=5, padx=5, sticky=tk.W)

        self.connect_button = ttk.Button(connection_frame, text="Conectar", command=self.connect_serial)
        self.connect_button.grid(row=0, column=3, pady=5, padx=5, sticky=tk.W)

        # Response Display Frame
        display_frame = ttk.Labelframe(main_frame, text="Respuestas del ESP32", padding="20")
        display_frame.pack(fill=tk.BOTH, expand=True, pady=10)

        self.text = tk.Text(display_frame, height=20, width=100, state=tk.DISABLED, wrap=tk.WORD,
                           bg="#ffffff", fg="#000000", font=("Helvetica", 10))
        self.text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10), pady=5)

        scrollbar = ttk.Scrollbar(display_frame, command=self.text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5)
        self.text['yscrollcommand'] = scrollbar.set

        # Action Buttons Frame
        btn_frame = ttk.Labelframe(main_frame, text="Acciones", padding="20")
        btn_frame.pack(fill=tk.X, pady=10)

        self.stop_btn = ttk.Button(btn_frame, text="Detener Ejecución", command=self.stop_execution, state=tk.DISABLED)
        self.stop_btn.grid(row=0, column=0, pady=10, padx=10, sticky=tk.W)

        self.show_pins_btn = ttk.Button(btn_frame, text="Mostrar Valores de Pines", command=self.show_pins, state=tk.DISABLED)
        self.show_pins_btn.grid(row=0, column=1, pady=10, padx=10, sticky=tk.W)

        self.show_gestures_btn = ttk.Button(btn_frame, text="Mostrar Gestos", command=self.show_gestures, state=tk.DISABLED)
        self.show_gestures_btn.grid(row=0, column=2, pady=10, padx=10, sticky=tk.W)

        self.add_gesture_btn = ttk.Button(btn_frame, text="Agregar Gesto", command=self.add_gesture, state=tk.DISABLED)
        self.add_gesture_btn.grid(row=0, column=3, pady=10, padx=10, sticky=tk.W)

        # Status Bar
        self.status_var = tk.StringVar()
        self.status_var.set("Estado: Desconectado")
        status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W,
                               padding=5, font=("Helvetica", 10, "italic"))
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # Close Connection on Exit
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def get_serial_ports(self):
        """Returns a list of available serial ports."""
        ports = serial.tools.list_ports.comports()
        return [port.device for port in ports]

    def refresh_ports(self):
        """Refreshes the list of available serial ports."""
        self.port_combo['values'] = self.get_serial_ports()

    def connect_serial(self):
        """Connects to the selected serial port."""
        port = self.port_var.get()
        if not port:
            messagebox.showwarning("Seleccionar Puerto", "Por favor, selecciona un puerto serial.")
            return

        baud_rate = 115200  # Puede hacerse configurable si se desea

        try:
            self.esp = ESP32Interface(port, baud_rate)
            self.append_text(f"Conectado a {port} a {baud_rate} BAUD.\n")
            self.status_var.set(f"Estado: Conectado a {port} a {baud_rate} BAUD.")
            self.update_buttons_state(disconnected=False)

            # Start reading thread
            threading.Thread(target=self.esp.read_response, args=(self.display_response_threadsafe,), daemon=True).start()
        except Exception as e:
            messagebox.showerror("Error de Conexión", f"Ocurrió un error al conectar: {e}")

    def update_buttons_state(self, disconnected=True):
        """Enables or disables buttons based on connection state."""
        state = tk.NORMAL if not disconnected else tk.DISABLED
        self.stop_btn.config(state=state)
        self.show_pins_btn.config(state=state)
        self.show_gestures_btn.config(state=state)
        self.add_gesture_btn.config(state=state)
        self.connect_button.config(state=tk.DISABLED if not disconnected else tk.NORMAL)
        self.port_combo.config(state=tk.DISABLED if not disconnected else tk.NORMAL)
        self.refresh_button.config(state=tk.DISABLED if not disconnected else tk.NORMAL)

    def append_text(self, message):
        """Appends text to the response display."""
        self.text.config(state=tk.NORMAL)
        self.text.insert(tk.END, message)
        self.text.see(tk.END)
        self.text.config(state=tk.DISABLED)

    def display_response_threadsafe(self, message):
        """Callback to display responses from ESP32 in a thread-safe manner."""
        self.text.after(0, self.append_text, message + "\n")

    def stop_execution(self):
        """Sends the 'stop' command to ESP32."""
        if self.esp:
            self.esp.send_command("stop")
            self.append_text("Comando 'stop' enviado.\n")

    def show_pins(self):
        """Sends the 'pin' command to ESP32."""
        if self.esp:
            self.esp.send_command("pin")
            self.append_text("Comando 'pin' enviado.\n")

    def show_gestures(self):
        """Sends the 'gesto' command to ESP32 to display stored gestures."""
        if self.esp:
            self.esp.send_command("gesto")
            self.append_text("Comando 'gesto' enviado para obtener gestos almacenados.\n")

    def add_gesture(self):
        """Opens the Add Gesture dialog and sends the gesture command to ESP32."""
        if not self.esp:
            messagebox.showwarning("No Conectado", "Por favor, conecta al ESP32 primero.")
            return

        dialog = AddGestureDialog(self.root)
        result = dialog.result

        if result:
            pins = result["pins"]
            actions = result["actions"]
            if not pins.strip():
                messagebox.showerror("Entrada Inválida", "La secuencia de pines no puede estar vacía.")
                return

            # Construir el comando 'gesto' con los pines y acciones
            command = f"gesto {' '.join(pins.split())} ="
            for idx, action in enumerate(actions):
                tipo, delay, tarea = action
                command += f" accion {tipo} {delay} {tarea}"
                if idx < len(actions) - 1:
                    command += " "

            self.esp.send_command(command)
            self.append_text(f"Comando para agregar gesto enviado: {command}\n")

    def on_closing(self):
        """Handles the window closing event."""
        if self.esp:
            self.esp.close()
        self.root.destroy()


def main():
    root = tk.Tk()
    app = App(root)
    root.mainloop()


if __name__ == "__main__":
    main()
```