Functional Test - ADXL345 status information

Basic Information:

Printer Model: N/A
MCU / Printerboard: Custom Main Controller Board
Host / SBC: rPi CM4/CM4 Equivalent
klippy.log

The original thread for this work was closed - I am continuing on it with a fair amount of success but I have a few questions going forward.

The first is getting the status information for the ADXL345. I’ve got it for BLTouch and TMC Stepper Drivers but I would like to get installed status information or be able to record the response to ACCELEROMETER_QUERY like what’s provided here:

Any suggestions?

Just my 2 cents, AFAIK adxl345 has self-test, and I think it probably makes sense to just use it (if we want to test the ADXL).
But this is something that requires implementation inside the ADXL345 Python module.


jfyi, you can just do something like:

$ python3 klippy/klippy.py rp2040_sht36v3.cfg -I /tmp/klippy_serial &
$ cat /tmp/klippy_serial  &
$ echo ACCELEROMETER_QUERY > /tmp/klippy_serial

I’m not even sure that I understand, what is actually requested.

Is it a purely cosmetic thing, that you get something like:

Test 5: ADXL345 Connection Test: 1110, 4290, 9622

@Sineos

What I’m looking for is to be able to determine whether or not the ADXL345 is present (ie the board hardware can communicate with the chip that is plugged into the header on the board).

@nefelim4ag

I’m trying to implement a “Functional Test” macro in which all of the tests are run within it. I’m basically there with the exception of this (and probably one or two other things I haven’t tested through).

What you’re suggesting is interesting and basically what I want although it is outside the main macro.

I’m not sure I’m implementing it correctly. For my system, I believe the command should be:

 python3 klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial & cat /tmp/kli
ppy_serial & echo ACCELEROMETER_QUERY > /tmp/klippy_serial

But, when I run that, I get the error:

Thanx for the responses!

1 Like

Basically, to get Klipper run from the console, you still need an environment.
(Lack of dependencies in the environment produces errors like No module named ..., greenlet in your output).

You can install dependencies in the system, or you can use/create a venv:

~/klippy-env/bin/python3 klipper/klippy/klippy.py ....

$ sign at the start of the string meant it is run by a user. # run by the root.
You can see that on your screenshot.
& means “fork”, so run in the background.
(I wrote it in that notation initially, to show the basic idea).

Basically, you want to start Klipper with the working board/config, and with -I /tmp/klippy_serial, it would have a Klipper console in this socket file.

You can basically do the same with multiple consoles/tabs. It would be more straightforward to understand and control:

  1. Run Klipper host.
  2. cat or read in any comfortable way.
  3. Write/pipe commands to the socket.

It can be further automated, but I hope it is easier and more powerful for testing, then use of macros.

Hope that helps a little.


Further Unix tools, like expect (TCL), or bash/shell (or python?) scripting on top of that, I suspect, are a slightly different topic. But the good thing is, there are plenty of them, and even neurodegenerative LLM should be able to suggest something useful, to read/write/check the output.
Basically, to do the tests.

But when the command returns values, then you know, right?

@nefelim4ag truly is a developer :slight_smile:

  • Start Klipper normally as you usually would. If you installed via KIAUH, the pseudo-tty is typically ~/printer_data/comms/klippy.serial.
  • Now you can communicate with Klipper from the shell, for example:
echo STATUS > ~/printer_data/comms/klippy.serial
  • Since there is no “return channel,” you will only see the result of the command in the web interface.
  • By running cat ~/printer_data/comms/klippy.serial &, you create a “return channel” and fork it into the background.
  • Now, when you use the echo command, you will receive the return value cluttering your shell, regardless of what else you are doing.
  • You could also redirect the output to a file, keep the channel open by omitting the &, or do whatever else you prefer.
2 Likes

@Sineos, thank you :smiley:
@mykepredko
Pardon, seems like a curse of knowledge on my side. I can miss, explanation for some things.

