diff --git a/README.de.md b/README.de.md
index b9a8582..adb8e7a 100644
--- a/README.de.md
+++ b/README.de.md
@@ -8,7 +8,7 @@
Eine Moonraker-kompatible Bridge, die direkt mit dem Drucker spricht.
-🇬🇧 English version
+🇬🇧 English version · 🇪🇸 Versión española
diff --git a/README.es.md b/README.es.md
new file mode 100644
index 0000000..026f861
--- /dev/null
+++ b/README.es.md
@@ -0,0 +1,224 @@
+
+
+

+
+# KX-Bridge
+
+**Controla tu Anycubic Kobra X con OrcaSlicer — sin Klipper, sin Raspberry Pi.**
+
+Un puente compatible con Moonraker que se comunica directamente con la impresora.
+
+
🇬🇧 English version · 🇩🇪 Deutsche Version
+
+
+
+[](https://ko-fi.com/viewitde)
+
+[](https://gitea.it-drui.de/viewit/KX-Bridge-Release/releases)
+
+[](https://gitea.it-drui.de/viewit/KX-Bridge-Release/releases)
+
+[](https://www.youtube.com/watch?v=1Ql4wfH27fM)
+
+
¿Te gusta KX-Bridge? Un café en Ko-fi mantiene el proyecto vivo. ☕
+
+
+
+---
+
+## ✨ Características
+
+| | |
+|---|---|
+| 🖨️ | **Control de impresora** — iniciar, pausar, reanudar, cancelar, temperaturas, velocidad de impresión |
+| 📊 | **Estado en tiempo real** — temperatura, progreso, capas, tiempo restante, transmisión de cámara |
+| 🎨 | **AMS / multicolor** — ranuras de filamento, reasignación por canal, emulación MMU para sincronización de filamento en OrcaSlicer |
+| 🗂️ | **Explorador de GCode** — archivos subidos con vistas previas, historial de impresión, búsqueda y filtros |
+| 🧩 | **Multi-impresora** — múltiples impresoras en **una** instancia del puente, cambia mediante un menú desplegable |
+| ➕ | **Añade una impresora con un clic** — solo introduce la IP, las credenciales se importan automáticamente |
+| 🔄 | **Actualización automática** — instala nuevas versiones directamente desde el navegador |
+| 🌐 | **OrcaSlicer** — protocolo Moonraker completo (HTTP + WebSocket), interfaz EN/ES |
+
+---
+
+## 🚀 Inicio rápido
+
+### 1. Prepara la impresora
+
+Activa el modo LAN en la Kobra X:
+**Pantalla de la impresora → Ajustes → Activar modo LAN**
+
+### 2. Inicia el puente
+
+**Docker (recomendado):**
+```bash
+docker compose up -d
+```
+
+**Binario Linux (sin Docker):**
+```bash
+chmod +x kx-bridge && ./kx-bridge
+```
+
+**EXE Windows (sin Docker):**
+```
+kx-bridge.exe
+```
+> `config\` y `data\` se crean junto al EXE — instalación portátil.
+
+> Con los binarios de Linux y Windows, `config/` y `data/` (configuración, SQLite, almacén de GCode)
+> viven junto al programa. Copia toda la carpeta para mover la instalación.
+
+**Python directamente:**
+```bash
+pip install -r bridge/requirements.txt
+python bridge/kobrax_moonraker_bridge.py
+```
+
+### 3. Configura la impresora
+
+Abre la interfaz web: **`http://IP-DEL-PUENTE:7125`**
+
+En el primer inicio, la pestaña **Impresoras** muestra *"+ Añadir impresora"* — solo introduce la dirección IP
+de la impresora, el resto (usuario, contraseña, ID de dispositivo) se obtiene de la impresora y se desencripta
+automáticamente. Listo.
+
+> ¿Más de una impresora? Simplemente haz clic en *"+ Añadir impresora"* de nuevo — cada una recibe su propio puerto
+> (7125, 7126, …) y se puede seleccionar desde el menú desplegable del encabezado.
+
+### 4. Conecta OrcaSlicer
+
+Impresora → Tipo de conexión **Moonraker** → Host: `http://IP-DEL-PUENTE:7125`
+
+> ⚠️ El tipo de conexión debe ser **Moonraker** (no "Bambu" ni "Klipper").
+> Introduce la URL completa incluyendo `http://` y el puerto `:7125` en el campo de host.
+
+---
+
+## 📺 Vídeo tutorial
+
+[](https://www.youtube.com/watch?v=1Ql4wfH27fM)
+
+---
+
+## 🎨 Slicer recomendado
+
+Para la mejor experiencia con KX-Bridge ofrecemos una **versión modificada de OrcaSlicer** que
+incluye tres PRs abiertos de SoftFever/OrcaSlicer: el perfil de la impresora Anycubic Kobra
+X, una corrección de GCode multicolor y — lo más importante — una corrección de sincronización de
+filamento Moonraker/Happy-Hare que mantiene las posiciones de las ranuras AMS intactas incluso con una ranura vacía.
+
+→ **[Lanzamientos de OrcaSlicer-KX](https://gitea.it-drui.de/viewit/OrcaSlicer-KX/releases/latest)** (Linux AppImage + Windows ZIP)
+
+OrcaSlicer estándar también funciona; la versión modificada mejora principalmente el manejo de AMS.
+Es una versión basada en [OrcaSlicer](https://github.com/SoftFever/OrcaSlicer) (AGPL-3.0);
+el código fuente está disponible a través de los PRs enlazados.
+
+---
+
+## 🏠 Comunidad e integraciones
+
+- **[Integración con Home Assistant](https://github.com/gangoke/kobrax-lan-hass-component)**
+ por [@gangoke](https://github.com/gangoke) — expone sensores, controles de impresión,
+ luz, cámara y la vista previa del GCode como entidades nativas de Home Assistant.
+
+> Estos son **proyectos de la comunidad**, no mantenidos ni soportados por KX-Bridge.
+> Para preguntas o problemas, utiliza el repositorio enlazado.
+
+---
+
+## 🔧 Obtener credenciales manualmente
+
+Normalmente no es necesario — *"+ Añadir impresora"* lo hace automáticamente. Si lo necesitas:
+
+```bash
+fetch_credentials --ip 192.168.x.x --write-config
+```
+Obtiene las credenciales directamente de la impresora vía HTTP y las escribe en `config/config.ini`.
+Solo se requiere la IP de la impresora, no hace falta un slicer.
+
+Alternativamente (si se desconoce la IP): abre AnycubicSlicerNext, conecta la impresora, luego ejecuta
+`extract_credentials` → muestra usuario, contraseña, ID de dispositivo y la IP de la impresora.
+
+> **Descargas:** [Lanzamientos](https://gitea.it-drui.de/viewit/KX-Bridge-Release/releases) → `fetch_credentials` / `extract_credentials` (Linux y Windows)
+
+---
+
+## ⚙️ Comandos útiles
+
+```bash
+docker compose logs -f # mostrar registros
+docker compose down # detener el puente
+docker compose pull && docker compose up -d # actualizar a la imagen publicada más reciente
+docker compose up -d --build # recompilar localmente (en lugar de descargar)
+```
+
+---
+
+## 🩹 Solución de problemas
+
+
+"Credenciales MQTT incorrectas" al iniciar
+
+- Vuelve a añadir la impresora mediante *"+ Añadir impresora"*, o ejecuta
+ `fetch_credentials --ip --write-config` y reinicia el puente
+- Introduce solo la dirección IP, sin puerto (✗ `192.168.1.102:9883` → ✓ `192.168.1.102`)
+
+
+
+Impresora no encontrada / modo LAN no activado
+
+- En la pantalla de la impresora: Ajustes → Activar modo LAN
+- La impresora y el puente deben estar en la misma red
+
+
+
+Docker: Permiso denegado
+
+```bash
+sudo usermod -aG docker $USER # luego cierra la sesión y vuelve a iniciarla
+```
+
+
+
+Actualizar desde 0.9.1 o anterior
+
+A partir de 0.9.2, KX-Bridge almacena la configuración en `config/config.ini` en lugar de `.env`.
+La migración se ejecuta automáticamente en el primer inicio después de la actualización — no requiere acción.
+
+
+---
+
+## 🔒 Seguridad
+
+- El puente es accesible en la red local en `http://:7125` — **no** lo expongas a internet
+- `config/config.ini` contiene las credenciales de la impresora — no las compartas públicamente
+- Las credenciales **no** otorgan acceso a los servicios en la nube de Anycubic
+
+---
+
+## 📄 Licencia
+
+[](LICENSE)
+
+KX-Bridge se publica bajo la **GNU General Public License v3.0**. Consulta
+[LICENSE](LICENSE) para el texto completo. Las bifurcaciones y modificaciones deben
+permanecer bajo GPLv3 si se redistribuyen.
+
+La implementación del protocolo MQTT es el resultado de una ingeniería inversa
+independiente con fines de interoperabilidad (§69e UrhG / Directiva de Software de la UE
+Art. 6). El material de terceros en el repositorio (certificados TLS de Anycubic)
+**no** está cubierto por GPLv3 y se incluye únicamente para permitir la
+autenticación contra impresoras que el usuario final ya posee. Consulta
+[NOTICE.md](NOTICE.md) para más detalles y el aviso legal.
+
+Este proyecto es independiente y no está afiliado con Anycubic.
+
+
+
+
+**Si KX-Bridge te ayuda, el proyecto agradece tu apoyo:**
+
+[](https://ko-fi.com/viewitde)
+
+
diff --git a/README.md b/README.md
index d57877f..c8173eb 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
A Moonraker-compatible bridge that talks directly to the printer.
-🇩🇪 Deutsche Version
+🇩🇪 Deutsche Version · 🇪🇸 Versión española
diff --git a/web/translations/es.json b/web/translations/es.json
index 632b469..344ee9f 100644
--- a/web/translations/es.json
+++ b/web/translations/es.json
@@ -20,9 +20,9 @@
"kobra_finished": "Finalizado",
"kobra_failed": "Error",
"kobra_canceled": "Cancelado",
- "kobra_offline": "Offline",
+ "kobra_offline": "Desconectada",
"nav_dashboard": "Panel",
- "nav_print": "Impresion",
+ "nav_print": "Impresión",
"nav_temps": "Temperaturas",
"nav_motion": "Movimiento",
"nav_ams": "AMS",
@@ -31,12 +31,12 @@
"card_progress": "Progreso",
"card_temps": "Temperaturas",
"card_light_fan": "Ventilador",
- "card_speed": "Velocidad de impresion",
- "card_cam": "Camara",
+ "card_speed": "Velocidad de impresión",
+ "card_cam": "Cámara",
"lbl_elapsed": "Transcurrido:",
"lbl_remaining": "Restante:",
- "lbl_slicer_time": "Estimacion del slicer:",
- "lbl_layers": "Layer",
+ "lbl_slicer_time": "Estimación del slicer:",
+ "lbl_layers": "Capa",
"speed_silent": "🐢 Silencioso",
"speed_normal": "⚡ Normal",
"speed_sport": "🚀 Sport",
@@ -52,14 +52,14 @@
"ace_dry_current_temp": "Temperatura",
"ace_dry_chart": "Historial (Temp/Humedad)",
"ace_dry_temp": "Temperatura (°C)",
- "ace_dry_duration": "Duracion (min)",
- "ace_dry_start": "▶ Start",
- "ace_dry_stop": "■ Stop",
- "ace_dry_auto_refill": "Relleno automatico",
+ "ace_dry_duration": "Duración (min)",
+ "ace_dry_start": "▶ Iniciar",
+ "ace_dry_stop": "■ Parar",
+ "ace_dry_auto_refill": "Relleno automático",
"ace_dry_enable": "Activar secado",
"ace_dry_temp_line": "Temperatura de secado",
"ace_dry_time_line": "Tiempo de secado",
- "ace_dry_ui_pending": "(solo UI, backend despues)",
+ "ace_dry_ui_pending": "(solo UI, backend después)",
"ace_dry_dialog_title": "Ajustes de temp/tiempo del secador",
"ace_dry_dialog_temp": "Temperatura (30-80°C)",
"ace_dry_dialog_time": "Tiempo restante (h:m:s)",
@@ -67,12 +67,12 @@
"ace_dry_dialog_cancel": "Cancelar",
"ace_dry_dialog_save_restart": "Guardar y reiniciar",
"ace_dry_dialog_custom_name": "Nombre personalizado",
- "ace_dry_dialog_reset_default": "Restablecer por defecto",
- "cam_placeholder": "📷 Camara no iniciada",
+ "ace_dry_dialog_reset_default": "Restablecer valores predeterminados",
+ "cam_placeholder": "📷 Cámara no iniciada",
"cam_stream_unavailable": "Stream no disponible",
- "btn_cam_start": "▶ Camara",
- "btn_cam_stop": "◼ Camara",
- "btn_pause": "⏸ Pause",
+ "btn_cam_start": "▶ Cámara",
+ "btn_cam_stop": "◼ Cámara",
+ "btn_pause": "⏸ Pausa",
"btn_resume": "▶ Reanudar",
"btn_cancel": "✕ Detener",
"label_nozzle": "Boquilla",
@@ -81,20 +81,20 @@
"label_light": "💡 Luz",
"label_on_off": "Encendido / Apagado",
"label_speed": "Velocidad",
- "panel_print_title": "Control de impresion",
- "panel_print_btn_pause": "⏸ Pause",
+ "panel_print_title": "Control de impresión",
+ "panel_print_btn_pause": "⏸ Pausa",
"panel_print_btn_resume": "▶ Reanudar",
"panel_print_btn_cancel": "✕ Cancelar",
"panel_print_temps_live": "Temperaturas (en vivo)",
"label_set": "Set",
- "label_off": "Off",
+ "label_off": "Apagado",
"panel_temps_nozzle": "Boquilla",
"panel_temps_bed": "Cama caliente",
- "panel_temps_chart": "Historial (ultimas 60 lecturas)",
+ "panel_temps_chart": "Historial (últimas 60 lecturas)",
"label_target_c": "Objetivo:",
"panel_motion_xy": "Ejes XY",
"panel_motion_z": "Eje Z",
- "label_step": "Tamano del paso:",
+ "label_step": "Tamaño del paso:",
"btn_home_z": "Home Z",
"btn_home_xy": "Home XY",
"btn_home_all": "Home All",
@@ -103,11 +103,11 @@
"card_ams": "Filamento",
"ams_no_data": "No se recibieron datos de AMS",
"label_slot": "Ranura",
- "ams_empty": "Vacio",
+ "ams_empty": "Vacío",
"panel_extras_light": "Luz",
"panel_extras_fan": "Ventilador",
- "panel_extras_camera": "Camara",
- "btn_cam_start2": "▶ Start",
+ "panel_extras_camera": "Cámara",
+ "btn_cam_start2": "▶ Iniciar",
"btn_cam_stop2": "◼ Detener",
"panel_console_title": "Registro de eventos",
"log_light_on": "Luz encendida",
@@ -118,29 +118,29 @@
"log_axis": "Eje",
"log_home": "Home",
"log_home_all": "Home All",
- "log_cam_start": "Camara iniciada:",
- "log_cam_stop": "Camara detenida",
+ "log_cam_start": "Cámara iniciada:",
+ "log_cam_stop": "Cámara detenida",
"log_poll_error": "Error de sondeo:",
"log_error": "Error:",
- "confirm_cancel": "Realmente cancelar la impresion?",
- "settings_title": "Configuracion",
- "settings_connection": "Conexion",
- "settings_print": "Ajustes de impresion",
+ "confirm_cancel": "¿Realmente cancelar la impresión?",
+ "settings_title": "Configuración",
+ "settings_connection": "Conexión",
+ "settings_print": "Ajustes de impresión",
"settings_poll": "Intervalo de sondeo",
- "settings_version": "Version",
+ "settings_version": "Versión",
"settings_save": "Guardar y reiniciar",
"settings_printer_name": "Nombre de impresora",
"settings_printer_ip": "IP de impresora",
"settings_mqtt_port": "MQTT Port",
"settings_username": "Usuario MQTT",
- "settings_password": "Contrasena MQTT",
+ "settings_password": "Contraseña MQTT",
"settings_device_id": "ID del dispositivo",
- "settings_mode_id": "Mode ID",
- "hint_ip_no_port": "Solo direccion IP, sin puerto (p. ej. 192.168.1.102)",
+ "settings_mode_id": "ID de modo",
+ "hint_ip_no_port": "Solo dirección IP, sin puerto (p. ej. 192.168.1.102)",
"settings_default_slot": "Ranura predeterminada (un color)",
"settings_slot_auto": "Auto (todos los slots cargados)",
"settings_auto_leveling": "Autonivelado antes de imprimir",
- "settings_camera_on_print": "Encender camara al iniciar impresion",
+ "settings_camera_on_print": "Encender cámara al iniciar impresión",
"settings_web_upload_warning": "Mostrar advertencia al imprimir subidas web",
"update_check": "Buscar actualizaciones",
"update_checking": "Comprobando...",
@@ -152,7 +152,7 @@
"update_error": "Error",
"btn_connect": "⚡ Conectar",
"btn_disconnect": "✕ Desconectar",
- "lbl_conn_error": "Error de conexion:",
+ "lbl_conn_error": "Error de conexión:",
"slot_edit_title": "Editar slot",
"slot_edit_color": "Color",
"slot_edit_material": "Material",
@@ -165,61 +165,61 @@
"slot_edit_profile_hint": "Envía al sincronizar con OrcaSlicer la marca concreta en lugar de solo \"Generic\"",
"slot_edit_profile_default": "— Genérico (Predeterminado) —",
"log_dir_all": "Todos",
- "log_lvl_label": "Level:",
- "file_ready_btn": "▶ Iniciar impresion",
+ "log_lvl_label": "Nivel:",
+ "file_ready_btn": "▶ Iniciar impresión",
"file_slots_btn": "🎨 Seleccionar ranuras",
"file_cancel_btn": "✕ Cancelar",
"nav_printers": "Impresoras",
"skip_title": "✂ Omitir objetos",
- "skip_hint": "Desmarca objetos que ya no quieras imprimir:",
+ "skip_hint": "Deselecciona los objetos que ya no quieras imprimir:",
"skip_btn_label": "Objetos",
- "skip_no_objects": "No hay objetos en esta impresion.",
+ "skip_no_objects": "No hay objetos en esta impresión.",
"skip_already": "omitido",
- "skip_select_at_least_one": "Elige al menos un objeto.",
+ "skip_select_at_least_one": "Selecciona al menos un objeto.",
"skip_sending": "Enviando …",
- "skip_success": "Se omitiran los objetos.",
+ "skip_success": "Se omitirán los objetos.",
"fd_objects_hint": "Omitir objetos (opcional):",
"fd_slots_hint": "Asignar canal GCode a la ranura AMS:",
"fd_cancel": "Cancelar",
"fd_print": "▶ Imprimir",
- "fd_no_slots_msg": "No hay slots AMS cargados.{br}Iniciar impresion de todos modos?",
+ "fd_no_slots_msg": "No hay slots AMS cargados.{br}¿Iniciar impresión de todos modos?",
"fd_slot": "Ranura",
"fd_no_matching_material": "No hay material compatible",
"fd_used": "USADO",
- "add_printer": "Agregar impresora",
+ "add_printer": "Añadir impresora",
"apd_lbl_ip": "IP de impresora",
"apd_lbl_name": "Nombre (opcional)",
"apd_placeholder_name": "p. ej. Kobra X Sala",
"apd_cancel": "Cancelar",
- "apd_confirm": "Agregar",
+ "apd_confirm": "Añadir",
"apd_fetching": "Obteniendo datos de la impresora…",
- "apd_success": "Impresora agregada, reiniciando bridge…",
- "apd_err_ip": "Introduce una direccion IP",
+ "apd_success": "Impresora añadida, reiniciando bridge…",
+ "apd_err_ip": "Introduce una dirección IP",
"printers_remove": "Eliminar impresora",
- "printers_remove_confirm": "Eliminar impresora \"{name}\"? El bridge se reiniciara.",
+ "printers_remove_confirm": "¿Eliminar impresora \"{name}\"? El bridge se reiniciará.",
"printers_active": "● activa",
"printers_switch": "Cambiar →",
"printers_current": "Impresora actual",
"printers_loading": "Cargando…",
"printers_none": "No hay impresoras configuradas.",
- "printers_empty_hint": "Aun no hay impresora configurada.",
+ "printers_empty_hint": "Aún no hay impresora configurada.",
"nav_browser": "Explorador",
"panel_browser_title": "Explorador de archivos",
"store_search_placeholder": "🔍 Buscar…",
- "store_empty": "Aun no hay archivos subidos.",
+ "store_empty": "Aún no hay archivos subidos.",
"store_refresh": "↻ Actualizar",
"store_print": "▶ Imprimir",
"store_download": "⬇ Descargar",
- "store_delete_confirm": "Eliminar archivo?",
- "store_print_confirm": "Imprimir archivo?",
+ "store_delete_confirm": "¿Eliminar archivo?",
+ "store_print_confirm": "¿Imprimir archivo?",
"store_web_verify_title": "Verificar archivo",
"store_web_verify_msg": "Verifica que este archivo fue creado para Anycubic Kobra X.",
"store_web_verify_confirm": "Confirmar",
"store_web_verify_abort": "Abortar",
"store_no_results": "No se encontraron archivos.",
"store_never": "nunca impreso",
- "store_estimate": "Estimacion",
- "store_upload_label_prefix": "Arrastra GCode aqui o ",
+ "store_estimate": "Estimación",
+ "store_upload_label_prefix": "Arrastra el GCode aquí o ",
"store_upload_label_browse": "buscar",
"store_upload_busy": "⏳ Subiendo…",
"store_upload_success": "✓ {file}",
@@ -230,5 +230,5 @@
"sf_new": "Nuevo",
"ss_date": "↓ Fecha",
"ss_name": "A–Z Nombre",
- "ss_dur": "⏱ Tiempo de impresion"
+ "ss_dur": "⏱ Tiempo de impresión"
}