Skip to content

Conversation

@tg73
Copy link
Collaborator

@tg73 tg73 commented Jul 28, 2025

Summary by CodeRabbit

  • New Features

    • Beacon adaptive heat-soak for better first-layer thermal stability
    • Beacon true-zero multi-point correction with diagnostics
    • Centralized Z-offset management combining multiple offset sources
    • Expanded bed-mesh tools: improved profile management, validation, and scan compensation
    • PrusaSlicer support extended to 2.9.1 and 2.9.2
  • Improvements

    • Streamlined safe-home and homing flows
    • Enhanced IDEX/toolhead offset handling and logs
    • Additional beacon preflight checks and calibration flow refinements

✏️ Tip: You can customize this high-level summary in your review settings.

miklschmidt and others added 30 commits July 8, 2025 15:09
…can compensation mesh issues rather than failing late eg after heat soaking.
…reasonably close to the current beacon coil temp.

Currently allowing up to 20C difference as the acceptable range.
…ault name for the beacon scan compensation mesh
…n model according to beacon_contact_calibrate_model_on_print
…ION, now always saves.

From discussion with MS there was no known use case for *not* saving, and not saving creates a profile in a confusing ephemeral state which is lost when the profile is reloaded.
- Implement _RAISE_ERROR in python instead of jinja for cleaner error messages
- Implement _TRY, the try/except/finally pattern for macros
…ated functionality

- Change and enhance the set of metadata stored:
    - Remove beacon_model_temp as this is not relevant.
    - Add bed temperature, mesh kind and probe method.
- Add warnings in create_compensation_mesh() for unapplied z-tilt or QGL
- Add various new gcode commands
- Defer profile deserialization using delayed gcode to ensure that warnings are seen in the console
- Replace/improve checks and warnings/errors
- Enhance preflight checks called from START_PRINT
- Apply extended metadata to all profiles/meshes created via BED_MESH_CALIBRATE
- Support saving via the standard Z_OFFSET_APPLY_PROBE macro
- Exclude active IDEX toolhead offset from the saved value
…tions

- TEMPERATURE_WAIT now calls TEMPERATURE_WAIT_BASE even when both MINIMUM and MAXIMUM are not specified, allowing the base impl to raise an error
tg73 added 3 commits August 29, 2025 11:37
- This can produce a visible improvement in surface quality, and appears to have little if any impact on CPU usage. The change was not applied more widely as other machines may have lower spec host boards, and the change has not been tested on those machines.
During further testing it became clear that changing the governor while klipper is running can occasionally lead to timer too close or other driver communication issues, and for the time being no workaround was found. So removing the feature for now.
@tg73
Copy link
Collaborator Author

tg73 commented Dec 2, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
configuration/klippy/ratos.py (2)

523-535: Bug in get_gcode_file_info for case‑insensitive filename lookup

When filename doesn’t match any entry in flist exactly, the function returns the raw [filepath, fsize] list from files_by_lower without joining it with sdcard_dirname. That means process_gcode_file() may pass a relative or incorrect path into the RatOS CLI instead of an absolute path under self.sdcard_dirname.

Consider normalizing both branches to always return [fullpath, size], e.g.:

def get_gcode_file_info(self, filename):
    files = self.v_sd.get_file_list(True)
    flist = [f[0] for f in files]
-   files_by_lower = { filepath.lower(): [filepath, fsize] for filepath, fsize in files }
+   files_by_lower = { filepath.lower(): filepath for filepath, _ in files }
    filepath = filename
    try:
-       if filepath not in flist:
-           filepath = files_by_lower[filepath.lower()]
-           return filepath
-       fullpath = os.path.join(self.sdcard_dirname, filepath);
-       return [fullpath, os.path.getsize(fullpath)]
+       if filepath not in flist:
+           filepath = files_by_lower[filepath.lower()]
+       fullpath = os.path.join(self.sdcard_dirname, filepath)
+       return [fullpath, os.path.getsize(fullpath)]
    except:
        raise self.printer.command_error("Can not get path for file " + filename)

This preserves behavior while ensuring the CLI always sees a full filesystem path.


546-565: Defensive handling of msg and display_status in console_echo

console_echo now unconditionally calls msg.replace("_N_", "\n"). If it’s ever invoked with msg=None (e.g. via CONSOLE_ECHO without MSG), this will raise an exception. It also assumes self.display_status is always present.

To harden this:

def console_echo(self, title, type, msg=''):
-    color = "white"
+    color = "white"
     opacity = 1.0
@@
-    msg = msg.replace("_N_","\n")
+    if msg is None:
+        msg = ""
+    msg = msg.replace("_N_", "\n")
@@
-    if (type == 'error' or type == 'alert'):
-        logging.error(title + ": " + msg)
-        self.display_status.message = f"ERROR: {title} (check the console for details)"
-    if (type == 'warning'):
-        logging.warning(title + ": " + msg)
-        self.display_status.message = f"WARNING: {title} (check the console for details)"
+    if (type == 'error' or type == 'alert'):
+        logging.error(title + ": " + msg)
+        if self.display_status is not None:
+            self.display_status.message = f"ERROR: {title} (check the console for details)"
+    if (type == 'warning'):
+        logging.warning(title + ": " + msg)
+        if self.display_status is not None:
+            self.display_status.message = f"WARNING: {title} (check the console for details)"

This avoids rare but nasty runtime errors from malformed CONSOLE_ECHO calls or from unusual setups lacking display_status.

♻️ Duplicate comments (4)
configuration/klippy/beacon_adaptive_heat_soak.py (4)

78-96: Training data path is still tightly bound to module location

_load_training_data() only looks for beacon_adaptive_heat_soak_model_training.csv next to this module. That’s usually fine, but it’s brittle if the file lives in the config dir or the module is packaged differently.

Consider the earlier suggestion to fall back to the printer’s config directory, e.g.:

-        path = os.path.join(
-            os.path.dirname(os.path.realpath(__file__)),
-            'beacon_adaptive_heat_soak_model_training.csv')
+        module_dir = os.path.dirname(os.path.realpath(__file__))
+        path = os.path.join(module_dir, 'beacon_adaptive_heat_soak_model_training.csv')
+        if not os.path.exists(path):
+            config_path = os.path.join(self.printer.get_config_dir(),
+                                       'beacon_adaptive_heat_soak_model_training.csv')
+            if os.path.exists(config_path):
+                path = config_path

This keeps behavior for the common case but is more robust across installs.


497-585: Z‑rate loop and progress handling are solid; consider exception chaining

The main adaptive soak loop correctly:

  • Enforces MAXIMUM_WAIT
  • Streams Z‑rates from BeaconZRateSession
  • Maintains moving and level‑2 averages, hold counts, and trend checks
  • Feeds progress via BackgroundDisplayStatusProgressHandler and always disables it in finally.

To preserve original tracebacks when wrapping failures from get_next_z_rate(), you could use explicit chaining:

-        except Exception as e:
+        except Exception as e:
             if self.printer.is_shutdown():
                 raise
             else:
-                raise self.printer.command_error(f"Error calculating Z-rate, wait ended prematurely: {e}")
+                raise self.printer.command_error(
+                    f"Error calculating Z-rate, wait ended prematurely: {e}"
+                ) from e

Same pattern applies in cmd_BEACON_WAIT_FOR_PRINTER_HEAT_SOAK_CAPTURE_Z_RATES.


639-680: Hardcoded config paths under /home/pi/printer_data/config

Both diagnostic commands write to fixed paths under /home/pi/printer_data/config/:

  • cmd_BEACON_WAIT_FOR_PRINTER_HEAT_SOAK_CAPTURE_Z_RATES: fullpath = f'/home/pi/printer_data/config/{filename}'
  • cmd_BEACON_WAIT_FOR_PRINTER_HEAT_SOAK_CAPTURE_BEACON_SAMPLES: filename = f'/home/pi/printer_data/config/...txt'

This assumes a specific user/home and layout and will misbehave on non‑pi setups. Prefer deriving the base from Klipper’s config dir:

-        fullpath = f'/home/pi/printer_data/config/{filename}'
+        config_dir = self.printer.get_config_dir()
+        fullpath = os.path.join(config_dir, filename)

and similarly for the beacon samples filename.


7-10: Ensure pygam is declared and installed (dependency hygiene)

This module imports and relies on pygam for the GAM model in ThresholdPredictor. Please make sure pygam is listed in your project’s install manifests (e.g. requirements, setup, or packaging metadata) and covered by your deployment/CI setup so prediction doesn’t fail at runtime on a missing module.

🧹 Nitpick comments (3)
configuration/klippy/ratos.py (1)

803-870: BackgroundDisplayStatusProgressHandler is a good fit for long‑running flows

The periodic timer, spinner sequence, and capped progress value provide a simple, reusable way to surface background progress (e.g. adaptive heat soak) via display_status.message. If you later need UI progress bars, consider also updating self.display_status.progress = self._progress inside _handle_timer, but it’s fine as‑is for the current text‑only usage.

configuration/klippy/beacon_mesh.py (1)

1028-1092: load_extra_mesh_params migration path is sensible, but logs could help on config errors

The migration from per‑profile config sections into mesh_params is well thought out (version gating, incompatible profile tracking, and optional chamber/bounds metadata). In the except Exception: around getsection, you silently continue; if you ever need to debug mis‑named sections, a debug_echo there could be useful, but that’s optional.

configuration/z-probe/beacon.cfg (1)

658-741: IDEX‑aware nozzle expansion compensation logic looks correct

_BEACON_SET_NOZZLE_TEMP_OFFSET now:

  • Avoids applying compensation unless both true‑zero and expansion‑compensation features are enabled.
  • Handles IDEX modes by only applying the offset to the active/applicable toolhead (with clear RATOS_ECHO and DEBUG_ECHO when skipped).
  • Derives the expansion offset from calibrated coefficients, multiplier, beacon_contact_true_zero_temp, and current target temperature.
  • Tracks and reuses nozzle_expansion_applied_offset to make adjustments idempotent.

You might consider defaulting svv.idex_zoffset to 0.0 in the lookup, but overall the logic and guardrails look sound.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5623a21 and 44a4174.

📒 Files selected for processing (10)
  • configuration/klippy/beacon_adaptive_heat_soak.py (1 hunks)
  • configuration/klippy/beacon_mesh.py (3 hunks)
  • configuration/klippy/ratos.py (10 hunks)
  • configuration/printers/base.cfg (1 hunks)
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg (1 hunks)
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1 hunks)
  • configuration/printers/v-core-4/v-core-4.cfg (1 hunks)
  • configuration/scripts/ratos-common.sh (1 hunks)
  • configuration/scripts/ratos-install.sh (1 hunks)
  • configuration/z-probe/beacon.cfg (18 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • configuration/scripts/ratos-common.sh
  • configuration/scripts/ratos-install.sh
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/base.cfg
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-28T19:09:05.023Z
Learnt from: miklschmidt
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/printers/v-core-4/v-core-4.cfg:7-9
Timestamp: 2025-07-28T19:09:05.023Z
Learning: In Klipper configuration files, duplicate sections (like `[gcode_macro RatOS]`) do not cause errors. Instead, Klipper uses config section merging where later section parameters (chronologically) take precedence over earlier ones. This means multiple definitions of the same section are allowed and the last one processed will override parameters from earlier definitions.

Applied to files:

  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
📚 Learning: 2025-06-16T16:44:30.280Z
Learnt from: LucidityCrash
Repo: Rat-OS/RatOS-configurator PR: 89
File: src/templates/v-core-pro.ts:18-20
Timestamp: 2025-06-16T16:44:30.280Z
Learning: In the RatOS configurator project, v-core-pro configuration files are stored in `configuration/printers/v-core-pro/` in the source repository, but are accessed via `RatOS/printers/v-core-pro/` paths in the deployed/installed environment. The include statements in templates should use the runtime paths, not the source repository paths.

Applied to files:

  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
🧬 Code graph analysis (3)
configuration/klippy/beacon_mesh.py (2)
configuration/klippy/ratos.py (8)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • debug_echo (543-544)
  • console_echo (546-572)
  • get_beacon_probing_regions (607-628)
  • enable (823-828)
  • disable (830-837)
  • progress (840-841)
  • progress (844-845)
configuration/klippy/beacon_true_zero_correction.py (1)
  • _probe_finalize (400-426)
configuration/klippy/ratos.py (1)
configuration/klippy/beacon_mesh.py (1)
  • get_profiles (323-336)
configuration/klippy/beacon_adaptive_heat_soak.py (1)
configuration/klippy/ratos.py (6)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • set_auto_rate (847-853)
  • enable (823-828)
  • progress (840-841)
  • progress (844-845)
  • disable (830-837)
🪛 Ruff (0.14.7)
configuration/klippy/beacon_mesh.py

205-205: Unused method argument: gcmd

(ARG002)


237-237: Avoid specifying long messages outside the exception class

(TRY003)


299-299: Avoid specifying long messages outside the exception class

(TRY003)


321-321: Avoid specifying long messages outside the exception class

(TRY003)


354-354: Avoid specifying long messages outside the exception class

(TRY003)


388-388: Avoid specifying long messages outside the exception class

(TRY003)


420-420: Avoid specifying long messages outside the exception class

(TRY003)


423-423: Avoid specifying long messages outside the exception class

(TRY003)


446-446: Avoid specifying long messages outside the exception class

(TRY003)


453-453: Avoid specifying long messages outside the exception class

(TRY003)


460-460: Avoid specifying long messages outside the exception class

(TRY003)


463-463: Avoid specifying long messages outside the exception class

(TRY003)


499-499: Avoid specifying long messages outside the exception class

(TRY003)


531-531: Avoid specifying long messages outside the exception class

(TRY003)


541-541: Avoid specifying long messages outside the exception class

(TRY003)


546-546: Consider moving this statement to an else block

(TRY300)


548-548: Avoid specifying long messages outside the exception class

(TRY003)


548-548: Use explicit conversion flag

Replace with conversion flag

(RUF010)


562-562: Avoid specifying long messages outside the exception class

(TRY003)


635-635: Avoid specifying long messages outside the exception class

(TRY003)


710-710: Consider moving this statement to an else block

(TRY300)


724-724: Do not catch blind exception: Exception

(BLE001)


748-751: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


748-751: Create your own exception

(TRY002)


748-751: Avoid specifying long messages outside the exception class

(TRY003)


1026-1026: Avoid specifying long messages outside the exception class

(TRY003)


1026-1026: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1040-1042: try-except-continue detected, consider logging the exception

(S112)


1040-1040: Do not catch blind exception: Exception

(BLE001)


1057-1057: Abstract raise to an inner function

(TRY301)


1057-1057: Avoid specifying long messages outside the exception class

(TRY003)


1063-1063: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1100-1100: Avoid specifying long messages outside the exception class

(TRY003)


1102-1102: Avoid specifying long messages outside the exception class

(TRY003)


1161-1161: Do not catch blind exception: Exception

(BLE001)


1191-1191: Avoid specifying long messages outside the exception class

(TRY003)


1205-1205: Do not catch blind exception: Exception

(BLE001)


1260-1260: Avoid specifying long messages outside the exception class

(TRY003)


1300-1300: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1300-1300: Avoid specifying long messages outside the exception class

(TRY003)


1300-1300: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1314-1314: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1329-1329: Avoid specifying long messages outside the exception class

(TRY003)


1359-1359: Do not catch blind exception: Exception

(BLE001)


1387-1390: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1387-1390: Create your own exception

(TRY002)


1387-1390: Avoid specifying long messages outside the exception class

(TRY003)


1393-1396: Create your own exception

(TRY002)


1393-1396: Avoid specifying long messages outside the exception class

(TRY003)


1546-1546: Avoid specifying long messages outside the exception class

(TRY003)


1563-1563: Avoid specifying long messages outside the exception class

(TRY003)


1572-1572: Avoid specifying long messages outside the exception class

(TRY003)


1600-1600: Avoid specifying long messages outside the exception class

(TRY003)


1620-1620: Avoid specifying long messages outside the exception class

(TRY003)


1643-1643: Avoid specifying long messages outside the exception class

(TRY003)


1660-1660: Avoid specifying long messages outside the exception class

(TRY003)


1688-1688: Avoid specifying long messages outside the exception class

(TRY003)


1722-1722: Avoid specifying long messages outside the exception class

(TRY003)


1731-1731: Avoid specifying long messages outside the exception class

(TRY003)


1772-1772: Avoid specifying long messages outside the exception class

(TRY003)


1812-1813: Avoid specifying long messages outside the exception class

(TRY003)


1822-1822: Avoid specifying long messages outside the exception class

(TRY003)


1834-1836: Avoid specifying long messages outside the exception class

(TRY003)


1840-1842: Avoid specifying long messages outside the exception class

(TRY003)


1899-1899: Function definition does not bind loop variable secondary_idx

(B023)

configuration/klippy/ratos.py

249-249: Avoid specifying long messages outside the exception class

(TRY003)


269-269: Do not catch blind exception: Exception

(BLE001)


270-270: Use explicit conversion flag

Replace with conversion flag

(RUF010)


276-276: Do not catch blind exception: Exception

(BLE001)


277-277: Use explicit conversion flag

Replace with conversion flag

(RUF010)


285-285: Avoid specifying long messages outside the exception class

(TRY003)


516-516: Consider moving this statement to an else block

(TRY300)


661-661: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


663-663: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


696-696: Unused method argument: eventtime

(ARG002)


713-713: Unused method argument: gcmd

(ARG002)

configuration/klippy/beacon_adaptive_heat_soak.py

44-44: Do not catch blind exception: Exception

(BLE001)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


89-89: Avoid specifying long messages outside the exception class

(TRY003)


94-94: Create your own exception

(TRY002)


94-94: Avoid specifying long messages outside the exception class

(TRY003)


179-179: Avoid specifying long messages outside the exception class

(TRY003)


184-184: Avoid specifying long messages outside the exception class

(TRY003)


232-232: Avoid specifying long messages outside the exception class

(TRY003)


366-366: Avoid specifying long messages outside the exception class

(TRY003)


372-372: Avoid specifying long messages outside the exception class

(TRY003)


372-372: f-string without any placeholders

Remove extraneous f prefix

(F541)


409-409: Avoid specifying long messages outside the exception class

(TRY003)


415-415: Avoid specifying long messages outside the exception class

(TRY003)


424-424: Avoid specifying long messages outside the exception class

(TRY003)


427-427: Avoid specifying long messages outside the exception class

(TRY003)


498-498: Probable insecure usage of temporary file or directory: "/tmp/heat_soak_"

(S108)


525-525: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


525-525: Avoid specifying long messages outside the exception class

(TRY003)


619-619: Avoid equality comparisons to True; use moving_average_trend_checks_passed: for truth checks

Replace with moving_average_trend_checks_passed

(E712)


619-619: Avoid equality comparisons to True; use level_2_moving_average_trend_checks_passed: for truth checks

Replace with level_2_moving_average_trend_checks_passed

(E712)


642-642: Avoid specifying long messages outside the exception class

(TRY003)


645-645: Avoid specifying long messages outside the exception class

(TRY003)


670-670: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


670-670: Avoid specifying long messages outside the exception class

(TRY003)


696-696: Avoid specifying long messages outside the exception class

(TRY003)


699-699: Avoid specifying long messages outside the exception class

(TRY003)


714-714: Avoid specifying long messages outside the exception class

(TRY003)


721-721: Function definition does not bind loop variable samples

(B023)

🔇 Additional comments (26)
configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1)

