diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index a6c3fdd1ed23..645b4ac55741 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -145,6 +145,15 @@
services.maddy.
+
+
+ K40-Whisperer,
+ a program to control cheap Chinese laser cutters. Available as
+ programs.k40-whisperer.enable.
+ Users must add themselves to the k40 group
+ to be able to access the device.
+
+
mtr-exporter,
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index d55a45f8b2b1..542fb24abbdc 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -45,6 +45,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
+- [K40-Whisperer](https://www.scorchworks.com/K40whisperer/k40whisperer.html), a program to control cheap Chinese laser cutters. Available as [programs.k40-whisperer.enable](options.html#opt-programs.k4-whisperer.enable). Users must add themselves to the `k40` group to be able to access the device.
+
- [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
- [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable).
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 351fcf7cdbb7..28974c17ec71 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -167,6 +167,7 @@
./programs/iftop.nix
./programs/iotop.nix
./programs/java.nix
+ ./programs/k40-whisperer.nix
./programs/kdeconnect.nix
./programs/kbdlight.nix
./programs/less.nix
diff --git a/nixos/modules/programs/k40-whisperer.nix b/nixos/modules/programs/k40-whisperer.nix
new file mode 100644
index 000000000000..3163e45f57e4
--- /dev/null
+++ b/nixos/modules/programs/k40-whisperer.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.programs.k40-whisperer;
+ pkg = cfg.package.override {
+ udevGroup = cfg.group;
+ };
+in
+{
+ options.programs.k40-whisperer = {
+ enable = mkEnableOption "K40-Whisperer";
+
+ group = mkOption {
+ type = types.str;
+ description = ''
+ Group assigned to the device when connected.
+ '';
+ default = "k40";
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.k40-whisperer;
+ defaultText = literalExpression "pkgs.k40-whisperer";
+ example = literalExpression "pkgs.k40-whisperer";
+ description = ''
+ K40 Whisperer package to use.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ users.groups.${cfg.group} = {};
+
+ environment.systemPackages = [ pkg ];
+ services.udev.packages = [ pkg ];
+ };
+}
diff --git a/pkgs/applications/misc/k40-whisperer/default.nix b/pkgs/applications/misc/k40-whisperer/default.nix
new file mode 100644
index 000000000000..b50a1751510e
--- /dev/null
+++ b/pkgs/applications/misc/k40-whisperer/default.nix
@@ -0,0 +1,74 @@
+{ stdenv
+, makeWrapper
+, writeText
+, python3
+, fetchzip
+, inkscape
+, lib
+, udevGroup ? "k40"
+}:
+
+let
+ pythonEnv = python3.withPackages (ps: with ps; [
+ lxml
+ pyusb
+ pillow
+ pyclipper
+ tkinter
+ ]);
+
+ udevRule = writeText "k40-whisperer.rules" ''
+ SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5512", ENV{DEVTYPE}=="usb_device", MODE="0664", GROUP="${udevGroup}"
+ '';
+
+in stdenv.mkDerivation rec {
+ pname = "k40-whisperer";
+ version = "0.59";
+
+ src = fetchzip {
+ url = "https://www.scorchworks.com/K40whisperer/K40_Whisperer-${version}_src.zip";
+ stripRoot = true;
+ sha256 = "0r8rhaksk87l44pwwpvrfnck2lyic3lgcbh3pi7ib6mrwbsyhlni";
+ };
+
+ nativeBuildInputs = [ makeWrapper ];
+
+ patchPhase = ''
+ substituteInPlace svg_reader.py \
+ --replace '"/usr/bin/inkscape"' '"${inkscape}/bin/inkscape"'
+ '';
+
+ buildPhase = "";
+
+ installPhase = ''
+ mkdir -p $out
+ cp -p * $out
+
+ mkdir -p $out/bin
+ mkdir -p $out/lib/udev/rules.d
+
+ ln -s ${udevRule} $out/lib/udev/rules.d/97-k40-whisperer.rules
+
+ makeWrapper '${pythonEnv.interpreter}' $out/bin/k40-whisperer \
+ --add-flags $out/k40_whisperer.py \
+ --prefix PYTHONPATH : $out
+ '';
+
+ meta = with lib; {
+ description = ''
+ Control software for the stock K40 Laser controller
+ '';
+ mainProgram = "k40-whisperer";
+ longDescription = ''
+ K40 Whisperer is an alternative to the the Laser Draw (LaserDRW) program that comes with the cheap Chinese laser cutters available on E-Bay and Amazon.
+ K40 Whisperer reads SVG and DXF files, interprets the data and sends commands to the K40 controller to move the laser head and control the laser accordingly.
+ K40 Whisperer does not require a USB key (dongle) to function.
+ '';
+ homepage = "https://www.scorchworks.com/K40whisperer/k40whisperer.html";
+ downloadPage = "https://www.scorchworks.com/K40whisperer/k40whisperer.html#download";
+ license = licenses.gpl3;
+ maintainers = with maintainers; [ fooker ];
+ platforms = platforms.all;
+ };
+}
+
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 247298df58e6..d1c8b6885688 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -33175,6 +33175,8 @@ with pkgs;
jstest-gtk = callPackage ../tools/misc/jstest-gtk { };
+ k40-whisperer = callPackage ../applications/misc/k40-whisperer { };
+
keynav = callPackage ../tools/X11/keynav { };
kgx = callPackage ../applications/terminal-emulators/kgx { };