Skip to content

[Knock to trigger macros] Beat your printer into obedience! - #326

Open
shawn-makes-stuff wants to merge 1 commit into
OpenCentauri:mainfrom
shawn-makes-stuff:knock-gestures
Open

[Knock to trigger macros] Beat your printer into obedience!#326
shawn-makes-stuff wants to merge 1 commit into
OpenCentauri:mainfrom
shawn-makes-stuff:knock-gestures

Conversation

@shawn-makes-stuff

@shawn-makes-stuff shawn-makes-stuff commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Knock gestures: knock a rhythm on the frame to run a macro

Knock on the printer frame and COSMOS runs a macro. Uses the accelerometer already on the toolhead, no extra hardware. Only active while the printer is idle.

How it works

The LIS2DW12 on the toolhead has a hardware tap detector. While the printer is idle the module runs it at 1600 Hz; every knock latches a flag, and a small poll reads the flag 20 times a second, counts knocks and times the gaps between them. A second of silence closes the pattern. Patterns are matched by the proportions of their gaps, so the same rhythm knocked faster or slower still matches (tolerance configurable, 35% default). Two-knock patterns compare short vs long gap instead.

Recording is knock-and-confirm: knock the rhythm, the console asks for it again, a match saves it. Recorded patterns live in /user-resource/knock/knock.json and take precedence over the built-in [knock_pattern] sections.

Commands

One console command, KNOCK:

KNOCK list patterns and state
KNOCK ENABLED=0 / ENABLED=1 feature off / on, persists
KNOCK CALIBRATE=1 learn the user's tempo (5 quick knocks twice, then 3 with pauses)
KNOCK RECORD=1 NAME=x MACRO=<gcode> record a pattern bound to a macro (MACRO="M117 hi" with quotes for arguments)
KNOCK RECORD=1 NAME=x PARROT=1 ...bound to parrot mode: the toolhead replays the rhythm from the bed centre
KNOCK RECORD=1 NAME=x PRINT="text" ...bound to a console message; combines with MACRO or PARROT
KNOCK REMIND=x forgot a pattern? the toolhead plays it back
KNOCK DELETE=x remove a pattern

Built in: a double tap toggles the case and toolhead lights ([knock_pattern lights] in extras-readonly/knock.cfg).

Setup

  1. Idle printer, open the console. KNOCK shows "enabled". Knock the frame twice, lights toggle.
  2. KNOCK CALIBRATE=1, follow the prompts. Once.
  3. KNOCK RECORD=1 NAME=home MACRO=G28, knock a rhythm, knock it again. Done.

Performance and safety

  • Idle only. Gated on idle_timeout state and on the accelerometer not being in use by a measurement. During prints, moves and resonance tests the chip is powered down and the task sleeps on the idle_timeout:ready / idle_timeout:idle events. No polling, no SPI, no CPU while printing. Measured on the CC1: klippy at its normal baseline while busy.
  • Idle cost: one SPI register read per 50 ms, about 2% of one core on the CC1. Memory is bounded (patterns dict, no sample buffers, no numpy).
  • Off switch: cosmos.conf [klipper] knock = False (default True) removes the include, module not loaded. KNOCK ENABLED=0 at runtime.
  • Motion from a knock (parrot, remind, user macros) goes through normal gcode and only when idle.

Changes

  • recipes-apps/klipper/files/knock.py: the klippy extra, installed to klippy/extras/
  • recipes-apps/klipper/files/knock.cfg: [knock] options and the default lights pattern, installed to extras-readonly/
  • kalico_2026.02.00.bb: install both
  • config-manager: knock option in default.conf, validator, and build-klipper-var-config.sh emits the include into zextras.cfg when True
  • docs/knock.md, README bullet

Notes for review

  • The module uses the lis2dw object's set_reg/read_reg and its bulk helper's is_started flag to detect measurements. Deliberate; commented in the source.
  • The poll runs as a reactor greenlet (like bulk_sensor) because SPI reads block.

New klippy extra (knock.py) that uses the toolhead LIS2DW12 tap engine to
detect knocks on the frame while the printer is idle. Knocks are grouped
into patterns matched by the proportions of the gaps between them, so a
pattern can be knocked faster or slower. One console command, KNOCK,
records patterns (knock, knock again to confirm), binds them to a macro,
a console message and/or "parrot" playback of the rhythm by the toolhead,
lists, deletes, reminds, calibrates tempo, and enables/disables.

Only runs while idle: during prints, moves and resonance tests the
accelerometer is powered down and the task sleeps on idle_timeout events.
Idle cost is one register read per 50 ms (about 2% of one core); memory
is bounded. Disabled via cosmos.conf [klipper] knock = False, in which
case the module is not loaded.

Ships a default double-tap that toggles the case and toolhead lights.
Recorded patterns persist in /user-resource/knock/knock.json.
@Atomique13

Copy link
Copy Markdown
Member

Me likey 😋

@shawn-makes-stuff
shawn-makes-stuff marked this pull request as ready for review September 13, 2026 15:34
@shawn-makes-stuff

Copy link
Copy Markdown
Contributor Author

I'm aware that its real world use is probably a bit limited, but its a cool gimmick so I'm leaving it here. If you decide that you don't want it just close the pr and I'll whine in discord later.

@TheDevMinerTV

Copy link
Copy Markdown
Collaborator

cursed

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.

3 participants