From 7e9ffea95ac50bcf57622d437726dfaca32c9669 Mon Sep 17 00:00:00 2001 From: Kira Bruneau Date: Thu, 2 Jan 2025 18:10:04 -0500 Subject: [PATCH 1/2] nixos/klipper: preserve SAVE_CONFIG for nixos-managed config Klipper macros that use `SAVE_CONFIG` (eg. bed mesh calibration, PID tuning, ...) don't currently work with a nixos-managed config. This can be worked around by using `services.klipper.mutableConfig = true`, but then you lose out on being able to configure klipper from NixOS. This changes the default behaviour so that: 1. The config is stored in `services.klipper.configDir` instead of `/etc` 2. The config is copied instead of symlinked (keeping a timestamped backup of the existing config) 3. The `SAVE_CONFIG` section from the backup is copied over into the new config 4. The backup is deleted if the final config is identical --- nixos/modules/services/misc/klipper.nix | 57 +++++++++++++++---------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/nixos/modules/services/misc/klipper.nix b/nixos/modules/services/misc/klipper.nix index b2345cbf7f337..7bd65301bfeef 100644 --- a/nixos/modules/services/misc/klipper.nix +++ b/nixos/modules/services/misc/klipper.nix @@ -18,6 +18,13 @@ let }; in { + imports = [ + (lib.mkRenamedOptionModule + [ "services" "klipper" "mutableConfigFolder" ] + [ "services" "klipper" "configDir" ] + ) + ]; + ##### interface options = { services.klipper = { @@ -52,23 +59,22 @@ in default = false; example = true; description = '' - Whether to copy the config to a mutable directory instead of using the one directly from the nix store. - This will only copy the config if the file at `services.klipper.mutableConfigPath` doesn't exist. + Whether to manage the config outside of NixOS. + + It will still be initialized with the defined NixOS config if the file doesn't already exist. ''; }; - mutableConfigFolder = lib.mkOption { + configDir = lib.mkOption { type = lib.types.path; default = "/var/lib/klipper"; - description = "Path to mutable Klipper config file."; + description = "Path to Klipper config file."; }; configFile = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; - description = '' - Path to default Klipper config. - ''; + description = "Path to default Klipper config."; }; octoprintIntegration = lib.mkOption { @@ -162,11 +168,6 @@ in } ]; - environment.etc = lib.mkIf (!cfg.mutableConfig) { - "klipper.cfg".source = - if cfg.settings != null then format.generate "klipper.cfg" cfg.settings else cfg.configFile; - }; - services.klipper = lib.mkIf cfg.octoprintIntegration { user = config.services.octoprint.user; group = config.services.octoprint.group; @@ -178,9 +179,7 @@ in "--input-tty=${cfg.inputTTY}" + lib.optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}" + lib.optionalString (cfg.logFile != null) " --logfile=${cfg.logFile}"; - printerConfigPath = - if cfg.mutableConfig then cfg.mutableConfigFolder + "/printer.cfg" else "/etc/klipper.cfg"; - printerConfigFile = + printerConfig = if cfg.settings != null then format.generate "klipper.cfg" cfg.settings else cfg.configFile; in { @@ -188,19 +187,31 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; preStart = '' - mkdir -p ${cfg.mutableConfigFolder} - ${lib.optionalString (cfg.mutableConfig) '' - [ -e ${printerConfigPath} ] || { - cp ${printerConfigFile} ${printerConfigPath} - chmod +w ${printerConfigPath} + mkdir -p ${cfg.configDir} + pushd ${cfg.configDir} + if [ -e printer.cfg ]; then + ${ + if cfg.mutableConfig then + ":" + else + '' + # Backup existing config using the same date format klipper uses for SAVE_CONFIG + old_config="printer-$(date +"%Y%m%d_%H%M%S").cfg" + mv printer.cfg "$old_config" + # Preserve SAVE_CONFIG section from the existing config + cat ${printerConfig} <(printf "\n") <(sed -n '/#*# <---------------------- SAVE_CONFIG ---------------------->/,$p' "$old_config") > printer.cfg + ${pkgs.diffutils}/bin/cmp printer.cfg "$old_config" && rm "$old_config" + '' } - ''} - mkdir -p ${cfg.mutableConfigFolder}/gcodes + else + cat ${printerConfig} > printer.cfg + fi + popd ''; serviceConfig = { - ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${printerConfigPath}"; + ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${cfg.configDir}/printer.cfg"; RuntimeDirectory = "klipper"; StateDirectory = "klipper"; SupplementaryGroups = [ "dialout" ]; From 434cbc672b5e63e1f13cebf4ad02e276db27d3e4 Mon Sep 17 00:00:00 2001 From: Kira Bruneau Date: Fri, 10 Jan 2025 09:34:56 -0500 Subject: [PATCH 2/2] nixos/klipper: restart when config changes --- nixos/modules/services/misc/klipper.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/modules/services/misc/klipper.nix b/nixos/modules/services/misc/klipper.nix index 7bd65301bfeef..f134c4455b075 100644 --- a/nixos/modules/services/misc/klipper.nix +++ b/nixos/modules/services/misc/klipper.nix @@ -209,6 +209,8 @@ in popd ''; + restartTriggers = lib.optional (!cfg.mutableConfig) [ printerConfig ]; + serviceConfig = { ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${cfg.configDir}/printer.cfg";