Skip to content

Macros

Macros are small, reusable automations triggered by specific moments in a print's lifecycle. BamDude supports two kinds of macros: classic G-code macros (the printer runs custom G-code) and MQTT-action macros (BamDude tells the printer to do something via its MQTT control channel — toggle the chamber light, etc.).

Use them for plate-swap mechanisms, chamber lighting, enclosure control, or any other per-event automation that doesn't belong in your slicer's start/end G-code.


Action Types

A macro's action_type decides what happens when its event fires.

Sends a G-code snippet over MQTT (gcode_line), wrapped in M1002 gcode_claim_action markers. The printer ACKs the snippet and BamDude waits for the printer's stg_cur to return to idle before reporting the macro complete.

Use cases

  • Bed levelling, custom park positions, vibration calibration
  • Plate swap-mode operations (eject + home + prep next plate)
  • Anything you would put in a slicer's start/end G-code but want orchestrated by BamDude instead

Limitations

  • G-code on print_started fights the print itself — the firmware is already running its own start sequence. Don't do this unless you know exactly why.
  • Long G-code on swap_mode_change_table is fine; it runs while the printer is idle between plates.

Invokes a named MQTT command from BamDude's catalog instead of sending G-code. Fire-and-forget — the printer doesn't ACK, so BamDude doesn't wait for completion.

Currently shipping commands

ID Value Effect
chamber_light on / off Turn the chamber light on or off
print_speed 1–4 Set the speed level: Silent, Standard, Sport, Ludicrous

An action names the command; the value is a separate setting that appears in the editor once you pick the action.

Use cases

  • Auto-light-on at print start, auto-light-off at print finish
  • Drop to Silent speed part-way through an overnight print
  • External automations that don't need the G-code pipeline

Chamber light macros made before 0.5.3

The light used to be two separate commands, chamber_light_on and chamber_light_off. They are now one command with an On/Off value, and existing macros are converted the first time the new version starts — they keep doing exactly what they did.

Print speed only applies while printing

The printer accepts a speed change during a print. Bambu Studio refuses one when the machine is idle, and so does BamDude's own printer card, so a speed macro is worth binding to layer_reached or print_started, not to print_finished.

The catalog lives in core/mqtt_macro_actions.py and is exposed to the frontend via /macros/meta. New named commands are added there as use cases come up.

Compatibility

Pre-0.4.0 G-code macros keep working unchanged. New macros default to G-code unless you explicitly pick MQTT-action in the editor.


Events

Each macro is bound to exactly one event. Action-type support is not symmetric across events — see the table below.

Event When It Fires Allowed action types
print_started When gcode_state transitions to RUNNING (via on_print_start) mqtt_action only. A G-code macro bound to this event is silently skipped at runtime (macro_trigger.py logs "Skipping gcode macro — only mqtt_action macros are supported for event-driven triggers"). G-code mid-print would fight the print itself.
print_finished When the print reaches a terminal state (FINISH, FAILED, or IDLE-aborted), via on_print_complete mqtt_action only, same reason — gcode here isn't wired yet (the trigger is shared with print_started).
swap_mode_start Before the print starts, when dispatch knows it's running with a swap-mode profile G-code only in practice — the swap-mode dispatcher executes the macro synchronously and waits for stg_cur to return to idle. Pick G-code that prepares the swap mechanism.
swap_mode_change_table After the print completes, before the queue picks up the next item G-code only, same reason. The macro physically swaps plates. See Swap Mode.
layer_reached While the print runs, when the layer counter crosses the Layer you set mqtt_action only — refused at save time for G-code, for the same reason as print_started.

Don't bind G-code to print_started / print_finished

The macro UI lets you save the combination, but it won't run. If you want chamber lights or external relays toggled on print events, use MQTT-action macros. G-code on these events is a planned future extension, not a current feature.

layer_reached in detail

One layer per macro — for two changes at two layers, make two macros.

The trigger is a crossing, not an exact match: MQTT reports do get dropped, so a print that jumps from layer 48 to 52 has still passed 50 and the macro for layer 50 still runs.

It runs once per print, and that survives more than the obvious cases:

  • a printer that drops its MQTT connection mid-print gets a fresh client whose layer counter starts at 0 — the replay past your layer does not fire the macro again;
  • neither does a BamDude restart mid-print, because what already ran is recorded on the print's archive entry as well as in memory;
  • a cancelled print followed by a new one does start fresh, which is what you want.

It also waits for the print to genuinely start. Some models — the P1S among them — tick the layer counter during the calibration they run beforehand, up to half an hour before the first layer goes down. Those ticks don't count.

print_finished covers all terminal states

Whether the print finished cleanly, failed, or was aborted from the printer's screen, print_finished fires once. Use it when you want behaviour to apply regardless of outcome (turn the light off, notify external systems, etc.).


Choosing macros per print