7-12: Adaptive heat soak + split_delta_z wiring looks correct

Enabling variable_beacon_adaptive_heat_soak: True here cleanly ties this printer into the new adaptive heat soak flow, and the local [bed_mesh] split_delta_z: 0.001 override is safe and consistent with the other Beacon‑ready configs. Klipper’s section‑merge behavior means this extra [gcode_macro RatOS] block will just augment/override earlier defaults as intended.

Based on learnings, multiple [gcode_macro RatOS] sections are merged with later values winning.

configuration/klippy/ratos.py (4)

607-650: Beacon probing region + safe home validation looks sound

get_beacon_probing_regions() and get_safe_home_position() correctly centralize beacon geometry and enforce that the configured safe‑home lies inside the intersection of contact and proximity probing bounds, with a controlled shutdown if it doesn’t. The status exposure via get_status() and use in _MOVE_TO_SAFE_Z_HOME give macros a clean, validated API.


651-695: _MOVE_TO_SAFE_Z_HOME fuzzy mode and clamping behavior

The fuzzy‑radius logic (random point within a circle, then clamped to the beacon region or printable area) is well‑bounded and logs when clamping alters the intended position. That’s a good trade‑off between randomness and safety, and the recorded last_move_to_safe_z_home_position is useful for debugging.


696-705: get_status extension is consistent with new state fields

Exposing last_check_bed_mesh_profile_exists_result, safe_home_position, and last_move_to_safe_z_home_position in get_status() aligns with how the macros use printer.ratos.* in beacon.cfg. The unused eventtime arg is standard for Klipper status objects and can be left as‑is.


711-801: Stack‑trace utilities are well‑scoped and opt‑in

cmd_DEBUG_ECHO_STACK_TRACE, get_function_arguments_of_type, and get_formatted_extended_stack_trace are only active when DEBUG_ECHO is enabled, and they avoid emitting frames without useful GCode context. The callback pattern and use of traceback.FrameSummary are appropriate; no functional concerns.

configuration/klippy/beacon_adaptive_heat_soak.py (3)

323-375: Beacon prep retry loop and timeout handling look reasonable

The three‑attempt wrapper around _prepare_for_sampling_and_get_sampling_frequency_core() and the 5‑second / 1000‑good‑sample gating handle known flakiness without blocking the reactor excessively. The final command_error on insufficient good samples gives a clear, user‑visible failure mode. No functional issues here.


421-451: Threshold prediction + forced threshold wiring is consistent

Mapping LAYER_QUALITY → max Z‑change microns, deriving the period from MAXIMUM_FIRST_LAYER_DURATION + 120, and feeding that into ThresholdPredictor matches the documented assumptions. The forced _FORCE_THRESHOLD path logs clearly and bypasses the predictor cleanly.


731-749: Duration formatting helper is correct and readable

_format_seconds() covers all hour/minute/second combinations cleanly and is used in user‑facing messages, which should help users interpret waits and thresholds. No issues here.

configuration/klippy/beacon_mesh.py (8)

323-337: Profile filtering helper get_profiles looks correct

The helper cleanly restricts to RatOS‑compatible profiles (ratos_mesh_version present) and optionally filters by ratos_mesh_kind. This matches how auto_select_compensation_mesh expects its input.


338-405: Automatic compensation mesh selection behavior is well designed

auto_select_compensation_mesh:

  • Filters to RATOS_MESH_KIND_COMPENSATION profiles
  • Falls back to nominal bed temp when bed_temperature is omitted
  • Detects ambiguous “equally good” profiles and errors out with a detailed console message
  • Warns for large bed‑temperature mismatches

This is a nice safety net around automatic selection; no functional issues spotted.


716-799: Local‑low filter multiprocessing helper is appropriate

_apply_local_low_filter()’s use of a child process with a Pipe to offload the numerically heavy _do_local_low_filter() keeps reactor load bounded. The error propagation via RatOSBeaconMeshError("Error applying local-low filter: %s" % (result,)) is clear and scoped to this feature. No correctness issues seen.


800-1024: Cotemporal compensation mesh creation is consistent with Beacon regions and helpers

In create_compensation_mesh:

  • Beacon probing bounds come from RatOS.get_beacon_probing_regions(), and you intersect contact/proximity regions to define the safe area.
  • You sensibly fall back from cotemporal offset‑aligned probing to point‑by‑point probing when can_use_offset_aligned_probing() says no.
  • Progress is surfaced via BackgroundDisplayStatusProgressHandler in both branches and always disabled in finally.
  • Temporary meshes and extra metadata are only created when requested (KEEP_TEMP_MESHES), and final compensation meshes are tagged with RatOS mesh parameters.

This is complex but internally consistent; I don’t see logic errors in the probing/spacing or mesh‑saving flow.


1197-1262: De‑ridging filter implementation is straightforward and axis‑safe

_do_apply_deridging_filter handles both primary axes with simple 1D smoothing and correctly treats edge rows/columns. The primary_axis validation raising ValueError for anything else is appropriate and bubbles up nicely through your multiprocessing wrapper.


1710-1790: Cotemporal probing capability checks are clear and conservative

can_use_offset_aligned_probing()’s validation of beacon offsets against minimum_spacing and MAXIMUM_SECONDARY_BEACON_OFFSET is a good guardrail. Errors are raised as RatOSBeaconMeshError with detailed messages, which is exactly what the compensation‑mesh path needs.


1791-1918: Offset‑aligned probe action sequence logic is intricate but consistent

generate_probe_action_sequence_beacon_offset_aligned carefully:

  • Validates desired vs minimum spacing
  • Enforces bounds on secondary offset
  • Picks primary/secondary axes based on offsets
  • Computes a resolution from the primary offset and rounds it
  • Generates a serpentine pattern over the bed with leading/trailing probe order dependent on beacon lead/lag
  • Ensures contact and proximity points align correctly via ProbeAction.

The use of offset_divisor and the three phases (initial, paired, trailing) is coherent; I don’t see an obvious indexing or bounds error here.


1351-1430: Use consistent exception types for SciPy dependency checks

_do_interpolate_faulty_region_values relies on scipy and scipy.interpolate.RBFInterpolator. When SciPy is missing or lacks RBFInterpolator, raise RatOSBeaconMeshError instead of bare Exception for consistency with the error handling already present in this function (line 1374):

-        if not self.scipy:
+        if not self.scipy:
             try:
                 self.scipy = importlib.import_module("scipy")
             except ImportError:
