devmaker.net
start/ 3d-druck/ klipper-update-2026-btt-eddy-richtig-konfigurier
3D Druck

Klipper-Update 2026: BTT Eddy richtig konfigurieren nach der Deprecation von z_offset

Das Klipper-Update 2026 hat z_offset im probe_eddy_current-Block als deprecated markiert – wer den alten Wert einfach in descend_z umbenennt, riskiert einen Düsencrash ins Bett. Die Parameter haben unterschiedliche Bedeutungen. Dieser Artikel zeigt die vollständige Migration: die korrekte printer.cfg, das angepasste Homing-Makro ohne den alten Berechnungsfehler und den Kalibrierungsprozess mit Basis- und Temperatur-Kompensation. Basierend auf einem echten BTT Eddy USB Setup.

Harry_im_Homelab31 (Portrait)
Harald
2026-04-02 · ~11 Min. Lesezeit
BTT Eddy nach der z_offset-Deprecation mit descend_z konfigurieren
BTT Eddy nach der z_offset-Deprecation mit descend_z konfigurieren

Was hat sich geändert?

Mit dem Klipper-Update 2026 hat sich eine fundamentale Änderung am Probe-System ergeben: Der Parameter z_offset ist im [probe_eddy_current]-Block jetzt deprecated (veraltet). An seine Stelle tritt descend_z – ein Wert mit einer völlig anderen Bedeutung.

Während z_offset den vertikalen Versatz zwischen Düse und Sensorpunkt beschrieb, definiert descend_z lediglich die Anfahrhöhe für den Kalibrierungsvorgang. Der eigentliche Z-Offset wird jetzt intern über die Kalibrierungstabelle verrechnet.

Wer nach dem Update einfach seinen alten z_offset-Wert in descend_z einträgt, riskiert einen Crash der Düse ins Bett. Diese Anleitung zeigt dir Schritt für Schritt, wie du alles korrekt umstellst.

Anzeige · Affiliate-Link – kaufst du darüber, erhalte ich ggf. eine Provision. Für dich ändert sich am Preis nichts.

Teil 1: Die richtige Konfiguration (printer.cfg)

Stelle sicher, dass dein [probe_eddy_current]-Block exakt so aussieht. Der Wert descend_z ist kein Offset, sondern nur die Anfahrhöhe für den Kalibriertest:

yaml
[probe_eddy_current btt_eddy]
sensor_type: ldc1612
i2c_mcu: eddy
i2c_bus: i2c0f
x_offset: 0
y_offset: 74.0

# descend_z ist die Höhe, auf die der Kopf beim Kalibrieren fährt.
# 1.0 ist sicher. Stell es NICHT auf deinen alten Z-Offset!
descend_z: 1.0

samples: 2
samples_result: median

Wichtig: Ein descend_z von 1.0 ist ein sicherer Startwert – der Kopf fährt auf 1 mm über das Bett.

Voraussetzungen: Was das Homing-Makro braucht

Das Makro aus Teil 2 ist kein Einzelstück. Es greift auf drei Dinge zu, die vorher in der Config stehen müssen. Fehlen sie, bricht Klipper beim ersten G28 ab – typischerweise mit jinja2.exceptions.UndefinedError: 'GetStatusWrapper' object has no attribute 'gcode_macro SET_GCODE_OFFSET'. Dieser Abschnitt ist nachträglich entstanden, weil zwei Leser in den Kommentaren zu Recht angemerkt haben, dass genau diese Voraussetzungen fehlten – danke dafür.

Bei mir liegen die Blöcke nicht in der printer.cfg, sondern in einer eigenen btt_eddy.cfg, die per [include ./btt_eddy.cfg] eingebunden wird. Das meiste davon liefert BTT in seiner Beispiel-Config schon mit – dort ist es nur auskommentiert.

1. Eddy als Z-Endstop und [safe_z_home]