Feel free to ask.

1 Like

For your test environment, this seems like a very clever idea for automation. So, just for fun:

#!/bin/bash

TTY=~/printer_data/comms/klippy.serial

# Send STATUS command
echo -ne "STATUS\n" > "$TTY"

# Listen for the response (timeout after 2 seconds)
RESPONSE=$(timeout 2 cat "$TTY")

# Print the response
echo "$RESPONSE"

# Check if it contains "Ready"
if echo "$RESPONSE" | grep -q "Ready"; then
    echo "HURRAY"
fi

This would be a very stupid and basic way to exploit this functionality in a shell script.

Would you be insulted if I said it doesn’t?

Sorry, I’m a reasonably competent Linux user and have very good hardware/low level software skills but I don’t see what you’re trying to do and I can’t recreate your screenshot.

Having said that, I would prefer giving the manufacturing operator a single test interface. Right now, it is my plan on having two to carry out the following three steps:

  1. Load Katapult, run my firmware to enable DFU mode and then load the Klipper firmware. This is done from a Linux console
  2. Run my test macro from Mainsail
  3. Return to the Linux console to remove the Klipper firmware (ie “seal” the product and have it ready for the end user)

If I can run my test macros from Python or a shell (while monitoring/recording the result) that would make the manufacturing process simpler and, hopefully, be easier to code, debug and maintain than the macro interface.


So, with that background, could you explain/provide pointers to what you are trying to do?

Following what you’ve said, I’ve tried:

python3 klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &

which is run from the root directory, has the correct paths to klippy.py and the working config, but still produces:

biqu@cm4-kgp79:~ $ python3 klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &
[1] 32208
biqu@cm4-kgp79:~ $ Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/klippy.py", line 8, in <module>
    import util, reactor, queuelogger, msgproto
  File "/home/biqu/klipper/klippy/reactor.py", line 7, in <module>
    import greenlet
ModuleNotFoundError: No module named 'greenlet'
^C
[1]+  Exit 1                  python3 klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial
biqu@cm4-kgp79:~ $

Looking back at:

I think the instruction to get the klipper git:(rp2040-spi-fifo) got cut off.

If you can get me past this then I’m pretty confident I can get running on my own (with probably a little help along the way).

Thanx.

1 Like

@mykepredko, did you read my follow-up to @nefelim4ag’s proposal?

Assuming you are running commands from SBC, with Klipper installed by KIAUH.
There would be a virtualenv with installed Klippy’s Python dependencies ~/klippy-venv.

So, the proper full command line would look like:

~/klippy-env/bin/python3 ~/klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &

If it does not, you can recreate the venv:

## Recreate venv
python3 -m venv --clear ~/klippy-env/
## Install dependencies
~/klippy-env/bin/python3 -m pip install -r ~/klipper/scripts/klippy-requirements.txt
## Run klippy
~/klippy-env/bin/python3 ~/klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &

I’m running on my local dev machine, where Klippy’s Python dependencies are installed in the system.
So, my system’s python has access to them.

Hope that explains something.

Yes I did - thank you for it.

I didn’t have a chance to test it and I wanted to understand exactly what @nefelim4ag was suggesting first. Honestly, I wasn’t sure if it would meet all my requirements (as set out in the reply to @nefelim4ag ) so I considered that Plan B.

Sorry - I didn’t mean to be insulting.

Actually, my follow-up is exactly what @nefelim4ag is describing, even including a practical (albeit sloppy) example in Bash.

The only difference is that I am approaching it from a “user perspective”, especially regarding how to set up and start Klipper. @nefelim4ag is approaching it from a “developer perspective”, focusing on how to set up and use Klipper and the Klipper Python environment more targeted to Klipper development.

1 Like

Tried it and got an unexpected error:

biqu@cm4-kgp79:~ $ ~/klippy-env/bin/python3 printer_data/config/printer.cfg -I /tmp/klippy_serial &
[1] 34982
biqu@cm4-kgp79:~ $   File "/home/biqu/printer_data/config/printer.cfg", line 386
    canbus_uuid: 7eef9b446328
                 ^
SyntaxError: invalid decimal literal
^C
[1]+  Exit 1                  ~/klippy-env/bin/python3 printer_data/config/printer.cfg -I /tmp/klippy_serial
biqu@cm4-kgp79:~ $

Put “0x” in front of the canbus_uuid: value?

Is your Klipper starting when using the “regular” or “user” method?

All you are doing here is starting Klipper manually instead of using the mechanisms and information in the .service and .env files. If you start your Klipper regularly and check with ps axu, you will see this exact command line. Probably the only differences will be:

  • The -I argument that denotes the serial pseudo-tty path and defaults to ~/printer_data/comms/klippy.serial.
  • The -l (lowercase L) that denotes the log location.
  • The -a argument giving the path to the Unix domain socket.

The key aspects of:

  • Sending commands via shell.
  • Receiving Klipper’s responses via shell.

are not influenced by how you start Klipper or how you created the venv. The same rules for the printer.cfg also apply.

The error could stem from either an actual issue in your printer.cfg or something that went wrong during the creation of the klippy-env.

Edit:
You might also want to check if a Klipper instance is already running and using the same environment or paths. Not sure what the outcome would be.

Sorry Myke, for confusing you, I made a mistake when doing copy-paste.

~/klippy-env/bin/python3 ~/klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &

Post above, are also fixed.

Python should run klippy.py, not the printer.cfg
So successful run would look similar:

user@v-core-3:~ $ ~/klippy-env/bin/python3 ~/klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &
[1] 16639
user@v-core-3:~ $ INFO:root:Starting Klippy...
WARNING:root:No log file specified! Severe timing issues may result!
INFO:root:Start printer at Thu May 29 23:23:26 2025 (1748553806.1 30107.6)
INFO:root:BMxx80: Oversampling: Temp 2x Humid 2x Pressure 2x
INFO:root:BMxx80: IIR: 1x
INFO:root:Extruder max_extrude_ratio=2.494510
INFO:root:mcu 'mcu': Starting serial connect
....

Hey @Sineos,

Your script works nicely. After pulling my hair out for a couple of hours trying to figure out why I kept getting a “File Not Found” error, I realized that I saved the file in “Windows” format (line ending in \r\n) rather “Linux” (line ending in just \n) and everything worked fine.

Along with sending “Ready”, I made simple ping (internet connectivity check), accelerometer present and End Stop function test scripts:
sineosREADY_et_al.zip (1.7 KB)

Operations from the console look good:

and, along with the hardware operations, what I see on the Mainsail console looks good:

So, this is a very viable way of doing things and probably now my “Plan A” although I have to architect the code so that it makes sense for the manufacturing line and maintaining it as well as how to control external hardware (the “sineosINDICATOR.sh” script accesses external hardware via a macro which then sets rPi pin states; all of which seems a bit circuitous).

Thanx for posting this.

Thanx for the correction - I probably should have figured out the problem on my own.

Now, when I run the statement, I get a lot more than the few lines you posted above. In less than a second I got:

biqu@cm4-kgp79:~ $ ~/klippy-env/bin/python3 ~/klipper/klippy/klippy.py printer_data/config/printer.cfg -I /tmp/klippy_serial &
[1] 4045
biqu@cm4-kgp79:~ $ INFO:root:Starting Klippy...
WARNING:root:No log file specified! Severe timing issues may result!
INFO:root:Start printer at Fri May 30 01:56:01 2025 (1748584561.2 12868.9)
INFO:root:mcu 'mcu': Starting CAN connect
INFO:can.interfaces.socketcan.socketcan:Created a socket
WARNING:root:mcu 'mcu': got {'oid': 29, 'next_clock': 2242675712, 'value': 31548, '#name': 'analog_in_state', '#sent_time': 12869.873474847, '#receive_time': 12869.876277143}
WARNING:root:mcu 'mcu': got {'oid': 31, 'next_clock': 2243955712, 'value': 31549, '#name': 'analog_in_state', '#sent_time': 12869.873474847, '#receive_time': 12869.896292162}
WARNING:root:mcu 'mcu': got {'oid': 27, 'next_clock': 2260595712, 'value': 7606, '#name': 'analog_in_state', '#sent_time': 12870.126802495, '#receive_time': 12870.156274051}
WARNING:root:mcu 'mcu': got {'oid': 28, 'next_clock': 2261235712, 'value': 10877, '#name': 'analog_in_state', '#sent_time': 12870.126802495, '#receive_time': 12870.166284402}
WARNING:root:mcu 'mcu': got {'oid': 29, 'next_clock': 2261875712, 'value': 31555, '#name': 'analog_in_state', '#sent_time': 12870.126802495, '#receive_time': 12870.176311125}
WARNING:root:mcu 'mcu': got {'oid': 31, 'next_clock': 2263155712, 'value': 31583, '#name': 'analog_in_state', '#sent_time': 12870.177376273, '#receive_time': 12870.196270254}
INFO:root:Loaded MCU 'mcu' 126 commands (v0.12.0-474-g4b9add2f / gcc: (15:12.2.rel1-1) 12.2.1 20221205 binutils: (2.40-2+18+b1) 2.40)
MCU 'mcu' config: ADC_MAX=4095 BUS_PINS_i2c1_PA9_PA10=PA9,PA10 BUS_PINS_i2c1_PB6_PB7=PB6,PB7 BUS_PINS_i2c1_PB8_PB9=PB8,PB9 BUS_PINS_i2c2_PB10_PB11=PB10,PB11 BUS_PINS_i2c2_PB13_PB14=PB13,PB14 BUS_PINS_i2c3_PB3_PB4=PB3,PB4 BUS_PINS_i2c3_PC0_PC1=PC0,PC1 BUS_PINS_spi1=PA6,PA7,PA5 BUS_PINS_spi1a=PB4,PB5,PB3 BUS_PINS_spi2=PB14,PB15,PB13 BUS_PINS_spi2_PB2_PB11_PB10=PB2,PB11,PB10 BUS_PINS_spi2a=PC2,PC3,PB10 BUS_PINS_spi3=PB4,PB5,PB3 CANBUS_BRIDGE=1 CLOCK_FREQ=64000000 MCU=stm32g0b1xx PWM_MAX=255 RECEIVE_WINDOW=192 RESERVE_PINS_CAN=PD0,PD1 RESERVE_PINS_USB=PA11,PA12 RESERVE_PINS_crystal=PF0,PF1 STATS_SUMSQ_BASE=256 STEPPER_OPTIMIZED_EDGE=8 STEPPER_STEP_BOTH_EDGE=1
INFO:root:mcu 'host': Starting connect
WARNING:root:mcu 'mcu': got {'oid': 27, 'next_clock': 2279795712, 'value': 7602, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.456359791}
WARNING:root:mcu 'mcu': got {'oid': 28, 'next_clock': 2280435712, 'value': 10874, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.466347717}
WARNING:root:mcu 'mcu': got {'oid': 29, 'next_clock': 2281075712, 'value': 31551, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.476323476}
WARNING:root:mcu 'mcu': got {'oid': 31, 'next_clock': 2282355712, 'value': 31548, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.496360513}
INFO:root:Loaded MCU 'host' 124 commands (v0.12.0-451-g730e5951b / gcc: (Debian 12.2.0-14) 12.2.0 binutils: (GNU Binutils for Debian) 2.40)
MCU 'host' config: ADC_MAX=4095 CLOCK_FREQ=50000000 MCU=linux PCA9685_MAX=4096 PWM_MAX=32768 STATS_SUMSQ_BASE=256
INFO:root:mcu 'toolhead': Starting CAN connect
INFO:can.interfaces.socketcan.socketcan:Created a socket
WARNING:root:mcu 'mcu': got {'oid': 27, 'next_clock': 2298995712, 'value': 7603, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.756343809}
WARNING:root:mcu 'mcu': got {'oid': 28, 'next_clock': 2299635712, 'value': 10879, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.766315161}
WARNING:root:mcu 'mcu': got {'oid': 29, 'next_clock': 2300275712, 'value': 31556, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.776277198}
WARNING:root:mcu 'mcu': got {'oid': 31, 'next_clock': 2301555712, 'value': 31567, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12870.796272939}
WARNING:root:mcu 'mcu': got {'oid': 27, 'next_clock': 2318195712, 'value': 7599, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12871.056296606}
WARNING:root:mcu 'mcu': got {'oid': 28, 'next_clock': 2318835712, 'value': 10878, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12871.066330457}
WARNING:root:mcu 'mcu': got {'oid': 29, 'next_clock': 2319475712, 'value': 31566, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12871.076296643}
WARNING:root:mcu 'mcu': got {'oid': 31, 'next_clock': 2320755712, 'value': 31534, '#name': 'analog_in_state', '#sent_time': 12870.280726328, '#receive_time': 12871.096306124}
WARNING:root:mcu 'toolhead': got {'oid': 0, 'next_clock': 2321015513, 'value': 7509, '#name': 'analog_in_state', '#sent_time': 12871.079377902, '#receive_time': 12871.097823346001}
INFO:root:Loaded MCU 'toolhead' 125 commands (v0.12.0-474-g4b9add2f / gcc: (15:12.2.rel1-1) 12.2.1 20221205 binutils: (2.40-2+18+b1) 2.40)
MCU 'toolhead' config: ADC_MAX=4095 BUS_PINS_i2c1_PA9_PA10=PA9,PA10 BUS_PINS_i2c1_PB6_PB7=PB6,PB7 BUS_PINS_i2c1_PB8_PB9=PB8,PB9 BUS_PINS_i2c2_PB10_PB11=PB10,PB11 BUS_PINS_i2c2_PB13_PB14=PB13,PB14 BUS_PINS_i2c3_PB3_PB4=PB3,PB4 BUS_PINS_i2c3_PC0_PC1=PC0,PC1 BUS_PINS_spi1=PA6,PA7,PA5 BUS_PINS_spi1a=PB4,PB5,PB3 BUS_PINS_spi2=PB14,PB15,PB13 BUS_PINS_spi2_PB2_PB11_PB10=PB2,PB11,PB10 BUS_PINS_spi2a=PC2,PC3,PB10 BUS_PINS_spi3=PB4,PB5,PB3 CANBUS_FREQUENCY=1000000 CLOCK_FREQ=64000000 MCU=stm32g0b1xx PWM_MAX=255 RECEIVE_WINDOW=192 RESERVE_PINS_CAN=PB0,PB1 RESERVE_PINS_crystal=PF0,PF1 STATS_SUMSQ_BASE=256 STEPPER_OPTIMIZED_EDGE=8 STEPPER_STEP_BOTH_EDGE=1
INFO:root:mcu_temperature 'mcu' nominal base=-270.581395 slope=1309.447674
INFO:root:mcu_temperature 'toolhead' nominal base=-267.982709 slope=1298.126801
INFO:root:Configured MCU 'mcu' (1024 moves)
INFO:root:Configured MCU 'host' (1024 moves)
INFO:root:Configured MCU 'toolhead' (1024 moves)
INFO:root:Starting heater checks for heater0
INFO:root:Starting heater checks for heater1
WARNING:root:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