-                raise Exception(
+                raise RatOSBeaconMeshError(
                     "Could not load `scipy`. To install it, simply run `ratos doctor`. This "
                     "module is required for Beacon contact compensation mesh creation."
                 )
@@
-        if not hasattr(self.scipy.interpolate, "RBFInterpolator"):
-            raise Exception(
+        if not hasattr(self.scipy.interpolate, "RBFInterpolator"):
+            raise RatOSBeaconMeshError(
                 "The RBFInterpolator class is missing from the scipy module. Try using `ratos doctor`. This "
                 "class is required for Beacon contact compensation mesh creation."
             )

Also verify that scipy is declared in your project's install manifests.

configuration/z-probe/beacon.cfg (10)

205-215: already_heated flag wiring in BEACON_RATOS_CALIBRATE is correct

Tracking already_heated to avoid re‑heating during BEACON_FINAL_CALIBRATION when a scan‑compensation mesh was just created is a nice optimization and is passed through correctly via _AUTOMATED_ALREADY_HEATED. No issues.


276-338: Adaptive‑vs‑fixed heat soak in BEACON_FINAL_CALIBRATION

The calibration macro cleanly switches between:

  • Adaptive soak (BEACON_WAIT_FOR_PRINTER_HEAT_SOAK with a relaxed forced threshold and min/max waits from RatOS variables), plus optional extra post‑completion wait.
  • Legacy fixed‑time bed soak (bed_heat_soak_time) when adaptive is disabled.

The guard on already_heated also correctly skips the entire heating/soak block when the earlier scan‑compensation step has already done the work.


386-403: Use of fastconfig for z_hop_speed is appropriate

Switching from macro variables to printer.fastconfig.config.ratos_homing.z_hop_speed in both BEACON_FINAL_CALIBRATION and BEACON_POKE_TEST centralizes the z‑hop speed in the fastconfig tree, which is consistent with the rest of the PR.


769-847: BEACON_MEASURE_BEACON_OFFSET correctly leverages safe_home_position

The offset‑measurement macro:

  • Uses (safe_home_x, safe_home_y) = printer.ratos.safe_home_position, which is exactly what the new RatOS status exposes.
  • Probes a sensible 3×3 pattern (center, edges, corners) within printable bounds derived from printable_x_max/printable_y_max and margins.
  • Stores relative offsets and summarises them via _BEACON_ECHO_BEACON_OFFSET.

This is a good consumer of the new safe‑home and beacon‑region logic.


918-1059: Scan compensation macro cleanly composes the new Python helpers

BEACON_CREATE_SCAN_COMPENSATION_MESH:

  • Wires user parameters (BED_TEMP, CHAMBER_TEMP, PROFILE, KEEP_TEMP_MESHES) straight through to _BEACON_CREATE_SCAN_COMPENSATION_MESH_CORE.
  • Handles adaptive heat soak vs fixed bed/hotend soak consistently with BEACON_FINAL_CALIBRATION.
  • Forces ABL (Z_TILT / QGL) before compensation and re‑homes Z where appropriate.
  • Restores heaters and chamber appropriately, and gives clear console feedback.

The use of _MOVE_TO_SAFE_Z_HOME and the IDEX activation block matches the rest of the RatOS flows.


1062-1072: _BEACON_APPLY_SCAN_COMPENSATION_IF_ENABLED is a nice guard macro

This macro simply logs the current profile + enable flag and conditionally calls BEACON_APPLY_SCAN_COMPENSATION PROFILE="...". It’s a low‑risk shim that helps keep higher‑level macros concise.


1074-1092: Preflight Beacon model check before START_PRINT is well‑targeted

_START_PRINT_PREFLIGHT_CHECK_BEACON_MODEL:

  • Uses fastconfig to detect Beacon usage and Z endstop mode.
  • Distinguishes between configurations that require an existing Beacon model (true‑zero without per‑print calibration, or proximity homing with a model) vs those that don’t.
  • Fails early with a clear error and LED indication when a model is required but missing.

This should prevent a lot of confusing mid‑print failures.


1096-1111: Preflight scan‑compensation profile validation is a good safety net

_START_PRINT_PREFLIGHT_CHECK_BEACON_SCAN_COMPENSATION computes a bed temperature (either from params or current heater) and, when compensation is enabled, delegates to _VALIDATE_COMPENSATION_MESH_PROFILE with COMPARE_BED_TEMP and the “mismatch is error” flag. That matches the new validation logic in beacon_mesh.py and will surface misconfigured profiles before printing.


1208-1216: Z_OFFSET_APPLY_PROBE override for runtime offset is coherent

Overriding Z_OFFSET_APPLY_PROBE to:

  • Use _BEACON_SET_RUNTIME_OFFSET {rawparams} when Beacon is configured and beacon_contact_start_print_true_zero is enabled.
  • Fall back to _Z_OFFSET_APPLY_PROBE_BASE otherwise

is a clean way to route true‑zero setups through RatOS’s runtime‑offset management while preserving default Klipper behavior for other setups.


1218-1228: Runtime offset restore macros are consistent with the new save path

_BEACON_RESTORE_RUNTIME_OFFSET and _BEACON_RESTORE_RUNTIME_OFFSET_LOG_BEFORE_AFTER correctly:

  • Load beacon_saved_runtime_offset from save_variables
  • Apply it via SET_GCODE_OFFSET Z_ADJUST=...
  • Log both the stored value and before/after offsets with DEBUG_ECHO

This closes the loop with _BEACON_SET_RUNTIME_OFFSET.

@tg73
Copy link
Collaborator Author

tg73 commented Dec 2, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
configuration/klippy/beacon_adaptive_heat_soak.py (2)

653-653: Hardcoded path /home/pi still present.

This was flagged in a past review and marked as addressed, but the hardcoded path remains. This will fail for users with different usernames.

The past review suggested using self.printer.get_config_dir() or a similar approach to dynamically resolve the path.


707-707: Hardcoded path /home/pi still present.

Same issue as line 653 - this hardcoded path should be replaced with a dynamic resolution.

-		filename = f'/home/pi/printer_data/config/beacon_adaptive_heat_soak_beacon_samples_{timestamp}.txt'
+		config_dir = self.printer.get_config_dir()
+		filename = os.path.join(config_dir, f'beacon_adaptive_heat_soak_beacon_samples_{timestamp}.txt')
🧹 Nitpick comments (7)
configuration/klippy/beacon_adaptive_heat_soak.py (3)

91-94: Consider using a more specific exception type.

Re-raising as a generic Exception loses the specific error type. While the from e chaining preserves the traceback, consider using a custom exception or preserving the original type for better error handling upstream.

 		try:
 			data = np.genfromtxt(path, delimiter=',', names=True)
 		except Exception as e:
-			raise Exception(f"Failed to load model training data: {e}") from e
+			raise IOError(f"Failed to load model training data: {path}") from e

197-199: Consider using collections.deque for O(1) sliding window operations.

Using list.pop(0) is O(n) for each removal. With window_size=30, the impact is minimal, but switching to collections.deque(maxlen=window_size) would provide O(1) popleft and automatic size limiting.

+from collections import deque
+
 class BeaconZRateSession:
 	def __init__(self, config, beacon, samples_per_mean=1000, window_size=30, window_step=1):
 		# ... existing code ...
-		self._mean_distances = []
-		self._times = []
+		self._mean_distances = deque(maxlen=window_size)
+		self._times = deque(maxlen=window_size)

Then simplify get_next_z_rate:

-		if len(self._mean_distances) == self.window_size:
-			self._mean_distances.pop(0)
-			self._times.pop(0)
+		# deque with maxlen handles removal automatically

267-291: Redundant reactor initialization followed by overwrite to None.

Line 267 sets self.reactor from printer.get_reactor(), but line 290 immediately overwrites it to None. This is then set again in _handle_connect. The initial assignment at line 267 is unnecessary and potentially confusing.

 	def __init__(self, config):
 		self.config = config
 		self.name = config.get_name()
 		self.printer = config.get_printer()
-		self.reactor = self.printer.get_reactor()
 		self.gcode = self.printer.lookup_object('gcode')
 
 		# ... configuration values ...
 
 		# Setup
 		self.reactor = None
 		self.beacon = None
configuration/klippy/beacon_true_zero_correction.py (4)

99-109: Unused handler parameters can be prefixed to clarify intent

rails and print_time are unused but required by the event signatures. To make this explicit (and silence ARG002), consider prefixing them with an underscore.

-	def _handle_homing_move_end(self, homing_state, rails):
+	def _handle_homing_move_end(self, homing_state, _rails):
@@
-	def _handle_motor_off(self, print_time):
+	def _handle_motor_off(self, _print_time):

130-207: Tighten diagnostics error handling and f-string usage

The diagnostics flow and CSV capture logic are well structured. Two small improvements:

  1. Include the actual ACTION value in the “unknown action” error while fixing the f-string-without-placeholders issue.
  2. (Optional) The hard-coded /home/pi/... path may not fit all installs; consider deriving it from configuration in the future.
-		else:
-			raise self.gcode.error(f"Unknown action.")
+		else:
+			# Include action name for easier debugging.
+			raise self.gcode.error(f"Unknown action '{action}'.")

339-378: Prefer a more specific exception type for repeat run() calls

The single-run guard is good, but raising a bare Exception is a bit coarse. A standard runtime error reads better and aligns with Ruff’s TRY002 suggestion.

-		if self._has_run:
-			raise Exception("ProbingSession has already been run, and cannot be run more than once.")
+		if self._has_run:
+			raise RuntimeError("ProbingSession has already been run and cannot be run more than once.")

400-426: Retry logic is correct; consider whether max_retries should be a hard cap

Filtering z-values by z_rejection_threshold, sorting, and using the minimal subset is solid. Currently, max_retries only affects how many extra points are pre-generated, not how many retry cycles are allowed. If you intended it as a strict retry cap, you could incorporate self.retries into the decision to set _finalize_result = 'retry'.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44a4174 and 81571c9.

📒 Files selected for processing (3)
  • configuration/klippy/beacon_adaptive_heat_soak.py (1 hunks)
  • configuration/klippy/beacon_true_zero_correction.py (1 hunks)
  • configuration/klippy/ratos_z_offset.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-28T19:09:05.023Z
Learnt from: miklschmidt
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/printers/v-core-4/v-core-4.cfg:7-9
Timestamp: 2025-07-28T19:09:05.023Z
Learning: In Klipper configuration files, duplicate sections (like `[gcode_macro RatOS]`) do not cause errors. Instead, Klipper uses config section merging where later section parameters (chronologically) take precedence over earlier ones. This means multiple definitions of the same section are allowed and the last one processed will override parameters from earlier definitions.

Applied to files:

  • configuration/klippy/ratos_z_offset.py
🧬 Code graph analysis (1)
configuration/klippy/beacon_true_zero_correction.py (2)
configuration/klippy/ratos_z_offset.py (1)
  • set_offset (74-78)
configuration/klippy/ratos.py (2)
  • get_beacon_probing_regions (607-628)
  • console_echo (546-572)
🪛 Ruff (0.14.7)
configuration/klippy/ratos_z_offset.py

83-83: Avoid specifying long messages outside the exception class

(TRY003)


113-113: Unused method argument: eventtime

(ARG002)

configuration/klippy/beacon_true_zero_correction.py

87-87: Avoid specifying long messages outside the exception class

(TRY003)


99-99: Unused method argument: rails

(ARG002)


105-105: Unused method argument: print_time

(ARG002)


207-207: Avoid specifying long messages outside the exception class

(TRY003)


207-207: f-string without any placeholders

Remove extraneous f prefix

(F541)


236-238: Avoid specifying long messages outside the exception class

(TRY003)


305-305: Avoid specifying long messages outside the exception class

(TRY003)


341-341: Create your own exception

(TRY002)


341-341: Avoid specifying long messages outside the exception class

(TRY003)


385-385: Avoid specifying long messages outside the exception class

(TRY003)


393-393: Avoid specifying long messages outside the exception class

(TRY003)


398-398: Avoid specifying long messages outside the exception class

(TRY003)

configuration/klippy/beacon_adaptive_heat_soak.py

44-44: Do not catch blind exception: Exception

(BLE001)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


89-89: Avoid specifying long messages outside the exception class

(TRY003)


94-94: Create your own exception

(TRY002)


94-94: Avoid specifying long messages outside the exception class

(TRY003)


179-179: Avoid specifying long messages outside the exception class

(TRY003)


184-184: Avoid specifying long messages outside the exception class

(TRY003)


232-232: Avoid specifying long messages outside the exception class

(TRY003)


366-366: Avoid specifying long messages outside the exception class

(TRY003)


372-372: Avoid specifying long messages outside the exception class

(TRY003)


409-409: Avoid specifying long messages outside the exception class

(TRY003)


415-415: Avoid specifying long messages outside the exception class

(TRY003)


424-424: Avoid specifying long messages outside the exception class

(TRY003)


427-427: Avoid specifying long messages outside the exception class

(TRY003)


498-498: Probable insecure usage of temporary file or directory: "/tmp/heat_soak_"

(S108)


525-525: Avoid specifying long messages outside the exception class

(TRY003)


619-619: Avoid equality comparisons to True; use moving_average_trend_checks_passed: for truth checks

Replace with moving_average_trend_checks_passed

(E712)


619-619: Avoid equality comparisons to True; use level_2_moving_average_trend_checks_passed: for truth checks

Replace with level_2_moving_average_trend_checks_passed

(E712)


642-642: Avoid specifying long messages outside the exception class

(TRY003)


645-645: Avoid specifying long messages outside the exception class

(TRY003)


670-670: Avoid specifying long messages outside the exception class

(TRY003)


696-696: Avoid specifying long messages outside the exception class

(TRY003)


699-699: Avoid specifying long messages outside the exception class

(TRY003)


714-714: Avoid specifying long messages outside the exception class

(TRY003)


721-721: Function definition does not bind loop variable samples

(B023)

🔇 Additional comments (24)
configuration/klippy/beacon_adaptive_heat_soak.py (6)

37-61: Multiprocessing implementation looks solid for reactor compatibility.

The use of multiprocessing.Pipe with reactor.pause polling ensures the main thread remains responsive to Klipper's reactor while waiting for the prediction to complete. The daemon process is appropriate here since it's short-lived and always joined before the method returns.


224-260: Clean and efficient circular buffer implementation.

The running sum approach provides O(1) operations for both add and get_average. The implementation correctly handles the transition from filling to rotating the buffer.


716-721: Loop variable samples captured in nested function is safe here.

The static analysis warning (B023) about samples being captured in the closure is a false positive in this case. The samples list is recreated on each iteration of the outer while loop before defining cb, and the streaming session completes before the next iteration.


496-498: Using /tmp for transient debug data is acceptable.

The static analysis warning (S108) about insecure /tmp usage is a false positive here. This file contains transient diagnostic Z-rate data that doesn't need to persist across reboots, and the timestamped filename prevents collisions.


731-748: Clean time formatting utility.

The _format_seconds method handles all edge cases correctly (hours only, minutes only, seconds only, and combinations).


750-751: Standard Klipper config loader pattern.

The load_config function follows the expected Klipper module pattern.

configuration/klippy/ratos_z_offset.py (8)

1-9: LGTM!

The module header and constant definitions are clear and appropriate. The offset names are well-defined and the combined offset key is properly distinguished.


10-29: LGTM!

The class initialization follows standard Klipper patterns. Event handler registration, G-code command registration, and instance variable initialization are all properly implemented.


37-66: LGTM! Duplication issue successfully addressed.

The G-code command implementations are well-structured. The SET_RATOS_Z_OFFSET command now correctly uses the refactored _validate_and_set_offset method, which addresses the code duplication concern raised in the previous review.


67-88: LGTM! Well-refactored offset management.

The offset management methods are clean and well-structured:

  • The _validate_and_set_offset method successfully eliminates the duplication identified in the previous review
  • The combined offset calculation using sum() is efficient
  • Resetting the last position after offset changes ensures consistency with the gcode_move system
  • The zero-value handling (removing from dict) keeps the storage clean

Note: Static analysis flags the error message on line 83 (TRY003), but the inline message is appropriate here for clarity and context.


92-105: LGTM! Transform logic is correctly implemented.

The gcode_move transform interface implementation is correct:

  • get_position removes the offset from Z, returning the true position to the caller
  • move adds the offset to Z, transparently applying the correction during movement

This pattern ensures that G-code commands work with logical coordinates while the physical movement incorporates all registered offsets.


109-117: LGTM! Status tracking is properly implemented.

The status methods correctly maintain and expose offset information:

  • Status is lazily initialized and updated when offsets change
  • The dict includes both individual offsets and the combined value

Note: Static analysis flags eventtime as unused (ARG002) on line 113, but this parameter is required by Klipper's get_status interface and cannot be removed.


118-119: LGTM!

The module loading function follows the standard Klipper pattern for extension loading.


30-33: No action required. The force=True parameter is necessary for proper transform chain insertion in Klipper's architecture. Z-offset handlers must override existing transforms to apply corrections at the correct position in the transform stack.

configuration/klippy/beacon_true_zero_correction.py (10)

18-76: Config-driven enable/disable and event wiring look correct

Config gates (disabled, presence of [beacon]) and event handler registration are consistent with Klipper patterns; overall initialization logic is sound.


77-98: Command wrapping of BEACON_AUTO_CALIBRATE is robust

Preserving the original handler via register_command(..., None) and failing fast if it is missing is a good pattern; the added diagnostics command registration is also clean.


110-129: BEACON_AUTO_CALIBRATE wrapper and multi-point probing trigger look good

Resetting true_zero_correction, honoring SKIP_MULTIPOINT_PROBING, and then running the multi-point session around the original command is a clear and minimally-invasive integration.


212-217: Homing check is straightforward and consistent

Using toolhead.get_status(...).homed_axes and raising self.gcode.error when any of x/y/z is missing is consistent with other RatOS modules.


218-240: Point generation logic is correct and defensive

The random point generator correctly enforces min_dist from both center (when requested) and existing points, and it fails fast with a clear error if constraints are too strict for max_iter.


242-267: Nozzle geometry helpers are reasonable approximations

Extruder selection with dual carriage and the heuristic for tip diameter vs. orifice size are sensible and localized, which will make future tuning easy.


269-290: Probe command preparation is clear; SENSOR propagation is handled

The split between normal and error-corrected probing, plus conditional SENSOR propagation, is easy to follow and keeps probe arguments centralized.


307-338: ProbingSession setup and sampling strategy look solid

The session tracks retries, pre-seeds the implied zero sample, and derives _take from the configured sampling strategy; this matches the documented behavior.


379-399: Finalize logic and safety clamp are well thought out

Using _finalize_result as a state machine output, enforcing a -0.2 mm lower bound, and only then applying the correction to ratos_z_offset gives a nice safety margin against bad data.


428-430: Config hook is minimal and correct

load_config returns the extension instance as expected for Klipper modules.

@tg73
Copy link
Collaborator Author

tg73 commented Dec 2, 2025

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
configuration/klippy/ratos.py (1)

66-69: load_settings() is called twice in __init__.

The method load_settings() is invoked at both line 66 and line 69. This appears to be unintentional and should be cleaned up.

 		self.old_is_graph_files = []
 		self.load_settings()
 		self.register_commands()
 		self.register_handler()
-		self.load_settings()
 		self.post_process_success = False
configuration/macros/util.cfg (1)

397-400: Define _RAISE_ERROR macro or replace with action_raise_error().

The _STOP_AND_RAISE_ERROR macro calls _RAISE_ERROR at line 400, but _RAISE_ERROR is not a standard Klipper function and was removed from this file. Either define _RAISE_ERROR macro elsewhere in the configuration, or replace the call with action_raise_error MSG="{params.MSG}" to follow standard Klipper error handling patterns.

♻️ Duplicate comments (1)
configuration/klippy/beacon_adaptive_heat_soak.py (1)

653-653: Hardcoded path /home/pi/printer_data/config/ limits portability.

This was flagged in past reviews. The path assumes the user is pi and the config directory is at a fixed location. Consider using a dynamic approach to get the config directory.

Per past review discussion, this was noted to be addressed separately via ratos-update.sh behavior changes.

🧹 Nitpick comments (11)
configuration/macros/idex/toolheads.cfg (1)

766-766: Minor timing adjustment - verify necessity.

The initial_duration for _INIT_TOOLHEADS was increased from 0.1 to 0.2 seconds. If this addresses a race condition or initialization timing issue, consider adding a brief comment explaining the reason.

configuration/klippy/ratos.py (1)

263-277: Bare except: clause catches all exceptions including KeyboardInterrupt and SystemExit.

Using a bare except: is overly broad. Consider catching Exception explicitly to avoid suppressing critical exceptions.

 		try:
 			self.gcode.run_script_from_command(to_run)
-		except:
+		except Exception:
 			if _except:
 				try:
 					self.gcode.run_script_from_command(_except)
 				except Exception as ex:
-					self.debug_echo("TRY", f"Except command failed: {str(ex)}")
+					self.debug_echo("TRY", f"Except command failed: {ex!r}")
 			raise
 		finally:
 			if _finally:
 				try:
 					self.gcode.run_script_from_command(_finally)
 				except Exception as ex:
-					self.debug_echo("TRY", f"Finally command failed: {str(ex)}")
+					self.debug_echo("TRY", f"Finally command failed: {ex!r}")

The !r conversion flag provides a more informative repr-style output for exceptions.

configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1)

7-12: Adaptive heat soak flag and mesh tuning look fine (minor typo)

Enabling variable_beacon_adaptive_heat_soak here cleanly opts this printer into the new workflow, and bed_mesh.split_delta_z = 0.001 is a targeted tuning knob. Only nit: the comment has a typo.

-[bed_mesh]
-split_delta_z: 0.001 # Avoid visible surface stripe arfetacts
+[bed_mesh]
+split_delta_z: 0.001 # Avoid visible surface stripe artifacts

(Based on learnings, multiple [gcode_macro RatOS] sections are merged by Klipper, so this extra section is safe.)

configuration/printers/v-core-4/v-core-4.cfg (1)

7-12: Mirrored adaptive heat soak and mesh tuning (same typo)

This mirrors the idex config: enabling variable_beacon_adaptive_heat_soak and tightening bed_mesh.split_delta_z. Functionally good; same minor spelling issue in the comment.

-[bed_mesh]
-split_delta_z: 0.001 # Avoid visible surface stripe arfetacts
+[bed_mesh]
+split_delta_z: 0.001 # Avoid visible surface stripe artifacts

(Based on learnings, the extra [gcode_macro RatOS] section will merge with earlier ones rather than error.)

configuration/klippy/fastconfig.py (1)

22-41: Fastconfig wrapper design looks solid; consider minor robustness/lint tweaks

The approach of snapshotting configfile.get_status() once on klippy:connect and exposing it via a Mapping to avoid repeated deep copies is sound and should address the timer too close issues from heavy configs.

Two small polish points:

  • Initialize _immutable_status in __init__ to avoid any accidental attribute access before _handle_connect runs (e.g., from logging or introspection).
  • To satisfy linters about the unused eventtime arg while keeping the Klipper get_status(eventtime) signature, rename it to _eventtime.
 class ImmutablePrinterConfigStatusWrapper(Mapping):
 
 	def __init__(self, config):
 		self.name = config.get_name()
 		self._printer = config.get_printer()
 		self._printer.register_event_handler("klippy:connect",
 											self._handle_connect)
-		self._initialized = False	
+		self._initialized = False
+		self._immutable_status = {}
@@
-	def get_status(self, eventtime=None):
+	def get_status(self, _eventtime=None):

The explicit RuntimeError on pre-initialization access is reasonable as a hard guard as long as no macros touch printer.fastconfig before klippy:connect.

If you haven’t already, it’s worth doing a cold Klipper restart on a test printer and exercising any early delayed_gcode that might reference printer.fastconfig to confirm no pre-connect call paths exist.

configuration/macros/idex/vaoc.cfg (1)

719-740: Configurable hotend heat soak is a nice improvement

Introducing hotend_heat_soak_time (in seconds) with a default of 0 and converting to milliseconds for G4 makes the extra soak opt-in and configurable:

  • No behavioral change for existing configs (default 0 → no added wait).
  • When set, the echo and dwell are consistent with the user-specified seconds.

Looks good; just ensure hotend_heat_soak_time is documented wherever RatOS macro variables are described.

configuration/klippy/beacon_true_zero_correction.py (2)

176-176: Hardcoded path may not work on all systems.

The path /home/pi/printer_data/config/ assumes a specific user directory structure. Consider using a configurable path or deriving from Klipper's config directory.

-			filename = f'/home/pi/printer_data/config/mpp_capture_{timestamp}.csv'
+			# Consider making this path configurable or using:
+			# config_path = self.config.get_printer().get_start_args().get('config_file', '')
+			# base_dir = os.path.dirname(config_path) if config_path else '/tmp'
+			filename = f'/home/pi/printer_data/config/mpp_capture_{timestamp}.csv'

207-207: Remove unnecessary f-string prefix.

This f-string has no placeholders.

-			raise self.gcode.error(f"Unknown action.")
+			raise self.gcode.error("Unknown action.")
configuration/klippy/beacon_adaptive_heat_soak.py (1)

715-726: Loop variable samples not bound in nested function.

The static analysis hint B023 is valid here. The cb function defined inside the while loop on line 717 references samples from the enclosing scope. While this works correctly in Python (the closure captures by reference, not value), and samples is reassigned each iteration before cb is used, this pattern can be confusing and error-prone.

 			while self.reactor.monotonic() - start_time < duration:
 				if self.printer.is_shutdown():
 					raise self.printer.command_error(f"{self.name}: Printer is shutting down")
 
 				samples = []
-				def cb(s):
+				def cb(s, samples=samples):
 					unsmooth_data = s["data"]
 					unsmooth_freq = self.beacon.count_to_freq(unsmooth_data)
 					unsmooth_dist = self.beacon.freq_to_dist(unsmooth_freq, s["temp"])
 					samples.append((s["time"], s["dist"], unsmooth_dist))

However, since samples is a mutable list and is reset each iteration before cb is invoked, the current code works correctly. This is a minor stylistic concern.

configuration/klippy/beacon_mesh.py (2)

1384-1397: Add exception chaining for scipy import errors.

When re-raising exceptions, use from e to maintain the exception chain.

 		if not self.scipy:
 			try:
 				self.scipy = importlib.import_module("scipy")
 			except ImportError:
-				raise Exception(
+				raise Exception(
 					"Could not load `scipy`. To install it, simply run `ratos doctor`. This "
 					"module is required for Beacon contact compensation mesh creation."
-				)
+				) from None

Using from None explicitly indicates this is a deliberate chain break with a user-friendly message.


1038-1043: Consider logging exceptions caught during config section lookup.

Static analysis flags the bare except Exception: continue as potentially hiding errors. While this is intentional (some profiles may not have config sections), consider logging at debug level for troubleshooting.

 			try:
 				config_section_name = self.bed_mesh.pmgr.name + " " + profile_name
 				config = self.config.getsection(config_section_name)
-			except Exception:
+			except Exception as e:
 				# Skip if no config section exists for this profile
+				logging.debug(f"{self.name}: No config section for profile '{profile_name}': {e}")
 				continue
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bdffe02 and 660efe3.

⛔ Files ignored due to path filters (1)
  • configuration/klippy/beacon_adaptive_heat_soak_model_training.csv is excluded by !**/*.csv
📒 Files selected for processing (43)
  • configuration/homing.cfg (8 hunks)
  • configuration/klippy/beacon_adaptive_heat_soak.py (1 hunks)
  • configuration/klippy/beacon_mesh.py (3 hunks)
  • configuration/klippy/beacon_true_zero_correction.py (1 hunks)
  • configuration/klippy/fastconfig.py (1 hunks)
  • configuration/klippy/ratos.py (10 hunks)
  • configuration/klippy/ratos_z_offset.py (1 hunks)
  • configuration/macros.cfg (20 hunks)
  • configuration/macros/idex/idex_is.cfg (2 hunks)
  • configuration/macros/idex/toolheads.cfg (6 hunks)
  • configuration/macros/idex/util.cfg (2 hunks)
  • configuration/macros/idex/vaoc.cfg (5 hunks)
  • configuration/macros/mesh.cfg (9 hunks)
  • configuration/macros/overrides.cfg (8 hunks)
  • configuration/macros/parking.cfg (1 hunks)
  • configuration/macros/priming.cfg (7 hunks)
  • configuration/macros/util.cfg (3 hunks)
  • configuration/moonraker.conf (1 hunks)
  • configuration/printers/base.cfg (1 hunks)
  • configuration/printers/v-core-3-hybrid/macros.cfg (1 hunks)
  • configuration/printers/v-core-3-idex/macros.cfg (2 hunks)
  • configuration/printers/v-core-3/macros.cfg (1 hunks)
  • configuration/printers/v-core-4-hybrid/300.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/400.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/500.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/macros.cfg (2 hunks)
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg (1 hunks)
  • configuration/printers/v-core-4-idex/300.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/400.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/500.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/macros.cfg (2 hunks)
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1 hunks)
  • configuration/printers/v-core-4/300.cfg (0 hunks)
  • configuration/printers/v-core-4/400.cfg (0 hunks)
  • configuration/printers/v-core-4/500.cfg (0 hunks)
  • configuration/printers/v-core-4/macros.cfg (1 hunks)
  • configuration/printers/v-core-4/v-core-4.cfg (1 hunks)
  • configuration/printers/v-core-pro/macros.cfg (1 hunks)
  • configuration/scripts/ratos-common.sh (1 hunks)
  • configuration/scripts/ratos-install.sh (1 hunks)
  • configuration/z-probe/beacon.cfg (18 hunks)
  • configuration/z-probe/stowable-probe.cfg (0 hunks)
  • src/server/gcode-processor/Actions.ts (1 hunks)
💤 Files with no reviewable changes (10)
  • configuration/printers/v-core-4-idex/500.cfg
  • configuration/printers/v-core-4-hybrid/500.cfg
  • configuration/printers/v-core-4-idex/300.cfg
  • configuration/printers/v-core-4-hybrid/300.cfg
  • configuration/printers/v-core-4-hybrid/400.cfg
  • configuration/printers/v-core-4/300.cfg
  • configuration/printers/v-core-4/500.cfg
  • configuration/printers/v-core-4/400.cfg
  • configuration/printers/v-core-4-idex/400.cfg
  • configuration/z-probe/stowable-probe.cfg
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-28T19:09:05.023Z
Learnt from: miklschmidt
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/printers/v-core-4/v-core-4.cfg:7-9
Timestamp: 2025-07-28T19:09:05.023Z
Learning: In Klipper configuration files, duplicate sections (like `[gcode_macro RatOS]`) do not cause errors. Instead, Klipper uses config section merging where later section parameters (chronologically) take precedence over earlier ones. This means multiple definitions of the same section are allowed and the last one processed will override parameters from earlier definitions.

Applied to files:

  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
  • configuration/macros/idex/util.cfg
  • configuration/z-probe/beacon.cfg
  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
  • configuration/macros/overrides.cfg
  • configuration/macros/util.cfg
  • configuration/klippy/ratos_z_offset.py
📚 Learning: 2025-06-16T16:44:30.280Z
Learnt from: LucidityCrash
Repo: Rat-OS/RatOS-configurator PR: 89
File: src/templates/v-core-pro.ts:18-20
Timestamp: 2025-06-16T16:44:30.280Z
Learning: In the RatOS configurator project, v-core-pro configuration files are stored in `configuration/printers/v-core-pro/` in the source repository, but are accessed via `RatOS/printers/v-core-pro/` paths in the deployed/installed environment. The include statements in templates should use the runtime paths, not the source repository paths.

Applied to files:

  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
📚 Learning: 2025-12-02T18:27:19.189Z
Learnt from: tg73
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/z-probe/beacon.cfg:100-131
Timestamp: 2025-12-02T18:27:19.189Z
Learning: In Klipper configuration macros using Jinja2 templates, the `|default(value)` filter provides a fallback value when a variable is undefined or missing. For example, `printer["gcode_macro RatOS"].some_variable|default(0)` will return `0` if `variable_some_variable` is not declared in the `[gcode_macro RatOS]` section. This is a standard pattern for optional or backward-compatible settings and does not cause errors.

Applied to files:

  • configuration/z-probe/beacon.cfg
🧬 Code graph analysis (6)
src/server/gcode-processor/Actions.ts (2)
src/server/gcode-processor/State.ts (2)
  • gcodeInfo (79-84)
  • gcodeInfo (86-88)
src/server/gcode-processor/errors.ts (1)
  • SlicerNotSupported (36-36)
configuration/klippy/beacon_true_zero_correction.py (2)
configuration/klippy/ratos_z_offset.py (2)
  • set_offset (74-78)
  • get_position (92-97)
configuration/klippy/ratos.py (2)
  • get_beacon_probing_regions (607-628)
  • console_echo (546-572)
configuration/klippy/ratos_z_offset.py (1)
configuration/klippy/fastconfig.py (3)
  • items (76-77)
  • get (67-68)
  • values (73-74)
configuration/klippy/ratos.py (2)
configuration/klippy/fastconfig.py (2)
  • get (67-68)
  • keys (70-71)
configuration/klippy/beacon_mesh.py (1)
  • get_profiles (323-336)
configuration/klippy/beacon_mesh.py (1)
configuration/klippy/ratos.py (6)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • get_beacon_probing_regions (607-628)
  • enable (823-828)
  • disable (830-837)
  • progress (840-841)
  • progress (844-845)
configuration/klippy/beacon_adaptive_heat_soak.py (1)
configuration/klippy/ratos.py (7)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • set_auto_rate (847-853)
  • enable (823-828)
  • progress (840-841)
  • progress (844-845)
  • disable (830-837)
  • load_config (875-876)
🪛 Ruff (0.14.7)
configuration/klippy/fastconfig.py

37-37: Unused method argument: eventtime

(ARG002)


39-39: Avoid specifying long messages outside the exception class

(TRY003)

configuration/klippy/beacon_true_zero_correction.py

87-87: Avoid specifying long messages outside the exception class

(TRY003)


99-99: Unused method argument: rails

(ARG002)


105-105: Unused method argument: print_time

(ARG002)


207-207: Avoid specifying long messages outside the exception class

(TRY003)


207-207: f-string without any placeholders

Remove extraneous f prefix

(F541)


236-238: Avoid specifying long messages outside the exception class

(TRY003)


297-297: Avoid specifying long messages outside the exception class

(TRY003)


310-310: Avoid specifying long messages outside the exception class

(TRY003)


346-346: Create your own exception

(TRY002)


346-346: Avoid specifying long messages outside the exception class

(TRY003)


390-390: Avoid specifying long messages outside the exception class

(TRY003)


398-398: Avoid specifying long messages outside the exception class

(TRY003)


403-403: Avoid specifying long messages outside the exception class

(TRY003)

configuration/klippy/ratos_z_offset.py

83-83: Avoid specifying long messages outside the exception class

(TRY003)


113-113: Unused method argument: eventtime

(ARG002)

configuration/klippy/ratos.py

249-249: Avoid specifying long messages outside the exception class

(TRY003)


269-269: Do not catch blind exception: Exception

(BLE001)


270-270: Use explicit conversion flag

Replace with conversion flag

(RUF010)


276-276: Do not catch blind exception: Exception

(BLE001)


277-277: Use explicit conversion flag

Replace with conversion flag

(RUF010)


285-285: Avoid specifying long messages outside the exception class

(TRY003)


516-516: Consider moving this statement to an else block

(TRY300)


661-661: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


663-663: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


696-696: Unused method argument: eventtime

(ARG002)


713-713: Unused method argument: gcmd

(ARG002)

configuration/klippy/beacon_mesh.py

205-205: Unused method argument: gcmd

(ARG002)


237-237: Avoid specifying long messages outside the exception class

(TRY003)


299-299: Avoid specifying long messages outside the exception class

(TRY003)


321-321: Avoid specifying long messages outside the exception class

(TRY003)


354-354: Avoid specifying long messages outside the exception class

(TRY003)


388-388: Avoid specifying long messages outside the exception class

(TRY003)


420-420: Avoid specifying long messages outside the exception class

(TRY003)


423-423: Avoid specifying long messages outside the exception class

(TRY003)


446-446: Avoid specifying long messages outside the exception class

(TRY003)


453-453: Avoid specifying long messages outside the exception class

(TRY003)


460-460: Avoid specifying long messages outside the exception class

(TRY003)


463-463: Avoid specifying long messages outside the exception class

(TRY003)


499-499: Avoid specifying long messages outside the exception class

(TRY003)


531-531: Avoid specifying long messages outside the exception class

(TRY003)


541-541: Avoid specifying long messages outside the exception class

(TRY003)


546-546: Consider moving this statement to an else block

(TRY300)


548-548: Avoid specifying long messages outside the exception class

(TRY003)


548-548: Use explicit conversion flag

Replace with conversion flag

(RUF010)


562-562: Avoid specifying long messages outside the exception class

(TRY003)


635-635: Avoid specifying long messages outside the exception class

(TRY003)


711-711: Consider moving this statement to an else block

(TRY300)


725-725: Do not catch blind exception: Exception

(BLE001)


749-752: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


749-752: Create your own exception

(TRY002)


749-752: Avoid specifying long messages outside the exception class

(TRY003)


1027-1027: Avoid specifying long messages outside the exception class

(TRY003)


1027-1027: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1041-1043: try-except-continue detected, consider logging the exception

(S112)


1041-1041: Do not catch blind exception: Exception

(BLE001)


1058-1058: Abstract raise to an inner function

(TRY301)


1058-1058: Avoid specifying long messages outside the exception class

(TRY003)


1064-1064: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1101-1101: Avoid specifying long messages outside the exception class

(TRY003)


1103-1103: Avoid specifying long messages outside the exception class

(TRY003)


1162-1162: Do not catch blind exception: Exception

(BLE001)


1192-1192: Avoid specifying long messages outside the exception class

(TRY003)


1206-1206: Do not catch blind exception: Exception

(BLE001)


1261-1261: Avoid specifying long messages outside the exception class

(TRY003)


1301-1301: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1301-1301: Avoid specifying long messages outside the exception class

(TRY003)


1301-1301: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1315-1315: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1330-1330: Avoid specifying long messages outside the exception class

(TRY003)


1360-1360: Do not catch blind exception: Exception

(BLE001)


1388-1391: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1388-1391: Create your own exception

(TRY002)


1388-1391: Avoid specifying long messages outside the exception class

(TRY003)


1394-1397: Create your own exception

(TRY002)


1394-1397: Avoid specifying long messages outside the exception class

(TRY003)


1547-1547: Avoid specifying long messages outside the exception class

(TRY003)


1564-1564: Avoid specifying long messages outside the exception class

(TRY003)


1573-1573: Avoid specifying long messages outside the exception class

(TRY003)


1601-1601: Avoid specifying long messages outside the exception class

(TRY003)


1621-1621: Avoid specifying long messages outside the exception class

(TRY003)


1644-1644: Avoid specifying long messages outside the exception class

(TRY003)


1661-1661: Avoid specifying long messages outside the exception class

(TRY003)


1689-1689: Avoid specifying long messages outside the exception class

(TRY003)


1723-1723: Avoid specifying long messages outside the exception class

(TRY003)


1732-1732: Avoid specifying long messages outside the exception class

(TRY003)


1773-1773: Avoid specifying long messages outside the exception class

(TRY003)


1813-1814: Avoid specifying long messages outside the exception class

(TRY003)


1823-1823: Avoid specifying long messages outside the exception class

(TRY003)


1835-1837: Avoid specifying long messages outside the exception class

(TRY003)


1841-1843: Avoid specifying long messages outside the exception class

(TRY003)


1900-1900: Function definition does not bind loop variable secondary_idx

(B023)

configuration/klippy/beacon_adaptive_heat_soak.py

44-44: Do not catch blind exception: Exception

(BLE001)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


89-89: Avoid specifying long messages outside the exception class

(TRY003)


94-94: Create your own exception

(TRY002)


94-94: Avoid specifying long messages outside the exception class

(TRY003)


179-179: Avoid specifying long messages outside the exception class

(TRY003)


184-184: Avoid specifying long messages outside the exception class

(TRY003)


232-232: Avoid specifying long messages outside the exception class

(TRY003)


366-366: Avoid specifying long messages outside the exception class

(TRY003)


372-372: Avoid specifying long messages outside the exception class

(TRY003)


409-409: Avoid specifying long messages outside the exception class

(TRY003)


415-415: Avoid specifying long messages outside the exception class

(TRY003)


424-424: Avoid specifying long messages outside the exception class

(TRY003)


427-427: Avoid specifying long messages outside the exception class

(TRY003)


498-498: Probable insecure usage of temporary file or directory: "/tmp/heat_soak_"

(S108)


525-525: Avoid specifying long messages outside the exception class

(TRY003)


642-642: Avoid specifying long messages outside the exception class

(TRY003)


645-645: Avoid specifying long messages outside the exception class

(TRY003)


670-670: Avoid specifying long messages outside the exception class

(TRY003)


696-696: Avoid specifying long messages outside the exception class

(TRY003)


699-699: Avoid specifying long messages outside the exception class

(TRY003)


714-714: Avoid specifying long messages outside the exception class

(TRY003)


721-721: Function definition does not bind loop variable samples

(B023)

🔇 Additional comments (79)
configuration/printers/v-core-3-hybrid/macros.cfg (2)

6-6: Clarify the rationale for the HYBRID_INIT delay change.

The initial_duration was increased from 0.1 to 0.2 seconds. Please provide context for this timing adjustment—is it addressing a timing issue, improving probe stability, or another concern?


22-22: Verify fastconfig migration consistency.

Per the PR objectives, the broader refactoring shifts from printer.configfile.settings to printer.fastconfig.settings for beacon-related configuration checks. This line still uses printer.configfile.settings.beacon. Confirm whether this should be updated to use fastconfig as part of the centralized configuration pattern, or if configfile.settings is intentionally retained here.

configuration/printers/v-core-pro/macros.cfg (1)

16-20: Beacon condition correctly migrated to fastconfig; ensure object is always present

Switching the guard to printer.fastconfig.settings.beacon keeps the contact-path behavior intact and aligns this macro with the new fastconfig model. Please just confirm that printer.fastconfig and .settings are guaranteed to exist for this profile at macro-eval time (even when beacon is disabled), so this check never throws due to a missing fastconfig object.

configuration/printers/v-core-3-idex/macros.cfg (2)

14-14: Verify the rationale for doubling the initialization delay.

The initial delay was doubled from 0.1 to 0.2 seconds. Please confirm whether this change addresses a specific timing or race condition issue during IDEX initialization, or if it's a preventive measure.


48-48: Verify fastconfig availability and complete migration.

The migration from printer.configfile.settings.beacon to printer.fastconfig.settings.beacon is part of a broader architectural change. Ensure that:

  1. printer.fastconfig is properly initialized before this macro executes
  2. The migration is complete and consistent across all printer configurations
  3. fastconfig.settings.beacon provides the same structure and values as configfile.settings.beacon
configuration/scripts/ratos-install.sh (1)

4-16: libopenblas-base addition to PKGLIST looks fine

The extended PKGLIST keeps the existing pattern and won’t affect the apt-get call semantics.

configuration/moonraker.conf (1)

113-116: Klipper pinned_commit bump is configuration-only

Changing the pinned_commit SHA for [update_manager klipper] is a straightforward version uplift and doesn’t alter Moonraker config semantics here. Just ensure this commit has been validated with the new beacon/mesh workflows.

configuration/macros/idex/idex_is.cfg (1)

41-51: Probe point source migration to fastconfig is consistent

Both macros now pull probe_points from printer.fastconfig.settings.resonance_tester.probe_points[0], matching the project-wide move off printer.configfile.settings without changing how the coordinates are consumed.

Also applies to: 301-309

configuration/printers/v-core-4-hybrid/macros.cfg (1)

5-10: Hybrid init delay and fastconfig-based beacon check look good

  • Increasing _HYBRID_INIT initial_duration to 0.2s should give a bit more safety margin without side effects.
  • Switching the Z tilt beacon check to printer.fastconfig.settings.beacon while gating on beacon_contact_z_tilt_adjust matches the rest of the fastconfig migration and keeps the legacy fallback path intact.

Also applies to: 22-26

src/server/gcode-processor/Actions.ts (1)

99-104: PrusaSlicer version gate and message are consistent

The updated semver.satisfies expression now exactly matches the error message (2.8.0, 2.8.1, and 2.9.02.9.2), preserving the “only specific releases” policy while adding 2.9.1 and 2.9.2. If you later broaden support, consider moving to a range (e.g. >=2.8.0 <2.10.0) to avoid having to touch this list for each patch.

configuration/macros/parking.cfg (1)

28-35: Guard against potentially undefined beacon_contact_start_print_true_zero

The variable beacon_contact_start_print_true_zero used in the condition appears without a local definition in this file. If this variable is not globally injected into the Jinja context by Klipper or the RatOS configuration, the condition could fail or behave unexpectedly. Verify that this variable is reliably available in the Jinja scope, or consider deriving it from printer["gcode_macro RatOS"] with a safe default as a more defensive approach.

configuration/macros/idex/util.cfg (1)

14-17: LGTM - Consistent migration to fastconfig.

The switch from printer.configfile.settings to printer.fastconfig.settings aligns with the centralized immutable config wrapper pattern introduced in this PR.

Also applies to: 40-41

configuration/homing.cfg (5)

81-81: LGTM - Centralized safe home position retrieval.

The tuple unpacking from printer.ratos.safe_home_position properly retrieves both X and Y coordinates from the centralized accessor in ratos.py.

Also applies to: 124-124


155-156: New beacon configuration variables added.

These variables support the beacon true-zero workflow and fuzzy positioning feature. The default values (false/0) ensure backward compatibility.


173-190: Beacon calibration logic looks correct.

The conditional branching properly distinguishes between:

  • beacon_contact_start_print_true_zero=true: Skip multipoint probing here since critical zero probing happens during start print
  • Otherwise: Perform full calibration including multipoint probing

334-336: Macro renamed to debug-only echo.

The macro _MOVE_TO_SAFE_Z_HOME was renamed to __MOVE_TO_SAFE_Z_HOME_ECHO_DEBUG and now only logs parameters. The actual movement is handled by the Python implementation cmd_MOVE_TO_SAFE_Z_HOME in ratos.py, which calls this macro for debug output via __MOVE_TO_SAFE_Z_HOME_ECHO_DEBUG.


329-330: Verify ratos_homing section exists in fastconfig.

The _Z_HOP macro now reads z_hop and z_hop_speed from printer.fastconfig.config.ratos_homing. Ensure the [ratos_homing] section (defined at lines 20-23 in this file) is properly captured by the fastconfig module.

configuration/macros/idex/toolheads.cfg (2)

496-498: LGTM - Consistent fastconfig migration for beacon checks.

Both beacon configuration checks are properly migrated to use printer.fastconfig.settings.beacon.

Also applies to: 563-565


830-834: LGTM - Debug logging helper.

The new _SET_TOOLHEAD_OFFSET_LOG_DEBUG macro provides useful before/after offset state logging for debugging toolhead offset changes.

configuration/klippy/ratos.py (3)

656-686: LGTM - Fuzzy positioning implementation.

The fuzzy positioning uses proper uniform distribution within a circle (sqrt of random for radius ensures uniform area distribution). The clamping to beacon probing or printable region is correctly implemented with appropriate warnings when clamping occurs.

Note: Using random.random() is acceptable here as this is not for cryptographic purposes - it's for distributing probe contact points to reduce bed wear.


803-870: New BackgroundDisplayStatusProgressHandler class.

This class provides background progress updates with a spinner for display status during long operations. The implementation looks solid:

  • Proper reactor timer registration/unregistration
  • Progress clamping between 0.0 and 1.0
  • Auto-rate feature for gradual progress updates
  • Clean enable/disable lifecycle

630-649: Safe home position validation triggers printer shutdown.

The get_safe_home_position method calls printer.invoke_shutdown() when the configured safe home is outside the beacon-probable region. This could cause unexpected shutdowns if invoked from frequently-called status update methods.

Consider whether a shutdown is the appropriate response here, or if raising an error during command execution would be more appropriate. The current implementation may cause operational issues if triggered repeatedly during normal operation.

configuration/macros.cfg (7)

284-294: Good UX improvement - LED feedback before error.

Adding _LED_START_PRINTING_ERROR before raising errors provides visual feedback to users when mandatory parameters are missing.


326-333: Beacon adaptive heat soak configuration.

The new configuration variables provide fine-grained control over the adaptive heat soak behavior with sensible defaults:

  • min_wait: 0 (no minimum)
  • max_wait: 5400 (90 minutes)
  • layer_quality: 3
  • maximum_first_layer_duration: 1800 (30 minutes)

625-639: Beacon adaptive heat soak integration.

The implementation properly:

  1. Moves to safe Z home position
  2. Lowers Z to 2.5mm for proximity measurements
  3. Waits for heat soak using beacon measurements
  4. Supports optional extra wait time after completion

The fallback to traditional time-based soak when beacon adaptive heat soak is disabled maintains backward compatibility.


733-740: Explicit standby flag reset ensures consistent state.

Resetting both T0 and T1 standby flags to False before conditionally setting the inactive toolhead to standby prevents stale state from previous prints.


1033-1039: Fuzzy positioning and position storage for bed mesh.

The fuzzy radius parameter allows randomizing the true-zero probe position to distribute wear, and the position is stored for later use when setting the mesh zero reference. This is a well-designed integration.


1274-1284: END_PRINT beacon offset cleanup.

The migration from inline offset reset to _BEACON_SUBTRACT_CONTACT_EXPANSION_OFFSET is cleaner and delegates the logic to the appropriate macro.


1055-1059: Position storage macro for bed mesh zero reference.

This macro reads printer.ratos.last_move_to_safe_z_home_position and stores it in _START_PRINT_BED_MESH variables. This enables the bed mesh to use the actual true-zero position (which may differ from the configured safe home when fuzzy positioning is used).

configuration/printers/v-core-3/macros.cfg (1)

20-24: Beacon check correctly migrated to fastconfig

Switching the beacon presence check to printer.fastconfig.settings.beacon keeps behavior while avoiding configfile deep copies. Looks good and consistent with the new fastconfig wrapper.

configuration/printers/v-core-4/macros.cfg (1)

16-20: Consistent fastconfig-based beacon guard

Using printer.fastconfig.settings.beacon here mirrors the v-core-3 macro and removes repeated configfile snapshots. No functional regression apparent.

configuration/printers/v-core-4-idex/macros.cfg (2)

15-19: Slightly increased _IDEX_INIT delay is reasonable

Doubling initial_duration from 0.1s to 0.2s should only improve robustness against startup races and has negligible impact on startup latency.


42-46: Beacon-aware Z-tilt now uses fastconfig

The Z-tilt contact path is now gated on printer.fastconfig.settings.beacon, aligning with the new immutable config snapshot and matching other macros in this PR. Behavior remains the same when beacon is configured.

configuration/macros/idex/vaoc.cfg (3)

117-120: IDEX safe distance now sourced from fastconfig

Using printer.fastconfig.settings.dual_carriage.safe_distance here removes the heavy configfile status copy and stays true to the configured dual_carriage value. Assumes dual_carriage is always present on VAOC-enabled IDEX machines, which matches this file’s target.

If there are edge configurations without [dual_carriage] that still include VAOC, consider a defensive default (e.g., |default(70)) to avoid undefined-key errors.


304-345: Consistent fastconfig migration for _VAOC_LOAD_TOOL safe distance

Same as _START_VAOC, sourcing safe_distance from printer.fastconfig.settings.dual_carriage.safe_distance keeps behavior while avoiding repeated deep copies. No functional issues spotted.


633-659: Beacon gate for temp-offset calibration updated to fastconfig

The VAOC temp-offset calibration is now guarded by printer.fastconfig.settings.beacon, in line with other beacon/true-zero flows. This should behave identically to the old configfile-based check while benefitting from the immutable snapshot.

configuration/scripts/ratos-common.sh (1)

194-198: Unable to verify this review comment. The repository could not be accessed in the sandbox environment to confirm:

  • Whether the extension paths actually exist
  • Whether the expected_extensions array follows the claimed pattern
  • Whether auto-registration logic will properly handle these entries
  • Whether config sections use matching extension names

The original review recommends verification but does not provide verification results. To properly assess this comment, access to the codebase is needed to inspect the registration logic, verify file paths, and check config section alignment.

configuration/macros/priming.cfg (4)

32-45: Consistent migration to fastconfig data source.

The migration from printer.configfile.settings to printer.fastconfig.settings is applied consistently across all beacon/bltouch/probe checks in this macro. The logic flow remains unchanged.


105-125: LGTM - Probe offset retrieval updated consistently.

The probe offset retrieval logic correctly migrates all three probe types (bltouch, probe, beacon) to use printer.fastconfig.settings. The error message at line 124 appropriately guides users when no probe is configured.


207-217: LGTM - Beacon detection updated for probe method selection.

The beacon presence check for selecting contact vs. standard probing is correctly migrated to fastconfig.


354-356: LGTM - PRIME_BLOB probe checks migrated consistently.

All probe availability checks within PRIME_BLOB are consistently updated to use fastconfig.

Also applies to: 379-381, 410-412

configuration/macros/util.cfg (3)

48-61: Good documentation for startup ordering requirements.

The added comment clearly explains the ordering dependency and the 0.2-second minimum delay requirement for subsequent init macros. The beacon check migration to fastconfig is correct.


255-262: LGTM - Hybrid inverted check migrated correctly.

The migration to printer.fastconfig.settings.ratos_hybrid_corexy maintains the same logic for detecting the inverted configuration.


383-391: LGTM - Skew profile lookup migrated to fastconfig.config.

The change to printer.fastconfig.config for looking up skew correction profiles is consistent with the config accessor pattern.

configuration/klippy/ratos_z_offset.py (4)

10-29: Well-structured Z-offset manager with Klipper transform compliance.

The class correctly implements the gcode_move transform interface with proper position list copying ([:]) to avoid mutating the original. The event handler registration and gcode command setup follow Klipper conventions.


80-88: Good refactor addressing previous review feedback.

The _validate_and_set_offset helper method consolidates the duplicated validation logic as suggested in past reviews. The implementation correctly handles zero-value cleanup by removing entries rather than storing zeros.


92-104: Transform implementation correctly applies offset bidirectionally.

The get_position removes the offset (for reporting the logical position) while move adds it (to apply physical correction). Both methods properly copy the position list to avoid side effects.


113-116: Unused eventtime parameter is intentional.

The eventtime parameter in get_status follows Klipper's standard signature for status methods and should be retained for API compatibility even if unused.

configuration/macros/overrides.cfg (5)

95-108: Beacon thermal offset updates properly gated by print state.

The is_printing_gcode check ensures nozzle thermal expansion offsets are only updated during active printing, preventing unintended offset changes during preheat or manual temperature commands.


149-154: LGTM - M109 beacon offset handling consistent with M104.

The same pattern is correctly applied to M109, updating thermal offsets after the wait completes.


185-191: LGTM - SET_HEATER_TEMPERATURE beacon integration.

Correctly applies beacon offset updates only when targeting an extruder heater (t != -1) and during active printing.


223-247: Improved logging with descriptive sensor/toolhead identification.

The new id variable provides clearer log messages distinguishing between generic sensors and toolhead extruders. The fallback case at lines 238-244 correctly propagates to the base command to maintain consistent error behavior.


319-354: Comprehensive BED_MESH_CALIBRATE wrapper with proper sequencing.

The macro correctly:

  1. Applies Z_TILT_ADJUST/QUAD_GANTRY_LEVEL if not already applied
  2. Rehomes Z after leveling adjustments
  3. Checks active beacon model temperature for proximity probing
  4. Handles stowable probe deploy/stow
  5. Applies RatOS bed mesh parameters post-calibration

The abl_and_home_z_if_required variable allows bypassing the leveling checks when needed.

configuration/klippy/beacon_true_zero_correction.py (6)

18-75: Well-structured configuration with sensible defaults and bounds.

The configuration options are well-documented with clear explanations of the sampling strategies. The safety defaults (z_rejection_threshold=0.075, max_retries=10) are derived from empirical testing data.


77-108: Correct event handling for offset lifecycle.

The offset is properly cleared on both Z-axis homing (homing:home_rails_end) and motor disable (stepper_enable:motor_off), ensuring stale corrections don't persist across homing cycles.


292-310: Good validation with clear error messaging.

The probing region validation correctly guards against None (addressing past review feedback) and provides clear error messages when the probing region exceeds the configured contact area.


344-382: Robust probing session with retry mechanism.

The session correctly:

  1. Generates points with minimum spacing based on nozzle tip diameter
  2. Validates the probing region before starting
  3. Reserves extra points for retries upfront
  4. Uses probe.ProbePointsHelper for standardized probing

384-403: Comprehensive finalization with safety checks.

The -0.2mm safety limit is a good protection against bed damage from erroneous corrections. Error messages are clear and actionable.


405-431: Statistical approach is well-implemented.

The "take N, keep 3 lowest" strategy effectively filters out early-trigger outliers (values above z_rejection_threshold) while using the mean of the lowest samples for robustness. The retry mechanism for rejected samples is elegantly handled by pre-generating extra points.

configuration/macros/mesh.cfg (4)

15-30: LGTM on the zero reference position sanity checks.

The logic correctly validates compatibility between zero_reference_position and fuzzy true-zero mode, with appropriate error messaging. The position matching check on line 25 uses rounded values which is appropriate for coordinate comparison.


48-55: LGTM on the new preflight check macro.

Clean implementation that resets internal state variables and delegates beacon scan compensation check when beacon is configured.


178-190: LGTM on zero reference position mesh expansion logic.

The logic correctly expands the mesh region to include the zero reference position when it falls outside the initial mesh bounds. This ensures SET_ZERO_REFERENCE_POSITION can meaningfully set the reference.


74-78: The is none check on line 77 will never be triggered—variables are pre-converted to float on lines 47-48.

Lines 47-48 convert params.ACTUAL_TRUE_ZERO_POSITION_X and params.ACTUAL_TRUE_ZERO_POSITION_Y to float with a default of 0, meaning actual_true_zero_position_x and actual_true_zero_position_y can never be None. The conditional on line 77 checking if actual_true_zero_position_x is none will always evaluate to False, making the fallback logic dead code. If the intent is to support optional parameters where no coordinate is provided, the initial conversion on lines 47-48 should use None as the default instead of float(0), and then the is none check would work correctly.

Likely an incorrect or invalid review comment.

configuration/klippy/beacon_adaptive_heat_soak.py (5)

37-61: LGTM on multiprocessing pattern for threshold prediction.

The implementation correctly uses a child process with daemon mode, reactor-friendly polling, proper pipe cleanup, and error propagation via the pipe. This avoids blocking the Klipper reactor during expensive GAM prediction.


88-96: Exception chaining is correct.

Line 94 properly uses from e for exception chaining, maintaining the traceback. This was addressed per past review comments.


224-260: LGTM on RunningAverage implementation.

Clean circular buffer implementation with efficient O(1) add and get_average operations. The edge case of size <= 0 is properly guarded.


496-507: Verify /tmp usage is acceptable in this context.

Static analysis flags /tmp/heat_soak_{ts}.csv as potentially insecure (S108). In this context, the file is used for diagnostic logging of heat soak data, which is low-sensitivity operational data. The risk is minimal, but consider:

  1. The file is world-readable by default
  2. On multi-user systems, another user could potentially read or manipulate it

For a 3D printer environment (typically single-user Raspberry Pi), this is likely acceptable, but verify this aligns with the project's security posture.


619-632: Confirmed: uses is True identity check correctly.

Per past review comments, using is True rather than truthiness check is intentional here since these variables can be 'N/A' (string), True, or False. Line 631 now correctly logs level_2_moving_average_trend_checks_passed (the boolean result). This was fixed per commit 62b6f6f.

configuration/z-probe/beacon.cfg (5)

19-26: LGTM on mesh configuration documentation.

Clear comments explaining why mesh_runs: 1 and mesh_cluster_size: 0 are recommended, helping users understand the rationale behind these defaults.


100-131: LGTM on adaptive heat soak configuration variables.

The variables are well-documented with inline comments explaining their purpose and constraints. Per retrieved learnings, the |default() pattern used when reading these variables elsewhere is correct Jinja2 behavior.


683-738: LGTM on IDEX-aware nozzle expansion offset logic.

The logic correctly handles:

  1. Single mode: applies offset only for the active toolhead
  2. Copy/Mirror mode: applies offset only for the default toolhead
  3. Proper calculation of expansion coefficient based on temperature delta
  4. Debug logging for troubleshooting

The conditional at line 698 (toolhead == 1) == (idex_mode == "primary") correctly determines if toolhead 1 is active when carriage_1 is in primary mode.


1074-1093: LGTM on preflight beacon model check.

The logic correctly identifies when a Beacon model is required but not present:

  1. For true zero calibration when beacon_contact_calibrate_model_on_print is false
  2. For homing when using proximity method without contact fallback

This provides early, clear error messaging rather than cryptic failures later in the print sequence.


1174-1206: LGTM on runtime offset management.

The _BEACON_SET_RUNTIME_OFFSET macro correctly:

  1. Subtracts the applied expansion offset from current gcode offset
  2. Handles IDEX tool z offset by adding it back (since _SET_TOOLHEAD_OFFSET applies negative offset)
  3. Documents the limitation that gcode file offsets cannot be distinguished from babystepping

This enables persistent babystep/z-offset adjustments across prints.

configuration/klippy/beacon_mesh.py (6)

744-754: LGTM on _gaussian_filter implementation.

The indentation issue flagged in past reviews has been fixed. The return statement is now correctly at the module level outside the if block. The lazy loading of scipy.ndimage is appropriate.


1895-1918: Loop variable secondary_idx captured in nested function.

Static analysis hint B023 flags that primary_idx_from_line_idx captures secondary_idx from the enclosing loop. While the function is only called within the same iteration where it's defined, this pattern can be confusing.

However, since primary_idx_from_line_idx is defined fresh each iteration and only used within that iteration, this is safe. No change required.


633-672: LGTM on apply_scan_compensation bed temp ordering.

Per past review comment, the measured_mesh_bed_temp is now correctly read after _validate_extended_parameters succeeds (line 657), preventing KeyError with legacy meshes. This was fixed per commit 7be6853.


1472-1525: LGTM on CotemporalProbingHelper initialization.

Clean initialization with proper handler registration, faulty region parsing from config, and clear documentation of why beacon.get_offsets() is not used (due to its limited-circumstance design).


1792-1860: LGTM on offset-aligned probe sequence generation.

The algorithm correctly:

  1. Validates beacon offsets and spacing constraints
  2. Determines primary/secondary axes based on offset magnitudes
  3. Calculates appropriate resolution as a divisor of the primary offset
  4. Handles both beacon-leading and beacon-trailing scenarios per scan direction

This enables cotemporal contact/proximity probing with minimal toolhead movement.


717-742: LGTM on multiprocessing pattern for local-low filter.

Consistent with the pattern in beacon_adaptive_heat_soak.py: daemon child process, reactor-friendly polling, proper pipe cleanup, error propagation. This prevents heavy numpy operations from blocking the Klipper reactor.

@tg73
Copy link
Collaborator Author

tg73 commented Dec 3, 2025

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 3, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
configuration/klippy/beacon_adaptive_heat_soak.py (1)

494-505: Avoid hard‑coded /home/pi paths in diagnostics (reuse config dir)

The adaptive heat‑soak diagnostics still write to fixed paths under /home/pi/printer_data/config/:

  • Z‑rate capture: fn = f"/tmp/heat_soak_{ts}.csv" (fine as a temp file) but _CAPTURE_Z_RATES writes summary CSVs to /home/pi/printer_data/config/{filename}.
  • Beacon sample capture: filename = f'/home/pi/printer_data/config/beacon_adaptive_heat_soak_beacon_samples_{timestamp}.txt'.

This hard‑codes the user and layout (Pi + Moonraker defaults) and will break on other hosts or custom setups. It also reintroduces the issue previously discussed in an earlier review.

Consider deriving these paths from Klipper’s config directory instead:

-        fullpath = f'/home/pi/printer_data/config/{filename}'
+        config_dir = self.printer.get_config_dir()
+        fullpath = os.path.join(config_dir, filename)

and similarly for the beacon‑samples filename.

This keeps diagnostics portable without changing user‑visible behavior.

Also applies to: 646-652, 703-705

🧹 Nitpick comments (3)
configuration/moonraker.conf (1)

113-115: Klipper dev pinned_commit bump looks consistent, but verify compatibility with new features and printer profiles

Line 115 updates the Klipper dev pinned_commit to 93c8ad8a017c45f4502e73ad1dc174cf7d3c3b90, which matches the existing pattern of tracking specific dev snapshots and is reasonable given the new Beacon/fastconfig-related functionality in this PR. Please double‑check that:

  • This commit contains all required Beacon/bed-mesh/RatOS APIs used elsewhere in the PR.
  • You’ve smoke‑tested across the main supported printer configs, since a Klipper dev bump can have side effects on kinematics, config parsing, or modules beyond Beacon.

Optionally, consider noting in the PR description (or a brief comment near this section) why this particular commit was chosen (e.g., “first commit with fastconfig support for X/Y”), to simplify future upgrades and debugging.

configuration/klippy/beacon_mesh.py (1)

1895-1918: Consider refactoring inner function to avoid closure ambiguity.

The inner function primary_idx_from_line_idx defined inside the loop references the loop variable secondary_idx. While this works correctly in this case (since the function is only called within the same iteration), it's a code pattern that static analysis tools flag and could be clearer.

Consider refactoring to make the dependency explicit, for example by passing secondary_idx as a parameter:

 for secondary_idx in range(secondary_count):
     # Determine if the beacon is leading or trailing the nozzle
     beacon_leading = ( primary_offset > 0 ) == ( secondary_idx % 2 == 0 )

-    def primary_idx_from_line_idx(primary_line_idx):
-        if secondary_idx % 2 == 0:
+    def primary_idx_from_line_idx(primary_line_idx, sec_idx):
+        if sec_idx % 2 == 0:
             return primary_line_idx
         else:
             return primary_count - primary_line_idx - 1

     # Add any initial probe actions for the first (offset_divisor - 1) points
     for primary_line_idx in range(offset_divisor - 1):
-        append_probe_action(not beacon_leading, primary_idx_from_line_idx(primary_line_idx), secondary_idx)
+        append_probe_action(not beacon_leading, primary_idx_from_line_idx(primary_line_idx, secondary_idx), secondary_idx)
configuration/klippy/beacon_true_zero_correction.py (1)

141-207: Tighten diagnostics path: avoid hard‑coded /home/pi and unnecessary f‑string

The diagnostics capture in cmd_BEACON_TRUE_ZERO_CORRECTION_DIAGNOSTICS works, but two small issues are worth addressing:

  • The CSV path is hard‑coded to /home/pi/printer_data/config/..., which will break on non‑Pi or differently laid‑out installs. Prefer deriving from Klipper’s config dir, e.g.:
-            filename = f'/home/pi/printer_data/config/mpp_capture_{timestamp}.csv'
+            config_dir = self.printer.get_config_dir()
+            filename = os.path.join(config_dir, f'mpp_capture_{timestamp}.csv')
  • The else branch raises self.gcode.error(f"Unknown action."), which is an f‑string with no interpolation. Dropping the f prefix avoids the Ruff F541 warning:
-        else:
-            raise self.gcode.error(f"Unknown action.")
+        else:
+            raise self.gcode.error("Unknown action.")

Both changes are low‑risk and improve portability and style.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bdffe02 and 84276ee.

⛔ Files ignored due to path filters (1)
  • configuration/klippy/beacon_adaptive_heat_soak_model_training.csv is excluded by !**/*.csv
📒 Files selected for processing (43)
  • configuration/homing.cfg (8 hunks)
  • configuration/klippy/beacon_adaptive_heat_soak.py (1 hunks)
  • configuration/klippy/beacon_mesh.py (3 hunks)
  • configuration/klippy/beacon_true_zero_correction.py (1 hunks)
  • configuration/klippy/fastconfig.py (1 hunks)
  • configuration/klippy/ratos.py (10 hunks)
  • configuration/klippy/ratos_z_offset.py (1 hunks)
  • configuration/macros.cfg (20 hunks)
  • configuration/macros/idex/idex_is.cfg (2 hunks)
  • configuration/macros/idex/toolheads.cfg (6 hunks)
  • configuration/macros/idex/util.cfg (2 hunks)
  • configuration/macros/idex/vaoc.cfg (5 hunks)
  • configuration/macros/mesh.cfg (9 hunks)
  • configuration/macros/overrides.cfg (8 hunks)
  • configuration/macros/parking.cfg (1 hunks)
  • configuration/macros/priming.cfg (7 hunks)
  • configuration/macros/util.cfg (3 hunks)
  • configuration/moonraker.conf (1 hunks)
  • configuration/printers/base.cfg (1 hunks)
  • configuration/printers/v-core-3-hybrid/macros.cfg (1 hunks)
  • configuration/printers/v-core-3-idex/macros.cfg (2 hunks)
  • configuration/printers/v-core-3/macros.cfg (1 hunks)
  • configuration/printers/v-core-4-hybrid/300.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/400.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/500.cfg (0 hunks)
  • configuration/printers/v-core-4-hybrid/macros.cfg (2 hunks)
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg (1 hunks)
  • configuration/printers/v-core-4-idex/300.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/400.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/500.cfg (0 hunks)
  • configuration/printers/v-core-4-idex/macros.cfg (2 hunks)
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1 hunks)
  • configuration/printers/v-core-4/300.cfg (0 hunks)
  • configuration/printers/v-core-4/400.cfg (0 hunks)
  • configuration/printers/v-core-4/500.cfg (0 hunks)
  • configuration/printers/v-core-4/macros.cfg (1 hunks)
  • configuration/printers/v-core-4/v-core-4.cfg (1 hunks)
  • configuration/printers/v-core-pro/macros.cfg (1 hunks)
  • configuration/scripts/ratos-common.sh (1 hunks)
  • configuration/scripts/ratos-install.sh (1 hunks)
  • configuration/z-probe/beacon.cfg (18 hunks)
  • configuration/z-probe/stowable-probe.cfg (0 hunks)
  • src/server/gcode-processor/Actions.ts (1 hunks)
