# Anycubic-Stack: wie Druck, Abbruch und ACE wirklich laufen Stand **15.10.2026**. Quellen: Anycubic [Klipper-go](https://github.com/ANYCUBIC-3D/Klipper-go), [K3-klipper-mcu](https://github.com/ANYCUBIC-3D/K3-klipper-mcu); Rinkhals `kobra.py`, `mmu_ace.py`, `mmu_ace_metadata.py`, Docs `firmware/mqtt.md` und `firmware/goklipper.md` (lokal unter `D:\Projekte\_ref\`). Nicht geraten — am Quellcode und an der Rinkhals-Doku gelesen. ## Schichten ```mermaid flowchart TB subgraph host [PC] Grotti[Grotti] end subgraph printer [Kobra 3 / S1] Moonraker[Moonraker + kobra.py] MmuAce[mmu_ace + mmu_ace_metadata] Gkapi[gkapi MQTT Broker] Gklib[gklib GoKlipper] Ui[K3SysUi Touch] Mcu[MCU Firmware] AceHw[ACE Hardware] end Grotti -->|"HTTP :80 upload / print/start / cancel"| Moonraker Grotti -->|"MQTTS :9883 print start/stop"| Gkapi Grotti -->|"HTTP :18910 info/ctrl Credentials"| Gkapi Moonraker -->|"bei print/start oft MQTT lokal :2883"| Gkapi Moonraker --> Gklib MmuAce --> Moonraker Gkapi --> Gklib Ui --> Gkapi Gklib --> Mcu Gklib --> AceHw ``` | Komponente | Offen? | Rolle | | --- | --- | --- | | **gklib** (GoKlipper) | teilweise ([Klipper-go](https://github.com/ANYCUBIC-3D/Klipper-go)) | Klipper-Host: Motion, Heater, `virtual_sdcard`, ACE-G-codes | | **MCU** | teilweise ([K3-klipper-mcu](https://github.com/ANYCUBIC-3D/K3-klipper-mcu)) | Stepper/Sensoren | | **gkapi** | nein (proprietär) | MQTT-Broker, Druck-Tasks, Cloud/LAN, Credentials `:18910` | | **K3SysUi** | nein | Touch-UI | | **Rinkhals Moonraker** | ja | Vanilla Moonraker + `kobra.py` + `mmu_ace*` | Anycubic schreibt in den READMEs: proprietäre Features sind gekapselt. MQTT-Taskverwaltung und Cloud stecken nicht in Klipper-go. ## Zwei Welten beim Druckstart 1. **Klipper-Pfad** (Moonraker `POST /printer/print/start` → gklib `virtual_sdcard`): setzt `print_stats`, lädt G-code in gklib. 2. **Anycubic-Task** (MQTT `type: print`, `action: start` an Topic `…/slicer/printer/{modelId}/{deviceId}/print`): legt den Job an, den Display und Cloud kennen; steuert LeviQ/`auto_leveling`, ACE-Map in der Payload. Rinkhals `kobra.py` `patch_mqtt_print` hängt den Moonraker-`print/start` oft auf MQTT um (`mqtt_print_file`), lokal `127.0.0.1:2883`. Grotti kann denselben Start von außen über **MQTTS `:9883`** mit Credentials aus `:18910` machen — dann mit eigener `task_settings` und `ams_settings` (siehe [Senden-Queue](Senden-Queue)). ### MQTT Start (belegt) Aus Rinkhals-Doku `firmware/mqtt.md` und `kobra.py`: - Publish: `anycubic/anycubicCloud/v1/slicer/printer/{modelId}/{deviceId}/print` - Report: `…/printer/public/{modelId}/{deviceId}/print/report` - Pflichtfelder Start: `filename`, `filetype` (1), `taskid` - Optional: `ams_settings.ams_box_mapping`, `task_settings.auto_leveling` (0/1 Integer) - Rinkhals und Grotti setzen `taskid` auf eine Zufallszahl; die Doc-Minimalbeispiel nutzt `"-1"` — beides kommt vor ### MQTT Stop (belegt) — warum 10101 ```json { "type": "print", "action": "stop", "data": { "taskid": "-1" } } ``` Moonraker `/printer/print/cancel` trifft nur gklib (`print_stats` → `cancelled`). Der Anycubic-Task in gkapi bleibt → nächster MQTT-Start mit **code 10101** („Print task already exists“ / chinesische Meldung). Rinkhals `mqtt_print_file` kennt 10101 und **retryt einmal**; Grotti sendet bei Abbruch Moonraker-cancel **und** MQTT-stop. ### Task-Hygiene (wie Rinkhals) Vorbild: `kobra.py` `mqtt_print_file` + `firmware/mqtt.md`. **Kobra 3 und Kobra S1** — dieselbe gkapi-API (`:18910` / MQTTS `:9883`). Gemessen 15.10.2026: S1 `modelId` 20025 / `state: free`, K3 `modelId` 20024; `project: null` zählt nicht als busy. Abräumen-Ablauf bleibt nur Kobra 3. | Schritt | Verhalten in Grotti | | --- | --- | | Vor MQTT-Start | `ensure_task_free`: `info/query`; wenn `state` nicht free oder `project` gesetzt → MQTT-stop, bis zu 3× pollen | | Vor Moonraker-`print/start` | dieselbe Hygiene best-effort (Rinkhals wandelt Start oft intern zu MQTT um) | | gkapi kurz weg | `print_info` → `None`, negativer Cache ~45 s; Start über Moonraker läuft weiter | | Report **10101** | einmal cancel + 1,5 s Pause + erneuter Start | | Report **10107** | klare Filament-Meldung | | Live | Snapshot-Feld `anycubic_task` (`state`, `task_id`, `filename`) aus gecachtem `print_info` (TTL ~10 s); Wand zeigt die Zeile | Codes und Retry: `grotti/anycubic_lan.py` (`message_for_code`, `ensure_task_free`, `start_print`). ### Report-Timeout `kobra.py` wartet max. 30 s auf `print/report`. Nach Bettnetz/`auto_leveling` kann der Report später kommen, der Druck trotzdem laufen (`info/query` → `project.task_id`). Grotti prüft bei Timeout deshalb `print_info` (MQTT `info/query`). ## FIRMWARE_RESTART In **Klipper-go** ist der Befehl implementiert wie bei Klipper: - `Cmd_FIRMWARE_RESTART` → `Request_restart("firmware_restart")` (`gcode.go`) - Nach dem Reactor-Ende: Event `project:firmware_restart` → MCU `_firmware_restart` (`k3c.go`, `Mcu.go`) Auf dem Gerät **deadlockt gklib** trotzdem (beobachtet, Rinkhals #32): Log zeigt Annahme des Befehls, danach keine weitere Verarbeitung, Moonraker bleibt in `startup`. Rinkhals `patch_klipper_restart` **lehnt** `RESTART` / `FIRMWARE_RESTART` unter GoKlipper ab. Grotti ebenso. Config: Display-Reboot oder Strom. Hängenden Fehler: **Fehler löschen** (`SDCARD_RESET_FILE`), nicht Firmware-Restart. Der Open-Source-Code erklärt den Intent des Befehls; die Deadlock-Ursache steckt vermutlich im ausgelieferten Binary / der Anbindung an gkapi — nicht im veröffentlichten Happy Path. ## ACE ### In gklib (Klipper-go `extras_ace.go`) G-codes: `ACE_CHANGE_TOOL`, `ACE_FEED`, `ACE_RETRACT`, `ACE_SET_SLOT`, Trocknen, Endless Spool, … Kommunikation über Seriell (`extras_ace_commun.go`). `Get_status` liefert ACE-`info` + Endless-Spool-Flags — **nicht** das Moonraker-Objekt `mmu` mit `gate_color`. ### In Rinkhals Moonraker (`mmu_ace.py`) - Emuliert Happy-Hare-ähnliches **`mmu`**-Objekt (`gate_color`, `gate_material`, …) für Clients - Beim MQTT-Start: `register_print_data_patcher` → wenn keine `ams_settings` in der Payload, baut Identity-/TTG-Map aus den Gates und hängt `ams_settings` an - Liest/schreibt Sidecar **`basename.acm`** neben dem G-code; ohne ACE kann sie nach `.acm.disabled` umbenannt werden - Auto-Feed-Logik vor Start, wenn nichts im Toolhead ist (Issue #464) ### Upload-Metadaten (`mmu_ace_metadata.py`) Beim Moonraker-Upload: ganze Datei lesen, ggf. umschreiben. Fingerprint `; processed by MmuAcePatcher`. Trailer `; referenced_tools = 0,2,…`. Ohne Trailer: gklib „skipping auto-feed (no trailer found)“. Grotti setzt Fingerprint + Trailer vor dem Upload, damit der teure Durchlauf entfällt ([Senden-Queue](Senden-Queue)). ### `.acm` vs MQTT-`ams_settings` Zwei Kanäle für dieselbe Zuordnung: | Kanal | Wann | | --- | --- | | Datei `name.gcode.acm` / `name.acm` auf dem Drucker | Stock/gklib liest Sidecar beim Start | | MQTT-Feld `data.ams_settings` | gkapi / Rinkhals-Patcher legt Map in die Payload | Ohne Map: Rinkhals füllt oft Identity T0→Platz0 … — deshalb Grotti bei eigener ACE-Zuordnung per MQTT mit expliziter Map startet und beide `.acm`-Varianten hochlädt ([ACE-Live](ACE-Live)). ## Was Grotti bewusst nutzt | Aktion | Weg | Beleg | | --- | --- | --- | | Einfacher Start | Upload + Moonraker `print/start` → Rinkhals MQTT | `kobra.py` `patch_mqtt_print` | | Start mit Bettnetz oder ACE-Map | Upload (+ `.acm`) + Grotti-MQTT `:9883` | `anycubic_lan.start_print`, mqtt.md | | Abbruch | Moonraker cancel + MQTT stop `taskid:-1` | `mqtt_stop_print`, mqtt.md | | Credentials | `:18910/info` + `/ctrl` AES | `anycubic_lan.credentials` | | Slots anzeigen | Moonraker `mmu` (Rinkhals) | `mmu_ace.py` | | Kein Firmware-Restart | abgelehnt | Rinkhals #32, `patch_klipper_restart` | ## Offene Grenzen - Quellcode von **gkapi** (Task-State-Machine, exakte 10101-Bedingungen) ist nicht öffentlich. - Deadlock in **FIRMWARE_RESTART** ist beobachtet und in Rinkhals abgefangen, Root Cause im Binary nicht freigelegt. - Kobra X / K4-Stack ist ein anderes System (C++-Klipper), nicht GoKlipper — für unsere Drucker irrelevant. ## Siehe auch - [Makros-Kobra](Makros-Kobra.md) — Nicht-tun, Vanilla-Alltag, ACE, LeviQ/Wipe je Druckertyp