In my functional test code, I’m checking for the presence of an ADXL345 using a macro to execute the ACCELEROMETER_QUERY command but I can’t figure out how to read and parse the response in the macro.
I’ve also looked at trying to change the ADXL234 values dynamically (which I should be able to capture the response) but I haven’t found any printer[adxl345]. objects that I can change (I was hoping for axes_map).
One comment to help explain what I’m doing and what I need. Looking back over the original post, I could have explained things better.
A script runs the main test code (which involves Flashing the Board Under Test’s MCU as well as accessing some simple python modules to exercise hardware attached to the board under test). For accessing hardware I have been executing the macros which execute the G-Code Commands in the Console and then parse the response, like:
After looking at adxl345.py, it looks like there isn’t an official status reference to read values from. However, I was able to dissect the ACCELEROMETER_QUERY command to make a simple Python script that can be run via Dynamic Macros to read the accelerometer values. You can probably do something similar to add a proper status reference if you wanted (via a get_status() function), which could be read by the Moonraker API.
I created the readadxl.py file (I changed it from “read_adxl” to avoid any underscore issues) what what should be the correct format for the Dynamic Macro Python file as described in
I did a Klipper Restart and was pleasantly surprised to see that the host version of Klipper is now “dirty” (expected due to adding the readadxl.py file):
Any suggestions on what I’ve done wrong? I think I have correctly set up the different READADXL class members and put the python file in the correct location.
I have not used dynamicmacros, from the errors you get it would seem you did not actually install dynamicmacros extension and instead created a standalone klipper extension that registers command READADXL and then proceeded to override the registered command with one that assumes existence of dynamicmacros.
I’m quite sure the contetns of the python file suggested by @3dcoded are meant verbatim, and I strongly suspect they are not meant to go into the klippy/extras folder. To make it work, you’d need to go through the setup procedure for dynamicmacros as described on the dynamicmacros site. Test the install with the tutorial from there first and then read up where exactly you should put the read_adxl.py my bet is next to the macro file.
First, a few explanations about Dynamic Macros. Dynamic Macros is an extra I designed to allow for updating macros without restarting Klipper, but it has since expanded to allow a host of features, Python code included. Dynamic Macros’s features can only be used by installing it (yes this will make Klipper “dirty”) and configuring as explained in its docs. The code I provided will work verbatim with Dynamic Macros. I tested it on my setup.
This problem can be approached in two main ways: DynamicMacros or extras.
DynamicMacros Approach
It looks like you created it as a full extra. The code I provided will work verbatim. Just put read_adxl.py in your printer config folder.
Like @bozzo said, this indicates that Dynamic Macros wasn’t installed or configured properly. Dynamic macros store macros in a separate file then read them with a [dynamicmacros] section, as explained in the docs.
Extras
If you want to do an extra that can provide a status reference for macros or Moonraker, you’re pretty close.
I made a few changes to get it to work as an extras module on my printer (explained in comments)
Then, put [readadxl] in your printer.cfgbelow your [adxl345] configuration.
You can use READADXL in the Mainsail/Fluidd console to update the accelerometer values. To read them, you can either access it via a macro (normal or Dynamic):
Sorry, I should have provided a more complete reply.
First off, I created a file containing what you provided placed it in ~/klipper/klippy/extras and it wasn’t recognized by Klipper - again, I was expecting to see the host Klipper version become “dirty” which, to me, indicates that it’s recognized by the system.
This never happened - after doing a RESTART, sudo service klipper stop followed by sudo service klipper stop and finally a full power cycle.
So, not seeing “dirty” indicated to me that the file wasn’t recognized.
My response to that was to read through the page and what you presented originally seemed to be the basis for an “extra” - it did not match what was described as a “Dynamic Macro”.
Could you explain how to install what you originally presented?
I tried your updates and no change - same error as above.
The problem I had here was that you don’t explain that the Python file is in the same folder as printer config (ie ~/printer_data/config). This is why I tried ~/klipper/klipper/extras as that seemed to make the most sense.
Can I suggest that be added to the documentation? I couldn’t find that instruction anywhere there.
Sorry for being so much trouble. I’m sure I’m doing/have done something wrong but I can’t figure out what it is.
Here is the process I use for setting up the system/SD Card image for the test process:
I don’t think I’m doing anything unusual or putting the Raspberry Pi CM4 host in some kind of unknown state. It’s a basic minimum 64bit OS, first does the Esoterical CANBus set up, load Klipper using KIAUH, load in Katapult, Load Numpy (obviously for what we’re doing here), Install a Klipper instance on the CM4. @bozzo - you may be interested in this.
For Dynamic Macros, macros are defined in a separate file, not printer.cfg or included by it. For example, if you put the macro in dmacros.cfg, you add the following to printer.cfg:
[dynamicmacros]
configs: dmacros.cfg
As for putting it after adxl345, that’s only necessary if you’re using a custom extra and not Dynamic Macros.
I think we’re confusing each other mixing up dynamic macros and extras. These are two different approaches to solve the same problem, reading accelerometer values into a macro.
Dynamic Macros are defined in a separate file and not included in your printer.cfg. They are instead read by a [dynamicmacros] section in your printer.cfg. The python file, read_adxl.py, is placed in the same folder as printer.cfg. This macro is called READ_ADXL
The extras approach for this is putting a different python file, readadxl.py, is in the extras directory and putting a [readadxl] section in printer.cfg. This approach provides the status reference and Moonraker API access to accelerometer values. This has a command called READADXL with an accompanying macro DISPLAY_ADXL to display the latest accelerometer values.
Since the sources are quite old (latest from Jun 12, 2023) and Klipper, Moonraker and Fluidd moved on, I imagine there could be problems with klipper-repl and an actual Klipper release.
You could write to unjordy and flowerysong asking for help here in discourse. flowerysong should be definitely reachable here at discourse (his last post is from May 19, 2025).
-a is the flag that tells Klipper where to create the API socket. If you’re running Klipper like this, you would then run klipper-repl /tmp/klippy_uds.
This would be a good introduction to your documentation page:
Looking back at how I did things, I started looking at the first page and, scanning through the table of contents, I jumped down to the “Examples” thinking that they were part of Dynamic Macros. “Extras” seemed to me to be “extra” information, not a different type of Dynamic Macro.
Sorry I had so much trouble figuring out the differences between the two - I’ll try to be less dense going forwards.
I figured this out on my own (by careful reading of the documentation - thanx) and changed Dynamic Macros to include the Dynamic Klipper macro “read_adxl” which checks the results of read_adxl.py:
With this and your read_adxl.py file, things started moving in the right direction and I got some results.
Now, when the ADXL345 is disconnected from the Board Under Test, the “values” returned was printed out as None which I thought was a Python value for a null object.
I changed the read_adxl.py code to:
adxl = printer.lookup_object('adxl345')
aclient = adxl.start_internal_client()
printer.lookup_object('toolhead').dwell(.1)
aclient.finish_measurements()
values = aclient.get_samples()
if values is None:
output("No ADXL345")
else:
_, x, y, z = values[-1]
output({
"x": x,
"y": y,
"z": z,
})
with the expectation that I would catch the None object but, following the output from my modified Dynamic Macro:
I’m posting this in the hope this tweaks on somebody.
@hcet14 I’m surprised that you would consider a two year old package as “quite old” - it says a lot regarding how much has been done to Klipper over what I would consider a little while.