Der Eddy ersetzt den mechanischen Z-Endschalter. Damit gibt es keinen festen Punkt mehr, an dem Z null ist – gemessen wird dort, wo der Kopf gerade steht. Deshalb muss er zum Homing erst über das Bett fahren, und genau das erledigt [safe_z_home]: erst X und Y homen, dann in die Bettmitte fahren, dann Z messen.

safe_z_home ist also keine Variable, sondern ein ganz normaler Klipper-Config-Abschnitt. Das Homing-Makro liest daraus genau einen Wert aus: cf.safe_z_home.z_hop ist die Höhe, auf die der Kopf nach der Messung zurückfährt.

yaml
# Z-Endschalter: der Eddy statt eines Mikroschalters
[stepper_z]
endstop_pin: probe:z_virtual_endstop

# Homing-Position - der Eddy misst nur über dem Bett
[safe_z_home]
home_xy_position: 199, 200   # Bettmitte (hier 398 x 400) - an dein Bett anpassen
z_hop: 10                    # DIESEN Wert liest SET_Z_FROM_PROBE aus
z_hop_speed: 25
speed: 200

2. Der SET_GCODE_OFFSET-Wrapper

Klipper selbst kennt kein runtime_offset – diese Variable gehört nicht zu Klipper, sondern zum Eddy-Paket. Es legt einen eigenen Makro-Wrapper um Klippers eingebautes SET_GCODE_OFFSET, benennt das Original per rename_existing in SET_GCODE_OFFSET_ORIG um und summiert jedes Babystepping (Z_ADJUST) stattdessen in die Makro-Variable runtime_offset.

Erst dadurch existieren überhaupt beide Namen, die das Homing-Makro benutzt. Ohne diesen Block läuft SET_Z_FROM_PROBE genau in den Fehler oben.

[save_variables] und der RESTORE_PROBE_OFFSET-Timer gehören dazu: Sie holen den dauerhaft gespeicherten Offset nach jedem Klipper-Neustart aus der variables.cfg zurück. Z_OFFSET_APPLY_PROBE aus Teil 5 schreibt ihn dorthin.

yaml
# Speicher für den dauerhaften Z-Offset
[save_variables]
filename: ~/printer_data/config/variables.cfg

# Wrapper um Klippers SET_GCODE_OFFSET.
# Das Original heißt danach SET_GCODE_OFFSET_ORIG - genau der Name,
# den SET_Z_FROM_PROBE aufruft.
[gcode_macro SET_GCODE_OFFSET]
rename_existing: SET_GCODE_OFFSET_ORIG
variable_restored: False
variable_runtime_offset: 0
gcode:
  {% if params.Z_ADJUST %}
    SET_GCODE_VARIABLE MACRO=SET_GCODE_OFFSET VARIABLE=runtime_offset VALUE={ printer["gcode_macro SET_GCODE_OFFSET"].runtime_offset + params.Z_ADJUST|float }
  {% endif %}
  {% if params.Z %}
    {% set paramList = rawparams.split() %}
    {% for i in range(paramList|length) %}
      {% if paramList[i]=="Z=0" %}
        {% set temp=paramList.pop(i) %}
        {% set temp="Z_ADJUST=" + (-printer["gcode_macro SET_GCODE_OFFSET"].runtime_offset)|string %}
        {% if paramList.append(temp) %}{% endif %}
      {% endif %}
    {% endfor %}
    {% set rawparams=paramList|join(' ') %}
    SET_GCODE_VARIABLE MACRO=SET_GCODE_OFFSET VARIABLE=runtime_offset VALUE=0
  {% endif %}
  SET_GCODE_OFFSET_ORIG { rawparams }

# Holt den gespeicherten Offset nach jedem Klipper-Neustart zurück
[delayed_gcode RESTORE_PROBE_OFFSET]
initial_duration: 1.
gcode:
  {% set svv = printer.save_variables.variables %}
  {% if not printer["gcode_macro SET_GCODE_OFFSET"].restored %}
    SET_GCODE_VARIABLE MACRO=SET_GCODE_OFFSET VARIABLE=runtime_offset VALUE={ svv.nvm_offset|default(0) }
    SET_GCODE_VARIABLE MACRO=SET_GCODE_OFFSET VARIABLE=restored VALUE=True
  {% endif %}

