Advanced macro templating support

I’ve been looking at Klipper’s existing Jinja2 templating support for macros and by the looks of it, we have the basic bare bones of Jinja2, plus the printer object and the actions_* commands.

I would like to introduce some extras, like a now() function to have the current date & time, some regular expression filters, …, some utility filters and functions that might come in handy for more “advanced” macro templating (kind like Home Assistant has)

I thought best to discuss this before doing any code… Is this something that would interest people?

1 Like

That could be useful. What specifically are you looking to add?

Right starters, I’m thinking on filters that would allow to make better conditional commands!

For example, one could have a buzzer sound only if the current time is between 10am and 10pm!

I currently have an open PR that would allow to have a rawparams on the custom command templates; that together with regular expression filters could allow for more fine-tuned custom commands!

This is just a simple example but given the possibility I do believe the community might come with some interesting things!

I would love improvements in this area! My macros are now around 3K lines, and sometimes convoluted to get around missing functionality. Some things I’ve been thinking about for Klipper/Jinja…

  1. Better reusability of macros/code. Adding ‘include’ support for Jinja2 so Jinja macros/functions can be reused would be fantastic. Even nicer would be for Jinja to share the namespace across Klipper macros so you could avoid having to do the ‘include’ on every macro that uses it (such as one include at the top of each Klipper macro file, or even just one at the start of printer.cfg)

  2. I’d love both time/date support. It would be nice to be able to get a string (various formats) that can be used for messages (such as RESPOND or M117) or in names (such as mesh profiles). Also a number, such as milliseconds (or seconds) since epoch, so relative time compare can be done (how long did this print take? how long to do a bed mesh?). And of course simple access to hours, minutes, day, month etc as numbers.

  3. Expanding on date/time, an alarm/timer feature [such as ‘[alarm_gcode]’ or ‘[timer_gcode]’) would be very useful (more of a Klipper plug-in than Jinja, but…) Basically the ability to specify gcode to execute at a particular time event (date/time, frequency like hourly, time of day, etc). Similar to [delayed_gcode] except it would run based on a specific time measurement. Also similar to delayed_gcode, it would allow macros to enable/disable or change the functionality at runtime. Use cases include turning off LED lights at a particular time, auto-pausing a print at night and starting up in morning, and starting a pre-heat of the bed/enclosure in the morning so it’s ready when you get to work.

HTH…

1 Like

Another feature I’d love to see is the ability to write content to a file. My primary use cases are general logging of macros (outside of the klipper log, which gets filled with other stuff), but also I’m doing a bunch of thermal analysis tests and currently I output CSV data to the console via action_respond_info but that then needs hand processing afterwards to get rid of the leading date/time and the ‘//’ comment characters before I can import the data into a spreadsheet for analysis.

@cmidgley For this kind of stuff you might be better suited to use the RUN_SHELL_COMMAND by adding the gcode_shell_command.py to your Klipper install!

1 Like

I tried … but currently gcode_shell_command doesn’t allow sending parameters to the shell script (so no way to send my data to the script). I do see why file access might not be a common need, or perhaps one better suited for task-specific extras python implementation.

I believe the script was actually updated quite recently to allow passing parameters, so do check again as it might actually do what you need!

Correct, gcode_shell_command does now support parameters. Additional documentation here:

FWIW, the printer object can be used for some time related functionality. While cputime will not tell you the present time it can be used to determine time deltas, e.g., present - previous. I believe that Cputime provides the elapsed time since the MCU was powered ON in whole Minutes.decimal fraction format.

printer.system_stats.cputime

CPU time indication of how much processing time that the process has used since the process has started, not the elapsed time since the MCU was powered ON!

CPU time - Wikipedia

Regarding timings, there is currently an open PR on GitHub related to this topic that you might want to follow.

Add unixtime pseudo-variable to jinja2 context by 30350n · Pull Request #6010 · Klipper3d/klipper (github.com)

Thanks for the heads up.

I would also like to have an absolute time to be able to switch printer off (via Tasmota) when it is the weekend or the printer has stopped at the middle of the night.
For that I need somehow to process the current day and time

The code changes for this are so trivial I’m surprised no-one’s done this.

In gcode_macro.py add an extra import…

from datetime import datetime

Then in method create_template_context add the following line to the returned object…

'now': datetime.now,

Then, after restarting, in your macro you can do…

{% set hour = now().hour %}

etc.

People would try all kinds of crazy timing things in their gcode and stall their printer and come to the forum and ask why Klipper isn’t working right.

Then they’d ask for non-blocking waits in the G-code, but how do you handle that in a G-code queue? Now you’re asking for multi-threaded Gcode.

As the person before you wanted, how would you even run a Gcode to determine if it’s the weekend and turn off your printer? That’s not really what GCodes are for, that’s what a home automation plug is for and Moonraker already works with that for that very thing.

People can probably already do all manner of stupid things in macros, but if they feel competent enough to change the code, they should understand what they are doing and accept the consequences.

I also agree that using G-code to turn the printer off is not sensible. Using time tests so it doesn’t sound a beeper at 3am possibly is.

The python code I run actually has significant changes in specific areas which I’ve merged with almost every update of the past year - I check for updates a couple of times a week. I haven’t yet decided if they’re likely to be useful enough to others to warrant a PR.

Having programmed for over 40 years and previously submitted PRs to Marlin and BTT’s touchscreen code, I probably do understand what I’m doing and if I encountered something I couldn’t fix myself and needed to ask for support would first revert to a standard setup to check I hadn’t done something stupid!