ERROR:root:Script running error
Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/extras/gcode_button.py", line 43, in button_callback
    self.gcode.run_script(template.render())
  File "/home/biqu/klipper/klippy/gcode.py", line 230, in run_script
    self._process_commands(script.split('\n'), need_ack=False)
  File "/home/biqu/klipper/klippy/gcode.py", line 212, in _process_commands
    handler(gcmd)
  File "/home/biqu/klipper/klippy/gcode.py", line 282, in cmd_default
    raise gcmd.error(self.printer.get_state_message()[0])
gcode.CommandError:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

WARNING:root:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

ERROR:root:Script running error
Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/extras/gcode_button.py", line 43, in button_callback
    self.gcode.run_script(template.render())
  File "/home/biqu/klipper/klippy/gcode.py", line 230, in run_script
    self._process_commands(script.split('\n'), need_ack=False)
  File "/home/biqu/klipper/klippy/gcode.py", line 212, in _process_commands
    handler(gcmd)
  File "/home/biqu/klipper/klippy/gcode.py", line 282, in cmd_default
    raise gcmd.error(self.printer.get_state_message()[0])
gcode.CommandError:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

WARNING:root:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

ERROR:root:Script running error
Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/extras/gcode_button.py", line 43, in button_callback
    self.gcode.run_script(template.render())
  File "/home/biqu/klipper/klippy/gcode.py", line 230, in run_script
    self._process_commands(script.split('\n'), need_ack=False)
  File "/home/biqu/klipper/klippy/gcode.py", line 212, in _process_commands
    handler(gcmd)
  File "/home/biqu/klipper/klippy/gcode.py", line 282, in cmd_default
    raise gcmd.error(self.printer.get_state_message()[0])