💤 Files with no reviewable changes (10)
  • configuration/printers/v-core-4-idex/400.cfg
  • configuration/printers/v-core-4-hybrid/400.cfg
  • configuration/printers/v-core-4-idex/300.cfg
  • configuration/printers/v-core-4-idex/500.cfg
  • configuration/printers/v-core-4/400.cfg
  • configuration/printers/v-core-4-hybrid/300.cfg
  • configuration/printers/v-core-4/300.cfg
  • configuration/printers/v-core-4/500.cfg
  • configuration/printers/v-core-4-hybrid/500.cfg
  • configuration/z-probe/stowable-probe.cfg
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: tg73
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/z-probe/beacon.cfg:259-259
Timestamp: 2025-12-03T11:42:25.554Z
Learning: In beacon_true_zero_correction.py, the BEACON_AUTO_CALIBRATE command is wrapped to add multi-point probing functionality for improved true zero consistency. The wrapper adds a custom parameter SKIP_MULTIPOINT_PROBING (accepts 1, true, or yes) that allows bypassing the multi-point probing and using just the standard Beacon auto-calibration. This is a valid RatOS-specific parameter, not part of upstream Beacon.
Learnt from: miklschmidt
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/printers/v-core-4/v-core-4.cfg:7-9
Timestamp: 2025-07-28T19:09:05.023Z
Learning: In Klipper configuration files, duplicate sections (like `[gcode_macro RatOS]`) do not cause errors. Instead, Klipper uses config section merging where later section parameters (chronologically) take precedence over earlier ones. This means multiple definitions of the same section are allowed and the last one processed will override parameters from earlier definitions.
📚 Learning: 2025-12-03T11:42:25.554Z
Learnt from: tg73
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/z-probe/beacon.cfg:259-259
Timestamp: 2025-12-03T11:42:25.554Z
Learning: In beacon_true_zero_correction.py, the BEACON_AUTO_CALIBRATE command is wrapped to add multi-point probing functionality for improved true zero consistency. The wrapper adds a custom parameter SKIP_MULTIPOINT_PROBING (accepts 1, true, or yes) that allows bypassing the multi-point probing and using just the standard Beacon auto-calibration. This is a valid RatOS-specific parameter, not part of upstream Beacon.