Macros are opt-in per print. The print dialog and the queue dialog list the macros that apply to the target printer, and only the ones you tick run for that job.

  • The list is filtered to the printer's model, to enabled macros, and to a matching swap profile. If nothing applies, the panel does not appear.
  • Your choice is remembered per printer model, exactly as the swap-macro panel's is. Open the dialog for another printer of the same model and the same ticks come back.
  • What is remembered is what you turned off, so a macro you create later arrives ticked rather than quietly missing.
  • Editing a queued job shows what that job stored. A macro created after it was queued starts unticked there — tick it if you want it.

A print started outside BamDude runs no macros

There is no dialog on a print launched from the printer's screen, sent straight from a slicer, started from Telegram, or received by the virtual printer — so nothing was ticked, and nothing runs. The same is true of jobs that were already sitting in a queue before this version. If you depend on a macro for those prints, queue them through BamDude and tick it.

Filter Fields

Both action types share the same filter set. A macro fires only when every filter matches.

Field Behaviour
enabled Global toggle. Disabled macros are skipped without further evaluation.
printer_models JSON array of model codes (e.g. ["A1 Mini", "X1 Carbon"]) or ["*"] for all models.
swap_mode_only Fire only when the printer has swap mode enabled. Hidden in the UI for non-swap events.
swap_profile Fire only when the printer's selected swap profile matches this value (a1mini_kit, a1mini_stl, or jobox-a1 — see Swap Mode). Lets multiple swap-mode G-code variants coexist.
delay_seconds 0–3600. Defer the action by N seconds after the trigger. 0 = immediate.

Why delay_seconds matters

Some events fire just before the printer is in the visible state you'd expect. Chamber-light-on at print_started looks premature on some models because the firmware-side start sequence (heat-up, purge) hasn't finished. A 10–30 s delay avoids flicker without you having to wire up your own state-machine.


Editing Macros

  1. Go to Settings → Macros.
  2. Pick or create a macro. Choose the Action Type (G-code or MQTT-action).
  3. Pick the Event. For layer_reached, a Layer field appears — set the layer the macro should fire on.
  4. Set filter fields (printer models, swap mode, profile, delay).
  5. For G-code macros, type the snippet into the editor. For MQTT-action macros, pick the command from the dropdown — and if it takes a value, a second dropdown appears beneath it.
  6. Save.

Test G-code on the printer first

Bad G-code can damage your printer. Run new snippets manually before binding them to an event.


How Macros Run

Macros run as fire-and-forget asyncio tasks. A slow G-code send, a long delay, or even a network blip never blocks the surrounding orchestration — on_print_start returns immediately and the macro fires in the background.

For G-code macros, the dispatcher additionally waits for the on_macro_complete callback (printer's stg_cur returning to idle) before proceeding to the next G-code macro in the same event chain. MQTT-action macros are fully fire-and-forget; nothing waits on them.


Replacing the Old auto_light_off Flag

Pre-0.4.0 BamDude had an auto_light_off boolean on each printer. It was dropped in migration m021 because macros do the same job better — with delay control, on/off symmetry, per-model targeting, and per-swap-profile filters.

To restore the old behaviour:

Field Value
Action type MQTT-action
Event print_finished
Command chamber_light
Value off
delay_seconds 0
Field Value
Action type MQTT-action
Event print_started
Command chamber_light
Value on
delay_seconds 10 (let heat-up finish first)

Pair both for full automatic-lighting cycles. Add swap_mode_only=true if you only want lights to cycle for swap-mode runs.


Swap Mode Integration

Swap-mode prints rely on G-code macros bound to swap_mode_start and swap_mode_change_table. See Swap Mode for the full lifecycle, restart-resilient event tracking, and dispatch ordering on multi-printer farms.


Macros vs G-code Injection

Macros and the G-code Injection feature look similar but solve different problems:

Aspect Macro G-code injection
Where it runs Server-side: BamDude sends gcode_line over MQTT at lifecycle events. Embedded in the file gcode: spliced into plate_*.gcode before upload, runs at the exact point in the print sequence the slicer would normally insert end-gcode.
Trigger Lifecycle event (print_started, print_finished, swap mode, manual). Per-job toggle on the print itself.
Survives server outage No — server has to be online to send. Yes — once the file is on the printer, BamDude can disappear.
Best for Lights, plugs, chamber heaters, status pings, swap-mode plate changes. Park-to-back-left, purge-tower clean cuts, mid-print pauses, post-cool-down park positions that must run before the printer's own end-gcode resets state.

Use macros first — they're simpler. Drop down to G-code injection when you need a snippet that has to fire inside the printer's own end-of-print sequence and survive even if BamDude crashed mid-print.


Tips

Pair print_started with print_finished

Use one MQTT-action macro on each event for clean symmetric automation (lights, fans, external relays).

Use delay_seconds for chamber-light-on

A 10–30 s delay hides the heat-up phase from the chamber camera and avoids the "premature lights-on" look on H2/X1.

Combine with smart plugs

For full plate-eject + cooldown + power-off cycles, pair end-event macros with Smart Plugs auto power-off.