gcode.CommandError:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

WARNING:root:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

ERROR:root:Script running error
Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/extras/gcode_button.py", line 43, in button_callback
    self.gcode.run_script(template.render())
  File "/home/biqu/klipper/klippy/gcode.py", line 230, in run_script
    self._process_commands(script.split('\n'), need_ack=False)
  File "/home/biqu/klipper/klippy/gcode.py", line 212, in _process_commands
    handler(gcmd)
  File "/home/biqu/klipper/klippy/gcode.py", line 282, in cmd_default
    raise gcmd.error(self.printer.get_state_message()[0])
gcode.CommandError:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

WARNING:root:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

ERROR:root:Script running error
Traceback (most recent call last):
  File "/home/biqu/klipper/klippy/extras/gcode_button.py", line 43, in button_callback
    self.gcode.run_script(template.render())
  File "/home/biqu/klipper/klippy/gcode.py", line 230, in run_script
    self._process_commands(script.split('\n'), need_ack=False)
  File "/home/biqu/klipper/klippy/gcode.py", line 212, in _process_commands
    handler(gcmd)
  File "/home/biqu/klipper/klippy/gcode.py", line 282, in cmd_default
    raise gcmd.error(self.printer.get_state_message()[0])
gcode.CommandError:
Printer is not ready
The klippy host software is attempting to connect.  Please
retry in a few moments.

and it’s still spitting out (the error thrown above doesn’t seem to affect the operation of anything) lines of data that look like the WARNING:root:mcu messages you got along with what looks like klippy.log status information. Ctrl-C doesn’t stop the torrent of data - I have to shutdown and restart (which is something I don’t want to do on the manufacturing floor).

Along with all that, when I look at Mainsail, I get:

So, I’m not sure this is moving in the direction I need it to. For this to work I need:

  1. To suppress the data being dumped onto the console.
  2. Display test status information on the console as the test script executes (I’m not sure if the operator will be entering data yet).
  3. Have Klipper running so I can execute the test functions.
  4. Understand how to write the test script.

So sorry, I have no idea how to proceed here.

I’d just install Klipper as you would as a user. Fiddling around with the command line approach doesn’t add any value in this context and only introduces additional complexities.