Applied to files:

  • configuration/printers/v-core-4/macros.cfg
  • configuration/printers/v-core-4-idex/macros.cfg
  • configuration/printers/v-core-4-hybrid/macros.cfg
  • configuration/macros/priming.cfg
  • configuration/printers/v-core-3/macros.cfg
  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
  • configuration/printers/v-core-pro/macros.cfg
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
  • configuration/printers/v-core-3-idex/macros.cfg
  • configuration/macros/mesh.cfg
  • configuration/homing.cfg
  • configuration/macros/overrides.cfg
  • configuration/klippy/beacon_true_zero_correction.py
  • configuration/macros/idex/vaoc.cfg
  • configuration/klippy/beacon_adaptive_heat_soak.py
  • configuration/macros.cfg
  • configuration/klippy/ratos.py
  • configuration/klippy/beacon_mesh.py
  • configuration/z-probe/beacon.cfg
📚 Learning: 2025-06-16T16:44:30.280Z
Learnt from: LucidityCrash
Repo: Rat-OS/RatOS-configurator PR: 89
File: src/templates/v-core-pro.ts:18-20
Timestamp: 2025-06-16T16:44:30.280Z
Learning: In the RatOS configurator project, v-core-pro configuration files are stored in `configuration/printers/v-core-pro/` in the source repository, but are accessed via `RatOS/printers/v-core-pro/` paths in the deployed/installed environment. The include statements in templates should use the runtime paths, not the source repository paths.

