aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Command_Templates.md35
-rw-r--r--docs/Config_Reference.md14
-rw-r--r--docs/G-Codes.md11
-rw-r--r--klippy/extras/save_variables.py63
4 files changed, 123 insertions, 0 deletions
diff --git a/docs/Command_Templates.md b/docs/Command_Templates.md
index 47f7755e..26271b75 100644
--- a/docs/Command_Templates.md
+++ b/docs/Command_Templates.md
@@ -396,3 +396,38 @@ gcode:
```
UPDATE_DELAYED_GCODE ID=report_temp DURATION=0
```
+
+### Save Variables to disk
+
+If a
+[save_variables config section](Config_Reference.md#save_variables)
+has been enabled, `SAVE_VARIABLE VARIABLE=<name> VALUE=<value>` can be
+used to save the variable to disk so that it can be used across
+restarts. All stored variables are loaded into the
+`printer.save_variables.variables` dict at startup and can be used in
+gcode macros. to avoid overly long lines you can add the following at
+the top of the macro:
+```
+{% set svv = printer.save_variables.variables %}
+```
+
+As an example, it could be used to save the state of 2-in-1-out hotend
+and when starting a print ensure that the active extruder is used,
+instead of T0:
+
+```
+[gcode_macro T1]
+gcode:
+ ACTIVATE_EXTRUDER extruder=extruder1
+ SAVE_VARIABLE VARIABLE=currentextruder VALUE='"extruder1"'
+
+[gcode_macro T0]
+gcode:
+ ACTIVATE_EXTRUDER extruder=extruder
+ SAVE_VARIABLE VARIABLE=currentextruder VALUE='"extruder"'
+
+[gcode_macro START_GCODE]
+gcode:
+ {% set svv = printer.save_variables.variables %}
+ ACTIVATE_EXTRUDER extruder={svv.currentextruder}
+```
diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md
index 54156c68..5b0a8b54 100644
--- a/docs/Config_Reference.md
+++ b/docs/Config_Reference.md
@@ -1182,6 +1182,20 @@ gcode:
# Default is 0.
```
+## [save_variables]
+
+Support saving variables to disk so that they are retained across
+restarts. See
+[command templates](Command_Templates.md#save-variables-to-disk) and
+[G-Code reference](G-Codes.md#save-variables) for further information.
+
+```
+[save_variables]
+filename:
+# Required - provide a filename that would be used to save the
+# variables to disk e.g. ~/variables.cfg
+```
+
## [idle_timeout]
Idle timeout. An idle timeout is automatically enabled - add an
diff --git a/docs/G-Codes.md b/docs/G-Codes.md
index 9d9c0619..1a944f0c 100644
--- a/docs/G-Codes.md
+++ b/docs/G-Codes.md
@@ -647,6 +647,17 @@ been enabled (also see the
for gcode execution. A value of 0 will cancel a pending delayed gcode
from executing.
+## Save Variables
+
+The following command is enabled if a
+[save_variables config section](Config_Reference.md#save_variables)
+has been enabled:
+- `SAVE_VARIABLE VARIABLE=<name> VALUE=<value>`: Saves the variable to
+ disk so that it can be used across restarts. All stored variables
+ are loaded into the `printer.save_variables.variables` dict at
+ startup and can be used in gcode macros. The provided VALUE is
+ parsed as a Python literal.
+
## Resonance compensation
The following command is enabled if an
diff --git a/klippy/extras/save_variables.py b/klippy/extras/save_variables.py
new file mode 100644
index 00000000..8a6e9bec
--- /dev/null
+++ b/klippy/extras/save_variables.py
@@ -0,0 +1,63 @@
+# Save arbitrary variables so that values can be kept across restarts.
+#
+# Copyright (C) 2020 Dushyant Ahuja <dusht.ahuja@gmail.com>
+# Copyright (C) 2016-2020 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+import os, logging, ast, ConfigParser
+
+class SaveVariables:
+ def __init__(self, config):
+ self.printer = config.get_printer()
+ self.filename = os.path.expanduser(config.get('filename'))
+ self.allVariables = {}
+ try:
+ self.loadVariables()
+ except self.printer.command_error as e:
+ raise config.error(str(e))
+ gcode = self.printer.lookup_object('gcode')
+ gcode.register_command('SAVE_VARIABLE', self.cmd_SAVE_VARIABLE,
+ desc=self.cmd_SAVE_VARIABLE_help)
+ def loadVariables(self):
+ allvars = {}
+ varfile = ConfigParser.ConfigParser()
+ try:
+ varfile.read(self.filename)
+ if varfile.has_section('Variables'):
+ for name, val in varfile.items('Variables'):
+ allvars[name] = ast.literal_eval(val)
+ except:
+ msg = "Unable to parse existing variable file"
+ logging.exception(msg)
+ raise self.printer.command_error(msg)
+ self.allVariables = allvars
+ cmd_SAVE_VARIABLE_help = "Save arbitrary variables to disk"
+ def cmd_SAVE_VARIABLE(self, gcmd):
+ varname = gcmd.get('VARIABLE')
+ value = gcmd.get('VALUE')
+ try:
+ value = ast.literal_eval(value)
+ except ValueError as e:
+ raise gcmd.error("Unable to parse '%s' as a literal" % (value,))
+ newvars = dict(self.allVariables)
+ newvars[varname] = value
+ # Write file
+ varfile = ConfigParser.ConfigParser()
+ varfile.add_section('Variables')
+ for name, val in sorted(newvars.items()):
+ varfile.set('Variables', name, repr(val))
+ try:
+ f = open(self.filename, "w")
+ varfile.write(f)
+ f.close()
+ except:
+ msg = "Unable to save variable"
+ logging.exception(msg)
+ raise gcmd.error(msg)
+ gcmd.respond_info("Variable Saved")
+ self.loadVariables()
+ def get_status(self, eventtime):
+ return {'variables': dict(self.allVariables)}
+
+def load_config(config):
+ return SaveVariables(config)