For a similar task (non-Klipper), I wrote a Bash script a while back that I quickly adapted for Klipper. I know Python folks might shake their heads and smile mildly, but I’m just a script kiddie, and if I need something quickly, I feel most comfortable with shell scripting.

#!/bin/bash

TTY=~/printer_data/comms/klippy.serial
LOGFILE="./klippy_command_log.txt"
TIMEOUT=2  # seconds
WAIT_TIME=1     # seconds to wait between commands

: > "$LOGFILE"

coproc KLIPPY { stdbuf -o0 cat "$TTY"; }

# Arrays: one for commands, one for corresponding regex patterns
COMMANDS=(
  "STATUS"
  "GET_POSITION"
  "M115"
)

REGEX_PATTERNS=(
  "Ready"                                           # for STATUS
  "X:[0-9\.\-]+ Y:[0-9\.\-]+"                       # for GET_POSITION
  "v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\-]+)?"       # for M115
)

send_command() {
  local CMD="$1"
  local REGEX="$2"
  local RESPONSE=""
  local START_TIME=$(date +%s)

  echo ">>> $CMD" | tee -a "$LOGFILE"
  echo -ne "$CMD\n" > "$TTY"

  while true; do
    local NOW=$(date +%s)
    if (( NOW - START_TIME > TIMEOUT )); then
      echo "[TIMEOUT] No response for '$CMD' within ${TIMEOUT}s." | tee -a "$LOGFILE"
      return 1
    fi

    if read -r -t 0.1 line <&"${KLIPPY[0]}"; then
      echo "$line" | tee -a "$LOGFILE"
      RESPONSE+="$line"$'\n'
      if [[ "$line" =~ $REGEX ]]; then
        echo "[MATCH] '${BASH_REMATCH[0]}' matched pattern: $REGEX" | tee -a "$LOGFILE"
        return 0
      fi
    fi
  done
}

# === Execute sequence with wait ===
for i in "${!COMMANDS[@]}"; do
  CMD="${COMMANDS[$i]}"
  PATTERN="${REGEX_PATTERNS[$i]}"
  send_command "$CMD" "$PATTERN"
  sleep "$WAIT_TIME"
done

# === Clean up ===
kill $KLIPPY_PID 2>/dev/null

Output will look like:

>>> STATUS
// Klipper state: Ready
[MATCH] 'Ready' matched pattern: Ready
>>> GET_POSITION
ok
// mcu: stepper_x:0 stepper_y:0 stepper_z:0 stepper_z1:0 stepper_z2:0 stepper_z3:0
// stepper: stepper_x:0.000000 stepper_y:0.000000 stepper_z:0.000000 stepper_z1:0.000000 stepper_z2:0.000000 stepper_z3:0.000000
// kinematic: X:0.000000 Y:0.000000 Z:0.000000
[MATCH] 'X:0.000000 Y:0.000000' matched pattern: X:[0-9\.\-]+ Y:[0-9\.\-]+
>>> M115
// toolhead: X:0.000000 Y:0.000000 Z:0.000000 E:0.000000
// gcode: X:0.000000 Y:0.000000 Z:0.000000 E:0.000000
// gcode base: X:0.000000 Y:0.000000 Z:0.000000 E:0.000000
// gcode homing: X:0.000000 Y:0.000000 Z:0.000000
ok
ok FIRMWARE_NAME:Klipper FIRMWARE_VERSION:v0.13.0-120-gb1011e3fb-dirty
[MATCH] 'v0.13.0-120-gb1011e3fb-dirty' matched pattern: v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\-]+)?

The script is pretty basic and does not handle delays in responses and multi-line values very well. With JavaScript or Python, this could be a lot more elegant, but I’ll leave it up to you to figure it out.

1 Like

as @nefelim4ag mentioned, I also encourage you to consider Expect: Expect as it does automation of interactive stuff with timeouts and searching of response patterns really elegant.