Applied to files:

  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
📚 Learning: 2025-07-28T19:09:05.023Z
Learnt from: miklschmidt
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/printers/v-core-4/v-core-4.cfg:7-9
Timestamp: 2025-07-28T19:09:05.023Z
Learning: In Klipper configuration files, duplicate sections (like `[gcode_macro RatOS]`) do not cause errors. Instead, Klipper uses config section merging where later section parameters (chronologically) take precedence over earlier ones. This means multiple definitions of the same section are allowed and the last one processed will override parameters from earlier definitions.

Applied to files:

  • configuration/printers/v-core-4/v-core-4.cfg
  • configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg
  • configuration/printers/v-core-4-idex/v-core-4-idex.cfg
  • configuration/macros/util.cfg
  • configuration/klippy/ratos_z_offset.py
  • configuration/macros/idex/util.cfg
  • configuration/macros/overrides.cfg
  • configuration/z-probe/beacon.cfg
📚 Learning: 2025-12-03T11:42:25.554Z
Learnt from: tg73
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/z-probe/beacon.cfg:259-259
Timestamp: 2025-12-03T11:42:25.554Z
Learning: In the RatOS codebase, standard Klipper and Beacon G-code commands are often wrapped by custom Python code to add extended functionality. The wrapping pattern involves: (1) calling `self.gcode.register_command(COMMAND_NAME, None)` to retrieve the original command handler and store it (e.g., `self.orig_cmd`), then (2) calling `self.gcode.register_command(COMMAND_NAME, self.custom_handler)` to install the wrapper. The wrapper can add custom parameters and logic, then delegate to the original command when needed.

Applied to files:

  • configuration/klippy/ratos.py
  • configuration/z-probe/beacon.cfg
📚 Learning: 2025-12-02T18:27:19.189Z
Learnt from: tg73
Repo: Rat-OS/RatOS-configurator PR: 101
File: configuration/z-probe/beacon.cfg:100-131
Timestamp: 2025-12-02T18:27:19.189Z
Learning: In Klipper configuration macros using Jinja2 templates, the `|default(value)` filter provides a fallback value when a variable is undefined or missing. For example, `printer["gcode_macro RatOS"].some_variable|default(0)` will return `0` if `variable_some_variable` is not declared in the `[gcode_macro RatOS]` section. This is a standard pattern for optional or backward-compatible settings and does not cause errors.

Applied to files:

  • configuration/z-probe/beacon.cfg
🧬 Code graph analysis (6)
src/server/gcode-processor/Actions.ts (2)
src/server/gcode-processor/State.ts (2)
  • gcodeInfo (79-84)
  • gcodeInfo (86-88)
src/server/gcode-processor/errors.ts (1)
  • SlicerNotSupported (36-36)
configuration/klippy/ratos_z_offset.py (1)
configuration/klippy/fastconfig.py (3)
  • items (76-77)
  • get (67-68)
  • values (73-74)
configuration/klippy/beacon_true_zero_correction.py (2)
configuration/klippy/ratos_z_offset.py (1)
  • set_offset (74-78)
configuration/klippy/ratos.py (2)
  • get_beacon_probing_regions (607-628)
  • console_echo (546-572)
configuration/klippy/beacon_adaptive_heat_soak.py (1)
configuration/klippy/ratos.py (6)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • set_auto_rate (847-853)
  • enable (823-828)
  • progress (840-841)
  • progress (844-845)
  • disable (830-837)
configuration/klippy/ratos.py (1)
configuration/klippy/beacon_mesh.py (1)
  • get_profiles (323-336)
configuration/klippy/beacon_mesh.py (1)
configuration/klippy/ratos.py (6)
  • BackgroundDisplayStatusProgressHandler (803-870)
  • get_beacon_probing_regions (607-628)
  • enable (823-828)
  • disable (830-837)
  • progress (840-841)
  • progress (844-845)
🪛 Ruff (0.14.7)
configuration/klippy/ratos_z_offset.py

83-83: Avoid specifying long messages outside the exception class

(TRY003)


113-113: Unused method argument: eventtime

(ARG002)

configuration/klippy/fastconfig.py

37-37: Unused method argument: eventtime

(ARG002)


39-39: Avoid specifying long messages outside the exception class

(TRY003)

configuration/klippy/beacon_true_zero_correction.py

87-87: Avoid specifying long messages outside the exception class

(TRY003)


99-99: Unused method argument: rails

(ARG002)


105-105: Unused method argument: print_time

(ARG002)


207-207: Avoid specifying long messages outside the exception class

(TRY003)


207-207: f-string without any placeholders

Remove extraneous f prefix

(F541)


236-238: Avoid specifying long messages outside the exception class

(TRY003)


297-297: Avoid specifying long messages outside the exception class

(TRY003)


310-310: Avoid specifying long messages outside the exception class

(TRY003)


346-346: Create your own exception

(TRY002)


346-346: Avoid specifying long messages outside the exception class

(TRY003)


390-390: Avoid specifying long messages outside the exception class

(TRY003)


398-398: Avoid specifying long messages outside the exception class

(TRY003)


403-403: Avoid specifying long messages outside the exception class

(TRY003)

configuration/klippy/beacon_adaptive_heat_soak.py

44-44: Do not catch blind exception: Exception

(BLE001)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


89-89: Avoid specifying long messages outside the exception class

(TRY003)


94-94: Create your own exception

(TRY002)


94-94: Avoid specifying long messages outside the exception class

(TRY003)


179-179: Avoid specifying long messages outside the exception class

(TRY003)


184-184: Avoid specifying long messages outside the exception class

(TRY003)


232-232: Avoid specifying long messages outside the exception class

(TRY003)


363-363: Avoid specifying long messages outside the exception class

(TRY003)


369-369: Avoid specifying long messages outside the exception class

(TRY003)


406-406: Avoid specifying long messages outside the exception class

(TRY003)


412-412: Avoid specifying long messages outside the exception class

(TRY003)


421-421: Avoid specifying long messages outside the exception class

