From 451d7918ff45f631dcce4788a7e218f091b13f79 Mon Sep 17 00:00:00 2001 From: Soliprem Date: Fri, 12 Jun 2026 02:10:13 +0200 Subject: [PATCH] watt: init at 1.2.0 --- .../manual/release-notes/rl-2611.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/hardware/watt.nix | 71 +++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/watt.nix | 19 +++++ pkgs/by-name/wa/watt/package.nix | 64 +++++++++++++++++ 6 files changed, 158 insertions(+) create mode 100644 nixos/modules/services/hardware/watt.nix create mode 100644 nixos/tests/watt.nix create mode 100644 pkgs/by-name/wa/watt/package.nix diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index 4f3ce80f917a..6b0d08604a41 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -16,6 +16,8 @@ - [Nezha](https://github.com/nezhahq/nezha), a self-hosted, lightweight server and website monitoring and O&M tool. Available as [services.nezha](#opt-services.nezha.enable). +- [Watt](https://github.com/NotAShelf/watt), a CPU frequency and power management daemon for Linux. Available as [services.watt](#opt-services.watt.enable). + - [mail-tlsa-check-exporter](https://github.com/ietf-tools/mail-tlsa-check-exporter), validates SMTP / IMAP server certificates against a TLSA record as a Prometheus exporter. Available as [services.prometheus.exporters.mail-tlsa-check](#opt-services.prometheus.exporters.mail-tlsa-check.enable). - [CastSponsorSkip](https://github.com/gabe565/CastSponsorSkip/), skips YouTube sponsorships (and sometimes ads) on all local Google Cast devices. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 0f420ffecbd3..b1ccf381f875 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -727,6 +727,7 @@ ./services/hardware/usbmuxd.nix ./services/hardware/usbrelayd.nix ./services/hardware/vdr.nix + ./services/hardware/watt.nix ./services/home-automation/deye-dummycloud.nix ./services/home-automation/ebusd.nix ./services/home-automation/esphome.nix diff --git a/nixos/modules/services/hardware/watt.nix b/nixos/modules/services/hardware/watt.nix new file mode 100644 index 000000000000..56b3d6f5036d --- /dev/null +++ b/nixos/modules/services/hardware/watt.nix @@ -0,0 +1,71 @@ +{ + config, + pkgs, + lib, + ... +}: +let + inherit (lib) + mkIf + mkOption + mkEnableOption + mkPackageOption + getExe + ; + inherit (lib.types) submodule; + + cfg = config.services.watt; + + format = pkgs.formats.toml { }; + cfgFile = format.generate "watt-config.toml" cfg.settings; + + conflictingServices = [ + "power-profiles-daemon" + "auto-cpufreq" + "tlp" + "cpupower-gui" + "thermald" + ]; + +in +{ + options.services.watt = { + enable = mkEnableOption "automatic CPU speed & power optimizer for Linux"; + package = mkPackageOption pkgs "watt" { }; + + settings = mkOption { + default = { }; + type = submodule { freeformType = format.type; }; + description = "Configuration for Watt. Options at https://github.com/notaShelf/watt"; + }; + }; + + config = mkIf cfg.enable { + assertions = map (service: { + assertion = !config.services.${service}.enable; + message = "You have set services.${service}.enable = true; which conflicts with Watt."; + }) conflictingServices; + + environment.systemPackages = [ cfg.package ]; + + # This is necessary for the Watt CLI. The environment variable + # passed to the systemd service will take priority in read order. + environment.etc."watt.toml".source = cfgFile; + + services.dbus.packages = [ cfg.package ]; + + systemd.services.watt = { + wantedBy = [ "multi-user.target" ]; + conflicts = map (service: "${service}.service") conflictingServices; + serviceConfig = { + WorkingDirectory = ""; + ExecStart = getExe cfg.package; + Restart = "on-failure"; + + RuntimeDirectory = "watt"; + RuntimeDirectoryMode = "0755"; + }; + }; + + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 09b0a4632d28..9f43f9bb6c14 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1825,6 +1825,7 @@ in wasabibackend = runTest ./wasabibackend.nix; wastebin = runTest ./wastebin.nix; watchdogd = runTest ./watchdogd.nix; + watt = runTest ./watt.nix; webhook = runTest ./webhook.nix; weblate = runTest ./web-apps/weblate.nix; wg-access-server = runTest ./wg-access-server.nix; diff --git a/nixos/tests/watt.nix b/nixos/tests/watt.nix new file mode 100644 index 000000000000..b06661b4b79f --- /dev/null +++ b/nixos/tests/watt.nix @@ -0,0 +1,19 @@ +{ pkgs, lib, ... }: +{ + name = "watt"; + meta.maintainers = with lib.maintainers; [ Soliprem ]; + + nodes.machine = _: { + services.watt.enable = true; + }; + + testScript = '' + machine.wait_for_unit("watt.service") + machine.succeed("watt --version | grep ${pkgs.watt.version}") + machine.wait_until_succeeds("busctl --system status net.hadess.PowerProfiles") + machine.wait_until_succeeds("busctl --system status dev.notashelf.Watt") + machine.succeed("busctl --system introspect net.hadess.PowerProfiles /net/hadess/PowerProfiles net.hadess.PowerProfiles") + machine.succeed("busctl --system introspect dev.notashelf.Watt /dev/notashelf/Watt dev.notashelf.Watt") + machine.succeed("busctl --system get-property dev.notashelf.Watt /dev/notashelf/Watt dev.notashelf.Watt Version | grep ${pkgs.watt.version}") + ''; +} diff --git a/pkgs/by-name/wa/watt/package.nix b/pkgs/by-name/wa/watt/package.nix new file mode 100644 index 000000000000..0181a43cb306 --- /dev/null +++ b/pkgs/by-name/wa/watt/package.nix @@ -0,0 +1,64 @@ +{ + lib, + stdenv, + rustPlatform, + fetchFromGitHub, + versionCheckHook, + nixosTests, + nix-update-script, +}: +rustPlatform.buildRustPackage (finalAttrs: { + pname = "watt"; + version = "1.2.0"; + __structuredAttrs = true; + + src = fetchFromGitHub { + owner = "notashelf"; + repo = "watt"; + tag = "v${finalAttrs.version}"; + hash = "sha256-mb7z1NHhS5DtFNzi/H/XQR5RfhYY5ELxJg8DFMWtzmU="; + }; + cargoHash = "sha256-2eHr88gMfiwimpcPa/ZQ08C2YalO91fH6BSvcyLNcso="; + + cargoBuildFlags = [ + "-p=watt" + "-p=xtask" + ]; + + enableParallelBuilding = true; + useNextest = true; + + nativeInstallCheckInputs = [ versionCheckHook ]; + doInstallCheck = true; + + # xtask doesn't support passing --target + # but nix hooks expect the folder structure from when it's set + env.CARGO_BUILD_TARGET = stdenv.hostPlatform.rust.cargoShortTarget; + + postInstall = + lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) '' + # Install required files with the 'dist' task + $out/bin/xtask dist --completions-dir $out/share/completions + '' + + '' + # Avoid populating PATH with an 'xtask' cmd + rm $out/bin/xtask + + install -Dm644 dbus/net.hadess.PowerProfiles.conf \ + $out/share/dbus-1/system.d/net.hadess.PowerProfiles.conf + ''; + + passthru = { + tests.nixos = nixosTests.watt; + updateScript = nix-update-script { }; + }; + + meta = { + description = "Modern CPU frequency and power management utility for Linux"; + homepage = "https://github.com/NotAShelf/watt"; + license = lib.licenses.mpl20; + maintainers = with lib.maintainers; [ Soliprem ]; + mainProgram = "watt"; + platforms = lib.platforms.linux; + }; +})