# Schreibt den aktuellen Runtime-Offset dauerhaft in die variables.cfg
[gcode_macro Z_OFFSET_APPLY_PROBE]
rename_existing: Z_OFFSET_APPLY_PROBE_ORIG
gcode:
  SAVE_VARIABLE VARIABLE=nvm_offset VALUE={ printer["gcode_macro SET_GCODE_OFFSET"].runtime_offset }

3. Das G28-Wrapper-Makro

Und das Bindeglied, das leicht übersehen wird: SET_Z_FROM_PROBE ruft sich nicht von selbst auf. Damit es beim Homing greift, wird auch G28 umbenannt und um zwei Zeilen ergänzt – erst normal homen, dann einmal PROBE, dann den Z-Nullpunkt setzen. Die Abfrage sorgt dafür, dass das nur bei einem vollen G28 oder einem G28 Z passiert, nicht bei G28 X Y.

yaml
[gcode_macro G28]
rename_existing: G28.1
gcode:
  G28.1 {rawparams}
  {% if not rawparams or (rawparams and 'Z' in rawparams) %}
    PROBE
    SET_Z_FROM_PROBE
  {% endif %}

Teil 2: Das korrigierte Homing-Makro

Hier lag bei vielen Nutzern die Ursache für Crashes: Das alte Makro hat descend_z vom Messwert abgezogen. Das neue Klipper verrechnet den Offset intern über die Kalibrierungstabelle. Ersetze dein altes Makro:

yaml
[gcode_macro SET_Z_FROM_PROBE]
gcode:
    {% set cf = printer.configfile.settings %}
    # Z auf Messwert des Eddy + manuellen Runtime-Offset setzen
    SET_GCODE_OFFSET_ORIG Z={printer.probe.last_z_result + printer["gcode_macro SET_GCODE_OFFSET"].runtime_offset}
    G90
    # Nach Homing auf Sicherheitsabstand fahren
    G1 Z{cf.safe_z_home.z_hop}

Was das Makro tut:

  • Liest den Messwert des Eddy (last_z_result)
  • Addiert deinen manuellen Runtime-Offset
  • Fährt auf die sichere Z-Hop-Höhe

Was es nicht mehr tut: descend_z abziehen – das war der Bug-Verursacher.

Teil 3: Basis-Kalibrierung (Frequenz-Mapping)

Bevor der Eddy präzise arbeiten kann, muss er lernen, wie das Bett unter ihm aussieht. Diese Kalibrierung erstellt eine Frequenz-Abstands-Tabelle.

Vorbereitung

  1. Bett auf 60 °C vorheizen
  2. Druckkopf in die Mitte des Betts fahren

Kalibrierung starten

bash
PROBE_EDDY_CURRENT_CALIBRATE CHIP=btt_eddy METHOD=paper

Ablauf

  1. Der Kopf fährt auf Z = 1.0 (dein descend_z-Wert)
  2. Nutze die Buttons in Mainsail oder TESTZ Z=-0.1 um die Düse abzusenken
  3. Papier zwischen Düse und Bett – es sollte leicht klemmen
  4. Klicke auf ACCEPT
  5. Gib SAVE_CONFIG ein

Klipper schreibt eine Datentabelle ans Ende deiner printer.cfg.

Teil 4: Temperatur-Kompensation

Induktive Sensoren reagieren auf Temperaturänderungen. Die Temperatur-Kalibrierung erstellt eine Korrekturtabelle.

Voraussetzung

Der Drucker muss kalt sein (Zimmertemperatur). Alle Heizungen aus.

Kalibrierung starten

bash
TEMPERATURE_PROBE_CALIBRATE PROBE=btt_eddy TARGET=56 STEP=4

Heizung manuell starten

Da der Befehl die Heizung nicht selbst aktiviert:

bash
SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=80

Ablauf

  1. Klipper fordert zum Papiertest auf → ACCEPT
  2. Warten: Der Eddy erwärmt sich durch die Bettwärme
  3. Bei jeder Stufe (+4 °C): erneuter Papiertest
  4. Fortfahren bis Zieltemperatur (56 °C) erreicht

Abschluss

bash
TEMPERATURE_PROBE_COMPLETE
SAVE_CONFIG

Tipp: Dieser Vorgang dauert 30–60 Minuten.

Teil 5: Der tägliche Betrieb

1. Homing (G28)

Der Eddy misst den Abstand. SET_Z_FROM_PROBE setzt den Z-Nullpunkt automatisch.

2. Bed Mesh

bash
BED_MESH_CALIBRATE

Führt einen rapid_scan aus – blitzschnell, der Kopf hält nicht an.

3. Feinjustierung

  • Nutze den Z-Offset-Regler im Mainsail/Fluidd-Interface
  • Z_OFFSET_APPLY_PROBE speichert dauerhaft in variables.cfg

Sicherheitshinweis für den ersten Test

Achtung – Erster Test nach der Umstellung
  1. Führe ein G28 aus
  2. Halte den Finger am Not-Aus!
  • Okay: Kopf fährt nach oben auf ca. 10 mm
  • Stopp: Kopf fährt ins Bett → alter Wert in der Berechnung

Prüfe: Zieht dein Makro noch descend_z ab? Hast du Teil 3 neu durchgeführt? Steht noch ein alter z_offset in der Config?

Zusammenfassung

WasAlt (vor 2026)Neu (ab 2026)
Z-Offset im Probe-Blockz_offset: -1.54Deprecated – durch descend_z ersetzen
Anfahrhöhe Kalibrierungimplizitdescend_z: 1.0
Offset-VerrechnungManuell im MakroIntern via Kalibrierungstabelle
Makro-Logiklast_z_result - descend_zlast_z_result + runtime_offset

Die Umstellung macht das System am Ende robuster und genauer. Der Eddy arbeitet nach der neuen Kalibrierung deutlich zuverlässiger.

// verwandte beiträge

// 4 responses — sorted oldest first
Bob 24.07.2026 23:22
This doesn't work!
I get the following error:
Error evaluating 'gcode_macro SET_Z_FROM_PROBE:gcode': jinja2.exceptions.UndefinedError: 'extras.gcode_macro.GetStatusWrapper object' has no attribute 'gcode_macro SET_GCODE_OFFSET'
You don't give us the gcode_macro SET_GCODE_OFFSET.
Harald 06.09.2026 09:29
You're right, and thanks for the exact error message - that was a real gap in the article. SET_GCODE_OFFSET_ORIG and runtime_offset only exist once the wrapper macro that ships with the BTT Eddy package is defined: it renames Klipper's built-in SET_GCODE_OFFSET to SET_GCODE_OFFSET_ORIG via rename_existing and keeps the babystepping in its own runtime_offset variable. On my machine that block lives in btt_eddy.cfg rather than printer.cfg, which is why it never made it into the post.

I've added a new "Prerequisites" section before Part 2 with the full macro, plus [save_variables] and the G28 wrapper that actually calls SET_Z_FROM_PROBE - without that one the macro is never invoked at all. Sorry for the wasted debugging time.
Duncan 21.08.2026 16:08
What is the variable safe_z_home?
Harald 06.09.2026 09:29
Good catch - safe_z_home isn't a variable, it's a regular Klipper config section, and I never showed it in the article. Since the Eddy replaces the mechanical Z endstop, there's no fixed point where Z is zero any more: it measures wherever the head happens to be. [safe_z_home] is what moves the head over the bed first, so homing measures in a sensible spot.

The macro reads exactly one value from it: cf.safe_z_home.z_hop is the height the head returns to after measuring. I've added the section with my actual config - see "Prerequisites: What the homing macro needs".

Schreibe einen Kommentar

Wird für die Bestätigung benötigt