(TRY003)


424-424: Avoid specifying long messages outside the exception class

(TRY003)


495-495: Probable insecure usage of temporary file or directory: "/tmp/heat_soak_"

(S108)


522-522: Avoid specifying long messages outside the exception class

(TRY003)


639-639: Avoid specifying long messages outside the exception class

(TRY003)


642-642: Avoid specifying long messages outside the exception class

(TRY003)


667-667: Avoid specifying long messages outside the exception class

(TRY003)


693-693: Avoid specifying long messages outside the exception class

(TRY003)


696-696: Avoid specifying long messages outside the exception class

(TRY003)


711-711: Avoid specifying long messages outside the exception class

(TRY003)


718-718: Function definition does not bind loop variable samples

(B023)

configuration/klippy/ratos.py

249-249: Avoid specifying long messages outside the exception class

(TRY003)


269-269: Do not catch blind exception: Exception

(BLE001)


270-270: Use explicit conversion flag

Replace with conversion flag

(RUF010)


276-276: Do not catch blind exception: Exception

(BLE001)


277-277: Use explicit conversion flag

Replace with conversion flag

(RUF010)


285-285: Avoid specifying long messages outside the exception class

(TRY003)


516-516: Consider moving this statement to an else block

(TRY300)


661-661: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


663-663: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


696-696: Unused method argument: eventtime

(ARG002)


713-713: Unused method argument: gcmd

(ARG002)

configuration/klippy/beacon_mesh.py

205-205: Unused method argument: gcmd

(ARG002)


237-237: Avoid specifying long messages outside the exception class

(TRY003)


299-299: Avoid specifying long messages outside the exception class

(TRY003)


321-321: Avoid specifying long messages outside the exception class

(TRY003)


354-354: Avoid specifying long messages outside the exception class

(TRY003)


388-388: Avoid specifying long messages outside the exception class

(TRY003)


420-420: Avoid specifying long messages outside the exception class

(TRY003)


423-423: Avoid specifying long messages outside the exception class

(TRY003)


446-446: Avoid specifying long messages outside the exception class

(TRY003)


453-453: Avoid specifying long messages outside the exception class

(TRY003)


460-460: Avoid specifying long messages outside the exception class

(TRY003)


463-463: Avoid specifying long messages outside the exception class

(TRY003)


499-499: Avoid specifying long messages outside the exception class

(TRY003)


531-531: Avoid specifying long messages outside the exception class

(TRY003)


541-541: Avoid specifying long messages outside the exception class

(TRY003)


546-546: Consider moving this statement to an else block

(TRY300)


548-548: Avoid specifying long messages outside the exception class

(TRY003)


548-548: Use explicit conversion flag

Replace with conversion flag

(RUF010)


562-562: Avoid specifying long messages outside the exception class

(TRY003)


635-635: Avoid specifying long messages outside the exception class

(TRY003)


711-711: Consider moving this statement to an else block

(TRY300)


725-725: Do not catch blind exception: Exception

(BLE001)


749-752: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


749-752: Create your own exception

(TRY002)


749-752: Avoid specifying long messages outside the exception class

(TRY003)


1027-1027: Avoid specifying long messages outside the exception class

(TRY003)


1027-1027: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1041-1043: try-except-continue detected, consider logging the exception

(S112)


1041-1041: Do not catch blind exception: Exception

(BLE001)


1058-1058: Abstract raise to an inner function

(TRY301)


1058-1058: Avoid specifying long messages outside the exception class

(TRY003)


1064-1064: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1101-1101: Avoid specifying long messages outside the exception class

(TRY003)


1103-1103: Avoid specifying long messages outside the exception class

(TRY003)


1162-1162: Do not catch blind exception: Exception

(BLE001)


1192-1192: Avoid specifying long messages outside the exception class

(TRY003)


1206-1206: Do not catch blind exception: Exception

(BLE001)


1261-1261: Avoid specifying long messages outside the exception class

(TRY003)


1301-1301: Avoid specifying long messages outside the exception class

(TRY003)


1301-1301: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1330-1330: Avoid specifying long messages outside the exception class

(TRY003)


1360-1360: Do not catch blind exception: Exception

(BLE001)


1388-1391: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


1388-1391: Create your own exception

(TRY002)


1388-1391: Avoid specifying long messages outside the exception class

(TRY003)


1394-1397: Create your own exception

(TRY002)


1394-1397: Avoid specifying long messages outside the exception class

(TRY003)


1547-1547: Avoid specifying long messages outside the exception class

(TRY003)


1564-1564: Avoid specifying long messages outside the exception class

(TRY003)


1573-1573: Avoid specifying long messages outside the exception class

(TRY003)


1601-1601: Avoid specifying long messages outside the exception class

(TRY003)


1621-1621: Avoid specifying long messages outside the exception class

(TRY003)


1644-1644: Avoid specifying long messages outside the exception class

(TRY003)


1661-1661: Avoid specifying long messages outside the exception class

(TRY003)


1689-1689: Avoid specifying long messages outside the exception class

(TRY003)


1723-1723: Avoid specifying long messages outside the exception class

(TRY003)


1732-1732: Avoid specifying long messages outside the exception class

(TRY003)


1773-1773: Avoid specifying long messages outside the exception class

(TRY003)


1813-1814: Avoid specifying long messages outside the exception class

(TRY003)


1823-1823: Avoid specifying long messages outside the exception class

(TRY003)


1835-1837: Avoid specifying long messages outside the exception class

(TRY003)


1841-1843: Avoid specifying long messages outside the exception class

(TRY003)


1900-1900: Function definition does not bind loop variable secondary_idx

(B023)

🔇 Additional comments (73)
configuration/printers/v-core-3/macros.cfg (1)

20-20: Verify fastconfig accessibility and equivalent behavior before merge.

The change from printer.configfile.settings.beacon to printer.fastconfig.settings.beacon requires confirmation that:

  1. fastconfig is initialized and available when this macro executes
  2. fastconfig.settings.beacon provides the same interface and data as configfile.settings.beacon
  3. This migration pattern is consistently applied across related configuration files
configuration/printers/v-core-4-hybrid/v-core-4-hybrid.cfg (2)

10-12: LGTM! Spelling corrected as requested.

The printer-specific [bed_mesh] override with split_delta_z: 0.001 is correctly configured, and the comment spelling has been fixed from "arfetacts" to "artifacts" as previously requested.


7-9: The printer-specific override of [gcode_macro RatOS] with variable_beacon_adaptive_heat_soak: True follows the correct RatOS pattern. Klipper's config section merging ensures this parameter will override any base definition. This change aligns with the Beacon/first layer improvements objective and follows the documented RatOS override pattern.

configuration/printers/v-core-pro/macros.cfg (1)

16-20: Fastconfig-based Beacon check looks correct; confirm fastconfig is always present

Switching the Beacon presence check to printer.fastconfig.settings.beacon aligns this macro with the new fastconfig wrapper while preserving the original conditional behavior around beacon_contact_z_tilt_adjust. No logic changes or regressions are apparent here.

Please just confirm that printer.fastconfig is guaranteed to exist for all v-core-pro configurations using this macro (so this file can’t be loaded in an environment without fastconfig); if there’s any chance of mixed environments, you may want a defensive fallback or a clear migration path.

configuration/printers/v-core-3-idex/macros.cfg (2)

13-16: Startup delay bump for _IDEX_INIT looks safe

Increasing initial_duration to 0.2s should only make the IDEX init more robust against startup timing/race issues and doesn’t change logic. No issues from this change.


30-52: Beacon condition via printer.fastconfig.settings.beacon looks correct; confirm config invariant

Gating the contact-based Z_TILT (PROBE_METHOD=contact) behind:

{% if printer.fastconfig.settings.beacon is defined and beacon_contact_z_tilt_adjust %}

is a sensible way to:

  • Avoid running beacon-specific logic when no beacon is present.
  • Keep the behavior opt‑in via beacon_contact_z_tilt_adjust.

One thing to double‑check: if fastconfig.settings.beacon can exist but be explicitly set false on some setups, you might want to additionally check its truthiness:

{% if printer.fastconfig.settings.beacon is defined
      and printer.fastconfig.settings.beacon
      and beacon_contact_z_tilt_adjust %}

If, by convention, the key is only defined when a beacon is installed, the current condition is fine.

src/server/gcode-processor/Actions.ts (1)

99-102: PrusaSlicer version extension looks consistent and safe

The expanded semver constraint cleanly adds 2.9.1 and 2.9.2, and the error message correctly reflects the supported set; no behavioural issues spotted here.

configuration/printers/v-core-4-hybrid/macros.cfg (2)

6-6: LGTM: Startup timing adjustment.

The increase in initial_duration from 0.1 to 0.2 seconds aligns with similar changes across other printer configurations, likely ensuring proper initialization ordering with the new fastconfig system.


22-22: LGTM: Fastconfig migration.

The migration from printer.configfile.settings to printer.fastconfig.settings is correct and improves performance by avoiding costly deep copies during config access.

configuration/klippy/fastconfig.py (3)

20-36: LGTM: Well-designed immutable snapshot pattern.

The one-time deep copy at klippy:connect creates an immutable snapshot of the configuration, trading a single upfront cost for eliminating repeated expensive deep copies during macro execution. Removing the save_config_pending fields from the snapshot is appropriate since this wrapper is read-only.


37-40: LGTM: Proper initialization guard.

The get_status method correctly enforces that the wrapper can only be queried after initialization. The eventtime parameter follows Klipper's standard status interface convention.


42-77: LGTM: Singleton-like copy semantics and complete Mapping interface.

The copy prevention methods (__copy__ and __deepcopy__ returning self) are essential to the performance optimization, ensuring that accessing this object never triggers expensive deep copies. The Mapping interface implementation is complete and correctly delegates to the immutable snapshot.

configuration/printers/v-core-4-idex/macros.cfg (1)

15-15: LGTM: Consistent with PR-wide patterns.

Both changes align with the broader PR updates:

  • The initial_duration increase ensures proper initialization ordering
  • The fastconfig migration improves performance by avoiding repeated deep copies

Also applies to: 42-42

configuration/macros/idex/util.cfg (1)

14-17: LGTM: Fastconfig migration for IDEX utilities.

The migration of stepper position and endstop settings from printer.configfile.settings to printer.fastconfig.settings is correct and consistent with the PR-wide performance improvements.

Also applies to: 40-41

configuration/klippy/ratos.py (9)

9-23: LGTM: Well-designed beacon probing regions structure.

The BeaconProbingRegions namedtuple provides a clean, typed interface for beacon probe configuration with clear field names and comprehensive documentation.


49-63: LGTM: Clear component and status field organization.

The new fields are well-organized with clear comments distinguishing initialization-time components from runtime status fields. These support the expanded RatOS functionality for beacon probing and bed mesh operations.


238-278: LGTM: Useful G-code control flow commands.

Both commands provide valuable functionality:

  • _RAISE_ERROR avoids unhelpful macro name prefixing
  • _TRY implements proper try/except/finally semantics in G-code

The broad exception catches in _TRY are intentional to implement the exception handling pattern correctly.


279-289: LGTM: Clean bed mesh profile validation.

The command correctly checks for profile existence and updates the status field for macro access. The error handling appropriately validates that a profile name was provided.


607-649: LGTM: Robust safe home position calculation with beacon region validation.

The safe home position calculation correctly:

  • Falls back to middle of printable area when not specified
  • Validates against beacon probing regions when beacon is configured
  • Triggers a shutdown with a clear error message if the safe home position is outside the beacon-probable region, preventing runtime failures

651-694: LGTM: Well-implemented fuzzy home positioning.

The fuzzy radius implementation correctly:

  • Uses sqrt(random.random()) for uniform distribution within the circle
  • Constrains the fuzzy position to beacon probing regions or printable area
  • Logs warnings when constraints are applied
  • Updates status with the actual position moved to

The use of standard pseudo-random is appropriate for position variance in probing (not cryptographic).


696-705: LGTM: Comprehensive status exposure.

The updated status dictionary properly exposes all the new runtime state for macro access, including the safe home position calculation and last movement position.


711-801: LGTM: Sophisticated debugging infrastructure.

The stack trace functionality provides valuable debugging capabilities for G-code macro execution:

  • Crawl markers (;$text) enable callsite identification
  • The callback pattern allows frame-specific formatting
  • The implementation correctly uses Python's inspect module for stack introspection

803-870: LGTM: Clean progress display handler implementation.

The BackgroundDisplayStatusProgressHandler provides a polished user experience with:

  • Animated spinner using Unicode Braille characters
  • Auto-rate progress increment capability
  • Proper timer lifecycle management
  • Configurable update interval and message formatting
configuration/homing.cfg (4)

81-81: LGTM: Centralized safe home position calculation.

The migration from individual safe_home_x/safe_home_y calculations to the centralized printer.ratos.safe_home_position ensures consistency and enables beacon-aware validation logic in a single location.

Also applies to: 124-124


155-156: LGTM: Flexible beacon calibration flow.

The updated HOME_Z logic correctly implements two beacon calibration modes:

  • When beacon_contact_start_print_true_zero is enabled, it skips multi-point probing during homing and defers critical zero probing to start print after heat soaking
  • Otherwise, it performs full calibration during homing

The conditional logic is clear and the parameters are properly validated. Based on learnings, SKIP_MULTIPOINT_PROBING is a valid RatOS-specific parameter.

Also applies to: 173-190


236-236: LGTM: Fastconfig migration for sensorless homing.

The migration of stepper driver run_current lookups from printer.configfile.config to printer.fastconfig.config is correct and consistent with the PR-wide performance improvements. These values are correctly restored after sensorless homing operations.

Also applies to: 240-240, 247-247, 251-251, 302-302, 306-306, 313-313, 317-317


329-330: LGTM: Centralized safe home movement implementation.

The fastconfig migration for z_hop settings is correct. The macro rename to __MOVE_TO_SAFE_Z_HOME_ECHO_DEBUG reflects that the actual movement logic has been centralized in ratos.py (cmd_MOVE_TO_SAFE_Z_HOME), while this macro now serves as a debug logging helper called by the Python implementation.

Also applies to: 334-336

configuration/klippy/ratos_z_offset.py (5)

7-33: LGTM: Clean Z-offset module initialization.

The module correctly:

  • Defines clear offset categories (toolhead, true_zero_correction, hotend_thermal_expansion)
  • Integrates with Klipper's gcode_move transform chain at connect time
  • Registers appropriate G-code commands

37-78: LGTM: Clean command implementation with proper validation.

The offset management commands are well-designed:

  • GET_RATOS_Z_OFFSET provides clear output including the combined offset
  • SET_RATOS_Z_OFFSET and CLEAR_RATOS_Z_OFFSET use the shared _validate_and_set_offset helper (addressing the past review concern)
  • The public set_offset method enables programmatic access for other extensions

80-87: LGTM: Proper validation with clean zero-offset handling.

The validation correctly ensures only recognized offset names are used, and removing zero offsets from the dictionary keeps the status clean and efficient.


92-104: LGTM: Correct gcode_move transform implementation.

The transform methods correctly implement Klipper's transform chain pattern:

  • get_position removes the offset so G-code sees the intended Z position
  • move applies the offset to the actual movement, ensuring proper tool height

109-119: LGTM: Efficient status reporting.

The status implementation correctly exposes all individual offsets plus the combined offset for macro access. The lazy initialization and caching on change is efficient.

configuration/scripts/ratos-install.sh (1)

4-4: Clarify the purpose and necessity of the libopenblas-base dependency.

The libopenblas-base package is being added alongside python3-numpy. While OpenBLAS is a linear algebra library that NumPy can use for performance optimization, the review comment speculates about its purpose (beacon mesh calculations) without confirming whether this dependency is actually required for the new changes or if it's optional. Confirm that this package is needed for the functionality being introduced, and if so, consider documenting the rationale in the commit message or code.

configuration/printers/v-core-3-hybrid/macros.cfg (1)

5-9: LGTM: Timing adjustment for hybrid initialization.

The increase in initial_duration from 0.1 to 0.2 seconds provides additional initialization time for the hybrid CoreXY configuration, which aligns with the broader timing adjustments introduced across the PR for extended startup flows and beacon integration.

configuration/macros/parking.cfg (1)

29-29: LGTM: Fastconfig migration for beacon detection.

The migration from printer.configfile.settings.beacon to printer.fastconfig.settings.beacon is consistent with the PR-wide shift to the immutable fastconfig wrapper introduced in this PR. This change centralizes configuration access and aligns with the new configuration architecture.

configuration/macros/idex/idex_is.cfg (2)

46-46: LGTM: Consistent fastconfig migration for resonance testing.

The change from printer.configfile.settings.resonance_tester.probe_points to printer.fastconfig.settings.resonance_tester.probe_points aligns with the PR-wide configuration access refactoring. This ensures the IDEX input shaper macros use the centralized immutable configuration wrapper.


306-306: LGTM: Second fastconfig reference for belt tension measurement.

Consistent with the fastconfig migration pattern applied throughout the PR, ensuring both shaper calibration and belt tension measurement macros use the same configuration access method.

configuration/printers/base.cfg (1)

45-48: LGTM: Base configuration additions for fastconfig and bed mesh.

The addition of the [bed_mesh] section with split_delta_z: 0.01 helps reduce visible surface artifacts, and the empty [fastconfig] section establishes the load point for the new immutable configuration wrapper module. These are appropriate foundational settings for the base printer configuration.

configuration/printers/v-core-4-idex/v-core-4-idex.cfg (1)

7-11: LGTM: V-Core 4 IDEX beacon and mesh configuration.

The addition of beacon_adaptive_heat_soak: True enables the new adaptive heat-soak functionality for this printer model, and the finer split_delta_z: 0.001 (compared to 0.01 in base.cfg) is appropriate for the higher precision expected from the V-Core 4 IDEX platform.

