nixos/klipper: Expose firmware and flasher packages in config (#432658)

This commit is contained in:
Cabia Rangris
2025-10-14 12:51:46 +00:00
committed by GitHub
+88 -63
View File
@@ -16,6 +16,68 @@ let
lib.concatMapStrings (s: "\n ${lib.generators.mkValueStringDefault { } s}") l;
mkKeyValue = lib.generators.mkKeyValueDefault { } ":";
};
firmwareSubmodule = lib.types.submodule (
{ name, ... }@local:
let
mcu = local.name;
subcfg = local.config;
in
{
options = {
enable = lib.mkEnableOption ''
building of firmware for manual flashing
'';
enableKlipperFlash = lib.mkEnableOption ''
flashings scripts for firmware. This will add `klipper-flash-$mcu` scripts to your environment which can be called to flash the firmware.
Please check the configs at [klipper](https://github.com/Klipper3d/klipper/tree/master/config) whether your board supports flashing via `make flash`
'';
serial = lib.mkOption {
type = lib.types.nullOr lib.types.path;
description = "Path to serial port this printer is connected to. Derived from `service.klipper.settings` by default.";
defaultText = lib.literalExpression "config.services.klipper.settings.<name>.serial";
default =
if lib.hasAttrByPath [ "${mcu}" "serial" ] cfg.settings then cfg.settings."${mcu}".serial else null;
};
configFile = lib.mkOption {
type = lib.types.path;
description = "Path to firmware config which is generated using `klipper-genconf`";
};
package = lib.mkOption {
type = lib.types.nullOr lib.types.package;
readOnly = true;
description = "Path to the built firmware package.";
};
klipperFlashPackage = lib.mkOption {
type = lib.types.nullOr lib.types.package;
readOnly = true;
description = "Path to the built klipper-flash package.";
};
};
config = {
package =
if subcfg.enable then
pkgs.klipper-firmware.override {
klipper = cfg.package;
mcu = lib.strings.sanitizeDerivationName mcu;
firmwareConfig = subcfg.configFile;
}
else
null;
klipperFlashPackage =
if subcfg.enable && subcfg.enableKlipperFlash then
pkgs.klipper-flash.override {
klipper = cfg.package;
klipper-firmware = subcfg.package;
mcu = lib.strings.sanitizeDerivationName mcu;
flashDevice = subcfg.serial;
firmwareConfig = subcfg.configFile;
}
else
null;
};
}
);
in
{
imports = [
@@ -119,30 +181,17 @@ in
};
firmwares = lib.mkOption {
description = "Firmwares klipper should manage";
description = "Firmwares Klipper should manage";
default = { };
type =
with lib.types;
attrsOf (submodule {
options = {
enable = lib.mkEnableOption ''
building of firmware for manual flashing
'';
enableKlipperFlash = lib.mkEnableOption ''
flashings scripts for firmware. This will add `klipper-flash-$mcu` scripts to your environment which can be called to flash the firmware.
Please check the configs at [klipper](https://github.com/Klipper3d/klipper/tree/master/config) whether your board supports flashing via `make flash`
'';
serial = lib.mkOption {
type = lib.types.nullOr path;
default = null;
description = "Path to serial port this printer is connected to. Leave `null` to derive it from `service.klipper.settings`.";
};
configFile = lib.mkOption {
type = path;
description = "Path to firmware config which is generated using `klipper-genconf`";
};
};
});
type = lib.types.attrsOf firmwareSubmodule;
example = {
mcu = {
enable = true;
enableKlipperFlash = true;
serial = "/dev/serial/by-id/usb-Klipper_123ABCDEF";
configFile = lib.literalExpression "./klipper-firmware.cfg";
};
};
};
};
};
@@ -158,16 +207,6 @@ in
assertion = cfg.user != null -> cfg.group != null;
message = "Option services.klipper.group is not set when services.klipper.user is specified.";
}
{
assertion =
cfg.settings != null
-> lib.foldl (a: b: a && b) true (
lib.mapAttrsToList (
mcu: _: mcu != null -> (lib.hasAttrByPath [ "${mcu}" "serial" ] cfg.settings)
) cfg.firmwares
);
message = "Option services.klipper.settings.$mcu.serial must be set when settings.klipper.firmware.$mcu is specified";
}
{
assertion = (cfg.configFile != null) != (cfg.settings != null);
message = "You need to either specify services.klipper.settings or services.klipper.configFile.";
@@ -176,7 +215,16 @@ in
assertion = (cfg.configFile != null) -> (cfg.extraSettings == "");
message = "You can't use services.klipper.extraSettings with services.klipper.configFile.";
}
];
]
++ lib.mapAttrsToList (mcu: firmware: {
assertion = firmware.enable -> firmware.serial != null;
message = ''
Unable to determine the serial connection for services.klipper.firmwares."${mcu}". Please set one of the following:
- services.klipper.firmwares."${mcu}".serial
- services.klipper.settings."${mcu}".serial
'';
}) cfg.firmwares;
services.klipper = lib.mkIf cfg.octoprintIntegration {
user = config.services.octoprint.user;
@@ -257,37 +305,14 @@ in
genconf = pkgs.klipper-genconf.override {
klipper = cfg.package;
};
firmwares = lib.filterAttrs (n: v: v != null) (
lib.mapAttrs (
mcu:
{
enable,
enableKlipperFlash,
configFile,
serial,
}:
if enable then
pkgs.klipper-firmware.override {
klipper = cfg.package;
mcu = lib.strings.sanitizeDerivationName mcu;
firmwareConfig = configFile;
}
else
null
) cfg.firmwares
firmwares = lib.filter (v: v != null) (
lib.mapAttrsToList (mcu: firmware: firmware.package) cfg.firmwares
);
firmwareFlashers = lib.filter (v: v != null) (
lib.mapAttrsToList (mcu: firmware: firmware.klipperFlashPackage) cfg.firmwares
);
firmwareFlasher = lib.mapAttrsToList (
mcu: firmware:
pkgs.klipper-flash.override {
klipper = cfg.package;
klipper-firmware = firmware;
mcu = lib.strings.sanitizeDerivationName mcu;
flashDevice = default cfg.firmwares."${mcu}".serial cfg.settings."${mcu}".serial;
firmwareConfig = cfg.firmwares."${mcu}".configFile;
}
) (lib.filterAttrs (mcu: firmware: cfg.firmwares."${mcu}".enableKlipperFlash) firmwares);
in
[ genconf ] ++ firmwareFlasher ++ lib.attrValues firmwares;
[ genconf ] ++ firmwares ++ firmwareFlashers;
};
meta.maintainers = [
lib.maintainers.cab404