Klipper Router is a small JSON-RPC bridge that connects multiple Klipper instances over their Unix sockets and lets them call each other using a shared set of remote methods. Its purpose is to support auxiliary functions that are independent from the main printer, and often non-critical, such as a printer with a dedicated LED controller, or a printer with multiple separate MMU controllers. With the router, the printer can reach the status of those services and vice versa.
What it does
- Connects to multiple Klipper sockets defined in a router config.
- Registers a shared set of remote methods on every Klipper instance.
- Routes G-code, events, and object status updates across instances.
Each Klipper instance connects to the router over a Unix socket. The router speaks Klipper’s JSON-RPC protocol and registers its own remote methods on every connected instance. When a macro calls a router method, the router forwards the request to the target instance and optionally turns the response into a G-code callback.
Key behavior from src/klipper_router.py:
- Connects to each socket and calls
info, then subscribes towebhooksstatus. - Marks a connection “ready” when Klipper reports
state=ready. - Registers router methods like
router/gcode/script,router/objects/subscribe, etc. - For object subscriptions, it forwards updates from one printer to another and converts status dictionaries into G-code parameters.
sequenceDiagram
participant Main as Klipper (main)
participant Router as Klipper Router
participant LED as Klipper (led)
Router->>Main: connect + info
Router->>LED: connect + info
Router->>Main: register_remote_method(router/*)
Router->>LED: register_remote_method(router/*)
LED->>Router: router/objects/subscribe target=main, objects={print_stats: [state]}, gcode_callback=ON_STATUS_UPDATE
Router->>Main: objects/subscribe response_template=router/objects/update
Main-->>Router: status_update (print_stats.state=printing)
Router->>LED: router/objects/update params=status
Router->>LED: gcode/script "ON_STATUS_UPDATE PRINT_STATS_STATE='printing'"
Create a router config with one section per Klipper instance:
# router.cfg
[klippy main]
sock: /tmp/klippy_host_main_uds
on_connect: M118 Router connected to main
[klippy led]
sock: /tmp/klippy_host_led_uds
on_connect: M118 Router connected to LEDThe example configuration lives in examples/klipper_router.cfg.example.
These are the remote methods the router registers on every connected Klipper instance. They are used by Klipper macros via action_call_remote_method, but you can call them directly with JSON-RPC as well.
| Method | Params | Purpose |
|---|---|---|
router/gcode/script |
target (printer name), script (G-code string) |
Send G-code to another printer. |
router/event/subscribe |
event, gcode, optional callback_target, optional callback_type (gcode or webhook) |
Register a global event handler. |
router/event/trigger |
event, optional context (key/value map for template substitution) |
Trigger a global event. |
router/printers/list |
none | List printers with name, connected, ready. |
router/objects/list |
target |
Proxy Klipper objects/list from the target. |
router/objects/query |
target, objects (dict of objects to query) |
Proxy Klipper objects/query from the target. |
router/objects/subscribe |
target, objects (dict of objects to subscribe), gcode_callback (macro name on the caller) |
Subscribe to target updates and forward status as a callback. |
router/objects/update |
internal | Internal method used as the subscription response template; forwards status to the gcode_callback. |
includes/router_api.cfg provides G-code macros that wrap the router methods:
ROUTER_GCODE_SCRIPT TARGET=<name> SCRIPT=<gcode>ROUTER_EVENT_SUBSCRIBE EVENT=<name> GCODE=<gcode>ROUTER_EVENT_TRIGGER EVENT=<name>ROUTER_PRINTERS_LISTROUTER_OBJECTS_LIST TARGET=<name>ROUTER_OBJECTS_QUERY TARGET=<name> OBJECTS=<obj1,obj2>ROUTER_OBJECTS_SUBSCRIBE TARGET=<name> OBJECTS=<obj1,obj2> CALLBACK=<gcode>
You can include it in any Klipper config:
[include ../../includes/router_api.cfg]This test spins up three Klipper instances (main, afc, led) and a router, then demonstrates how LED reacts to print_stats.state changes from the main printer.
- Configures a minimal virtual printer and
virtual_sdcard. - Uses
delayed_gcodeto printtest.gcodeafter 10 seconds. - That triggers Klipper’s
print_statsstate transitions:standby→printing→complete.
- Implements
ROUTER_ON_CONNECTEDto detect whenmainconnects. - Calls
SUBSCRIBE_MAIN_STATUSusingrouter/objects/subscribetargetingmainwithobjects={'print_stats': ['state']}andgcode_callback='ON_STATUS_UPDATE'. ON_STATUS_UPDATEcompares the last seen state and triggers the corresponding macro forprinting,paused,complete,cancelled,error, orstandby.- Each macro currently emits an
M118message and includes commentedSET_LEDcommands you can enable.
When the main printer sends a status update, the router encodes the dictionary into G-code parameters. For print_stats.state, the callback receives:
ON_STATUS_UPDATE PRINT_STATS_STATE='printing'
The LED macro uses params.PRINT_STATS_STATE to decide which LED macro to run.
From the repo root:
./test/run.sh ./test/print_statsFor a tmux view with serial consoles:
./test/run-tmux.sh ./test/print_stats