configuration/printers/v-core-4/macros.cfg (1)

16-16: LGTM: Fastconfig migration in Z_TILT_ADJUST.

The migration to printer.fastconfig.settings.beacon in the Z_TILT_ADJUST macro is consistent with the PR-wide configuration access refactoring, ensuring beacon detection uses the centralized immutable configuration wrapper.

configuration/scripts/ratos-common.sh (1)

194-197: LGTM: Extension registration for new modules.

The four new extension entries correctly register the new Klipper modules introduced in this PR:

  • ratos_z_offset_extension for Z-offset management
  • beacon_true_zero_correction_extension for enhanced beacon calibration
  • beacon_adaptive_heatsoak_extension for adaptive heat soak functionality
  • fastconfig for the immutable configuration wrapper

Each entry follows the established pattern with correct realpath resolution.

configuration/printers/v-core-4/v-core-4.cfg (1)

7-11: Configuration additions for Beacon adaptive heat soak look good.

The variable_beacon_adaptive_heat_soak: True enables the new adaptive heat soak feature, and split_delta_z: 0.001 is an appropriate value for reducing visible surface stripe artifacts in bed mesh probing. Based on learnings, Klipper's config section merging allows this duplicate [gcode_macro RatOS] section to override/extend parameters from earlier definitions in base.cfg.

configuration/macros/idex/vaoc.cfg (5)

117-117: Migration to fastconfig for safe_distance looks correct.

The change from printer.configfile.settings to printer.fastconfig.settings is consistent with the broader PR migration pattern.


304-304: Consistent fastconfig usage.


633-633: Fastconfig-based beacon check is appropriate.

This aligns with the migration pattern and correctly gates the temp offset calibration on beacon presence.


736-740: Conditional hotend heat soak implementation looks good.

The new hotend_heat_soak_time knob provides flexibility for thermal expansion compensation. The conditional execution when > 0 and conversion to milliseconds (* 1000) for G4 dwell is correct.


882-978: No action required.

Klipper's config section merging is the intended behavior for handling duplicate macro definitions. Later definitions override earlier ones without error. If the macros are identical, the duplicate is redundant but harmless. To determine if removal is warranted, verify whether the duplicate definitions are truly identical or if there are intentional differences that should be consolidated into a single definition.

configuration/macros/priming.cfg (7)

32-45: Fastconfig migration for probe result saving is consistent.

The migration from printer.configfile.settings to printer.fastconfig.settings for beacon, bltouch, and probe detection maintains the same logic flow while using the new centralized config access.


105-122: Fastconfig usage for bed_mesh and probe offsets is correct.

The changes properly migrate config access patterns for:

  • bed_mesh.horizontal_move_z
  • bed_mesh config object
  • Probe offset retrieval for bltouch, probe, and beacon

207-217: Beacon detection for probe method selection is properly migrated.


262-262: Nozzle diameter retrieval via fastconfig is correct.


354-356: Probe existence validation properly migrated.


379-381: Consistent with T0 probe validation above.


410-412: Beacon nozzle temp offset integration is correct.

configuration/macros/idex/toolheads.cfg (8)

496-498: Fastconfig beacon check in T0 toolchange offset flow is correct.


563-565: Consistent fastconfig usage for T1 toolchange offset flow.


766-766: Timing adjustment coordinates with RATOS_INIT ordering.

Increasing initial_duration from 0.1 to 0.2 ensures _INIT_TOOLHEADS runs after RATOS_INIT (which runs at 0.1s), aligning with the startup ordering comment added in util.cfg.


779-785: Fastconfig-based safe_distance validation is properly migrated.


791-792: Capturing offset_before for debugging purposes is helpful.

The offset_before variable captures the homing origin state before applying offsets, enabling before/after comparison in debug logs.


811-821: Enhanced debug logging with precision formatting.

The .round(6) formatting provides consistent decimal precision in debug output.


825-827: Fastconfig beacon check for nozzle temp offset is consistent.


830-834: New debug logging macro for toolhead offset tracking.

The _SET_TOOLHEAD_OFFSET_LOG_DEBUG macro provides a clean way to log offset changes with before/after state comparison. Note that this macro reads printer.gcode_move.homing_origin at execution time, so offset_after will reflect the state when the macro runs (after the offset is applied), while offset_before was captured before the SET_GCODE_OFFSET commands.

configuration/macros/util.cfg (4)

48-61: Startup ordering documentation and fastconfig migration are well-implemented.

The comment block clearly documents the initialization order requirement (RATOS_INIT at 0.1s must run first, others at ≥0.2s). The simplified beacon check using printer.fastconfig.settings.beacon removes the previous dual condition checking both beacon and zero_reference_position.


255-258: Fastconfig migration for hybrid corexy check is correct.


383-383: Fastconfig usage for skew profile lookup is correct.


397-400: Verify _RAISE_ERROR macro exists.

The _STOP_AND_RAISE_ERROR macro calls _RAISE_ERROR, but this macro definition could not be located in the configuration files. If _RAISE_ERROR has been removed or is not defined, invoking _STOP_AND_RAISE_ERROR will result in a runtime error.

configuration/macros/overrides.cfg (2)

95-107: Beacon nozzle thermal-offset integration in M104/M109/SET_HEATER_TEMPERATURE looks solid

The new Beacon hooks correctly:

  • Gate on printer.fastconfig.settings.beacon is defined and is_printing_gcode, so they don’t affect non‑Beacon or out‑of‑print calls.
  • Respect IDEX copy/mirror by applying offsets to both toolheads and using the existing RatOS T* temperature_offset variables.
  • Reuse the same toolhead index (t) resolution in SET_HEATER_TEMPERATURE so the behavior matches M104/M109.

This wiring looks coherent with the rest of the RatOS/Beacon integration; I don’t see functional issues here.

Also applies to: 146-153, 166-191


203-248: Temperature wait offsets and bed‑mesh wrapper behavior align with Beacon/fastconfig flow

  • TEMPERATURE_WAIT now:

    • Maps SENSOR=extruder|extruder1 to a toolhead index, applies that toolhead’s temperature_offset to MINIMUM/MAXIMUM, and logs against a computed id (“sensor …” vs “toolhead Tn”).
    • Falls through to TEMPERATURE_WAIT_BASE SENSOR="{sensor}" when neither bound is provided, preserving Klipper’s native error behavior while adding explicit debug/echo messages.
  • SKEW_PROFILE’s switch to printer.fastconfig.settings["skew_correction %s" % params.LOAD] is consistent with the rest of the fastconfig migration and still guards on the key being defined.

  • The new BED_MESH_CALIBRATE wrapper cleanly:

    • Runs Z‑tilt / quad‑gantry leveling first (with rehome of Z where needed),
    • Handles stowable probes via DEPLOY/STOW,
    • Adds Beacon‑specific model checks and applies RatOS bed mesh parameters only when Beacon is configured.

Overall these changes are coherent and preserve sensible behavior for non‑Beacon setups.

Also applies to: 259-269, 319-354

configuration/macros/mesh.cfg (1)

15-47: Zero‑reference and Beacon sanity checks are well‑designed

The additions around _BED_MESH_SANITY_CHECK and _START_PRINT_BED_MESH look robust:

  • Validating bed_mesh.zero_reference_position against printer.ratos.safe_home_position and fuzzy true‑zero mode ensures misconfigurations are caught early with clear console errors.
  • The flow “explicit zero_reference_position from fastconfig, else fall back to last true‑zero position or safe_home” is sensible and keeps behavior deterministic across prints.
  • Beacon warning messages for contact bed mesh, automatic scan, and contact Z‑tilt adjust are explicit and actionable.
  • Preflight _START_PRINT_PREFLIGHT_CHECK_AND_RESET_BED_MESH correctly resets the internal fuzzy true‑zero coordinates and delegates Beacon scan‑comp validation to the dedicated macro.

I don’t see functional issues here; this is a nice tightening of mesh/beacon interactions.

Also applies to: 48-55, 72-79, 98-123

configuration/macros.cfg (2)

320-333: START_PRINT preflight and adaptive heat‑soak wiring is coherent

The updated START_PRINT flow ties together Beacon and bed‑mesh nicely:

  • Preflight:

    • _START_PRINT_PREFLIGHT_CHECK_BEACON_MODEL is only called when printer.fastconfig.settings.beacon is defined and gives an early, clear failure if a model is required (for homing or true zero) but not present.
    • _START_PRINT_PREFLIGHT_CHECK_AND_RESET_BED_MESH centralizes mesh state reset and Beacon scan‑comp profile validation before heating.
  • Bed heating / heat soak:

    • For Beacon + beacon_adaptive_heat_soak, the sequence _MOVE_TO_SAFE_Z_HOME, G1 Z2.5, and BEACON_WAIT_FOR_PRINTER_HEAT_SOAK (with layer quality, first‑layer duration, min/max wait) matches the new adaptive heat‑soak API.
    • The legacy bed_heat_soak_time branch remains intact as a fallback when adaptive heat soak is disabled or Beacon is absent.
  • The conditional PARK_TOOLHEAD suppression when Beacon true zero or adaptive heat soak is active avoids unnecessarily moving away from the bed while relying on Beacon measurements.

This overall sequencing looks correct and matches the new Python heat‑soak module’s interface.

Also applies to: 359-365, 601-640, 624-639


879-889: Fuzzy true‑zero storage and runtime Z‑offset restoration are wired correctly

  • _START_PRINT_AFTER_HEATING_CONTACT_WITH_OPTIONAL_WIPE:

    • Derives a fuzzy radius from beacon_contact_start_print_true_zero_fuzzy_position and beacon_contact_start_print_true_zero_fuzzy_radius, passes it into _MOVE_TO_SAFE_Z_HOME, and then stores printer.ratos.last_move_to_safe_z_home_position via _START_PRINT_AFTER_HEATING_CONTACT_WITH_OPTIONAL_WIPE_STORE_TRUE_ZERO_POSITION.
    • This feeds the actual_true_zero_position_x/y variables later consumed by _START_PRINT_BED_MESH (via zero_ref_pos fallback), so the mesh’s zero reference follows the last true-zero contact point.
  • The true‑zero calibration call correctly distinguishes:

    • With beacon_contact_calibrate_model_on_print: BEACON_AUTO_CALIBRATE (full model+true zero).
    • Without: BEACON_AUTO_CALIBRATE SKIP_MODEL_CREATION=1 (true zero only).
  • At the end of START_PRINT, the sequence:

    • _BEACON_SET_NOZZLE_TEMP_OFFSET RESET=True
    • _BEACON_SET_NOZZLE_TEMP_OFFSET TOOLHEAD={initial_tool}
    • _BEACON_RESTORE_RUNTIME_OFFSET (when contact true zero is enabled)

ensures the model‑based contact expansion is reapplied cleanly and the user’s saved runtime Z offset is restored on top of the new true-zero baseline. END_PRINT’s _BEACON_SUBTRACT_CONTACT_EXPANSION_OFFSET + _BEACON_SET_NOZZLE_TEMP_OFFSET RESET=True then correctly unwind that expansion component.

This end‑to‑end flow appears internally consistent.

Also applies to: 982-987, 1040-1051, 1055-1060, 787-797, 1273-1284

configuration/z-probe/beacon.cfg (2)

19-27: Beacon calibration/adaptive‑heat‑soak configuration is coherent

Key pieces line up well here:

  • [beacon] tweaks (mesh_runs docs and mesh_cluster_size: 0) are consistent with the new Beacon mesh helper’s behavior, avoiding aliasing from clustered sampling.

  • The empty [beacon_true_zero_correction] and [beacon_adaptive_heat_soak] sections (plus [ratos_z_offset]) correctly activate the corresponding Python extensions without forcing per‑printer overrides.

  • New RatOS variables under [gcode_macro RatOS] for:

    • beacon_contact_* (true-zero, wipe, bed mesh, z‑tilt adjust),
    • scan compensation (beacon_scan_compensation_*),
    • adaptive heat soak (beacon_adaptive_heat_soak_*),
      are all consumed via |default(...), so older configs remain compatible.
  • Calibration macros:

    • BEACON_INITIAL_CALIBRATION and BEACON_FINAL_CALIBRATION use BEACON_AUTO_CALIBRATE SKIP_MULTIPOINT_PROBING=1 for their internal contact calibration passes, which is appropriate for setup routines.
    • BEACON_FINAL_CALIBRATION now optionally uses BEACON_WAIT_FOR_PRINTER_HEAT_SOAK with its own min/max wait, quality, and first‑layer duration parameters, gated by beacon_adaptive_heat_soak, so full Beacon calibration can reuse the same adaptive soak logic as START_PRINT.
  • The already_heated flag that flows from BEACON_RATOS_CALIBRATE into BEACON_FINAL_CALIBRATION ensures you don’t redo chamber/bed heat soak when scan‑compensation calibration has already brought the machine to temperature.

Overall this config side matches the new Python and macro flows cleanly.

Also applies to: 45-46, 55-75, 83-131, 170-215, 276-338


658-747: Nozzle expansion and runtime Z‑offset helpers look internally consistent

The new macros for Beacon contact expansion and runtime Z offset appear sound:

  • _BEACON_SET_NOZZLE_TEMP_OFFSET:

    • Only applies expansion when both beacon_contact_start_print_true_zero and beacon_contact_expansion_compensation are enabled.
    • Handles IDEX by:
      • Applying offsets only when the target toolhead is actually “active/applicable” (default toolhead in copy/mirror; current active tool in single mode).
      • Using per‑toolhead expansion coefficients from save_variables with a multiplier, and adjusting by the delta from the previously applied expansion (nozzle_expansion_applied_offset).
    • Uses SET_GCODE_OFFSET Z_ADJUST=... plus SAVE_VARIABLE to keep the applied expansion offset tracked and reversible, with detailed debug logging via _BEACON_SET_NOZZLE_TEMP_OFFSET_LOG_DEBUG.
  • _BEACON_SUBTRACT_CONTACT_EXPANSION_OFFSET correctly subtracts the saved applied expansion offset at END_PRINT (single‑toolhead path), after which _BEACON_SET_NOZZLE_TEMP_OFFSET RESET=True clears the tracking variable.

  • _BEACON_SET_RUNTIME_OFFSET and _BEACON_RESTORE_RUNTIME_OFFSET:

    • Capture beacon_saved_runtime_offset as the current gcode Z offset minus the applied expansion compensation (and minus the active IDEX Z‑offset where applicable), so what’s stored is effectively the user’s runtime/babystepped Z offset.
    • Later restore it via SET_GCODE_OFFSET Z_ADJUST={runtime_offset}, which is appropriate because it’s applied onto the fresh true‑zero + expansion baseline at START_PRINT.
    • The Z_OFFSET_APPLY_PROBE wrapper only switches to this RatOS path when Beacon contact true zero is enabled; otherwise, it falls back to the original Klipper behavior.

These pieces fit together with the macros in configuration/macros.cfg and the true‑zero Python module; I don’t see a correctness hole here, assuming the existing save_variables keys are present on IDEX setups.

Please double‑check on a real IDEX machine that:

  • idex_applied_offset / idex_zoffset are always present in save_variables before _BEACON_SET_RUNTIME_OFFSET can run, and
  • The restored runtime offset matches user expectations after a full START_PRINT/END_PRINT cycle with Beacon contact true zero enabled.

Also applies to: 1169-1205, 1207-1228

@tg73
Copy link
Collaborator Author

tg73 commented Dec 3, 2025

@coderabbitai get_config_dir() appears to be a hallucination, or at least it's not present in the version of klipper we use.

config_dir = self.printer.get_config_dir()
+            filename = os.path.join(config_dir, f'mpp_capture_{timestamp}.csv')

The correct way to get the configuration directory is:

			config_file = self.printer.get_start_args()['config_file']
			config_dir = os.path.dirname(config_file)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 3, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for get_config_dir usage in the codebase
rg -n "get_config_dir" --type=py -C3

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for get_start_args usage to confirm the correct pattern
rg -n "get_start_args" --type=py -C3

Length of output: 569


🏁 Script executed:

#!/bin/bash
# Look for the specific file mentioned in the context - beacon_true_zero_correction.py
cat configuration/klippy/beacon_true_zero_correction.py | head -200

Length of output: 8972


@tg73 Thank you for the correction! You're absolutely right—get_config_dir() doesn't exist in Klipper. I apologize for the error.

Looking at the current code in configuration/klippy/beacon_true_zero_correction.py (lines 183-184), I can see there's a hardcoded path that should be fixed:

timestamp = time.strftime("%Y%m%d_%H%M%S")
filename = f'/home/pi/printer_data/config/mpp_capture_{timestamp}.csv'

This should be updated to use your suggested approach:

config_file = self.printer.get_start_args()['config_file']
config_dir = os.path.dirname(config_file)
filename = os.path.join(config_dir, f'mpp_capture_{timestamp}.csv')

I confirmed that get_start_args() is indeed used elsewhere in the codebase (e.g., in vaoc_led.py), so this is the correct pattern for Klipper. I'll remember this for future references.


✏️ Learnings added
Learnt from: tg73
URL: https://github.com/Rat-OS/RatOS-configurator/pull/101

Timestamp: 2025-12-03T12:18:28.372Z
Learning: In Klipper Python modules, to get the configuration directory, use `config_file = self.printer.get_start_args()['config_file']` followed by `config_dir = os.path.dirname(config_file)`. The method `self.printer.get_config_dir()` does not exist in Klipper.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

tg73 added a commit to tg73/RatOS-configurator that referenced this pull request Dec 3, 2025
…gurator@topic/first-layer-improvements-pr

- This merge was performed while development was taking place away from the main RatOS repos.
- Merges upstream PR Rat-OS#101
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants