Files
KX-Bridge-Release/CLAUDE.md
2026-06-03 07:22:58 -05:00

8.0 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

KX-Bridge is a Python 3.11+ bridge that emulates the Klipper/Moonraker API to enable OrcaSlicer to control Anycubic Kobra X printers in LAN mode — no Klipper, no Raspberry Pi required. It reverse-engineers the Anycubic MQTT protocol to relay commands from slicers to the printer.

Running

Docker (recommended):

docker compose up -d
docker compose logs -f

Python directly:

pip install -r requirements.txt
python kobrax_moonraker_bridge.py --printer-ip 192.168.x.x

Build binary:

pyinstaller kx-bridge.spec

No test suite exists in this repository.

Architecture

The system bridges three parties:

OrcaSlicer / Browser
      ↕ HTTP + WebSocket (port 7125+, Moonraker API)
KX-Bridge (kobrax_moonraker_bridge.py)
      ↕ MQTT over TLS (port 9883, Anycubic LAN protocol)
Anycubic Kobra X Printer

Core Files

  • kobrax_moonraker_bridge.py — Main server (~5,000 lines). Houses KobraXBridge (HTTP/WebSocket handlers, state management), GCodeStore (SQLite-backed file/print-history storage), and CameraCache (MJPEG stream caching). This is where all Moonraker API endpoints are implemented.
  • kobrax_client.py — Low-level MQTT client for the Kobra X. Handles raw MQTT 3.1.1 framing, TLS certificate auth, topic subscriptions, and message dispatch.
  • config_loader.py — Loads config/config.ini (primary); env_loader.py handles .env fallback. Also exposes list_notification_urls(), list_printers(), list_filament_profiles().
  • fetch_credentials.py — Standalone tool to pull printer credentials over HTTP from the Kobra X.
  • extract_credentials.py — Reads credentials from a running AnycubicSlicerNext process (Windows/Linux).

Web UI

Single-page app served by the bridge itself:

When adding UI text, all four translation files must be updated. The hint element for notifications uses innerHTML (not textContent) to support links — follow the same pattern used for orca_profile_help_html when translation values contain HTML.

The theme system is documented in web/DOC/THEME-CSS-HOOKS.md and web/DOC/THEME-JS-ID-HOOKS.md.

Configuration

Primary config: config/config.ini (copy from config/config.ini.example). Sections:

  • [connection] — Printer IP, MQTT credentials, device/mode IDs
  • [printer_N] — One section per printer for multi-printer setups (ports 71257130)
  • [print] — AMS slots, auto-leveling, camera
  • [filament_profiles] — Per-slot filament for AMS
  • [bridge] — Poll interval (15 s, default 3 s), printer name
  • [notifications] — Apprise notification URLs and interval settings (see below)

Data Storage

  • SQLite at data/kx-bridge.db — G-code metadata, print history, thumbnails (base64)
  • data/orca_filaments.json — OrcaSlicer filament database, loaded at startup

Key Protocol Details

  • MQTT auth: AES-256-CBC encrypted credentials + TLS certificates (anycubic_slicer.crt/key bundled via PyInstaller)
  • Moonraker emulation: Kobra states are mapped to Klipper states via KOBRA_TO_KLIPPER_STATE in kobrax_moonraker_bridge.py
  • Real-time logs: Streamed to the browser via Server-Sent Events (SSE), not WebSocket
  • Multi-printer: Each printer runs its own KobraXBridge instance on a separate port

PyInstaller Build

kx-bridge.spec bundles the web UI, filament database, and Anycubic TLS certificates into a single binary. The web/ tree maps to static/ inside the binary. Both pycryptodome and apprise use collect_all() to capture dynamically loaded plugins.

Notification System (Apprise)

Push notifications are sent via the apprise library (supports 60+ services via URL syntax: discord://, telegram://, pover://, gotify://, slack://, etc.).

Config format ([notifications] section):

url_1 = discord://webhook_id/webhook_token
events_1 = started,finished,failed,cancelled,paused,progress
image_1 = false
url_2 = pover://USERKEY@TOKEN
events_2 = finished,failed
image_2 = true
notify_every_minutes = 10
notify_every_layers = 0

Key implementation points:

  • KobraXBridge._notify(event, filename) — fires on state transitions detected in _on_print(). Splits matching URLs into plain and image groups; image group attaches a temp .jpg from camera_cache.latest_jpeg via apprise.AppriseAttachment.
  • KobraXBridge._check_progress_notifications() — called from _poll_loop() every poll tick; fires progress event when the time or layer threshold is crossed. Both counters are reset together when either fires, and are also reset when a new print starts.
  • _prev_kobra_state guards against duplicate notifications when the printer repeatedly reports the same state.
  • All notification dispatches run in threading.Thread(daemon=True) to avoid blocking the MQTT reader thread or the event loop.
  • The test endpoint (POST /api/notifications/test) runs apprise synchronously via run_in_executor.

Supported events: started, finished, failed, cancelled, paused, progress

Settings UI: Managed through the WebUI settings modal. Each URL entry has per-event checkboxes, a 📷 Image toggle, and a Test button. Global repeat interval fields (minutes / layers) apply to all URLs subscribed to the progress event.

Android App

A companion Android app lives in android/. It connects to a running KX-Bridge server and provides a mobile printer control panel.

Building

cd android
./gradlew assembleDebug    # APK at app/build/outputs/apk/debug/
./gradlew assembleRelease  # Minified release APK
  • Min SDK: 26 (Android 8.0), Compile/Target SDK: 34
  • Language: Kotlin 2.0.0 + Jetpack Compose (Material3)
  • Java toolchain: 17
  • No test suite exists.

Architecture

android/app/src/main/java/com/kxbridge/
├── MainActivity.kt              # Entry point; reads SharedPreferences for server URL
├── data/
│   ├── PrinterRepository.kt    # OkHttp3 HTTP client; polls /api/state every 3 s
│   └── model/PrinterState.kt   # kotlinx-serialization data model (snake_case JSON)
├── viewmodel/PrinterViewModel.kt # StateFlow<UiState> (Loading / Success / Error)
└── ui/
    ├── PrinterScreen.kt         # Main control UI: temps, progress, pause/resume/cancel
    └── SetupScreen.kt           # First-run server URL entry form

MainActivity stores the server URL in SharedPreferences ("kxbridge" / key "server_url") and switches between SetupScreen and PrinterScreen based on whether a URL is configured.

PrinterViewModel drives all network interaction: it holds a PrinterRepository, exposes a StateFlow<UiState>, and exposes command methods (pause, resume, cancel). UiState is a sealed interface.

Communication with KX-Bridge

The app uses plain HTTP (cleartext allowed in the manifest):

Method Endpoint Purpose
GET /api/state Fetch PrinterState JSON (polled every 3 s)
POST /printer/print/pause Pause active print
POST /printer/print/resume Resume paused print
POST /printer/print/cancel Cancel print

PrinterState fields use @SerialName for snake_case JSON keys. ProGuard is configured to keep com.kxbridge.data.model.** to prevent serialization breakage in release builds.