From 43b1db710b28935597507cf94e57c35efe261e9a Mon Sep 17 00:00:00 2001 From: Svenum Date: Sun, 13 Jul 2025 18:22:30 +0200 Subject: [PATCH 1/2] fw-fanctrl: init at 1.0.3 --- pkgs/by-name/fw/fw-fanctrl/package.nix | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 pkgs/by-name/fw/fw-fanctrl/package.nix diff --git a/pkgs/by-name/fw/fw-fanctrl/package.nix b/pkgs/by-name/fw/fw-fanctrl/package.nix new file mode 100644 index 000000000000..172d67e7ad02 --- /dev/null +++ b/pkgs/by-name/fw/fw-fanctrl/package.nix @@ -0,0 +1,43 @@ +{ + lib, + python3Packages, + fw-ectool, + fetchFromGitHub, +}: + +python3Packages.buildPythonPackage rec { + pname = "fw-fanctrl"; + version = "1.0.3"; + pyproject = true; + + src = fetchFromGitHub { + owner = "TamtamHero"; + repo = "fw-fanctrl"; + tag = "v${version}"; + hash = "sha256-TDVULNb/oH66/UX20mC89NSx8YPe8mPwNCB9+phavP4="; + }; + + build-system = [ python3Packages.setuptools ]; + + dependencies = [ python3Packages.jsonschema ]; + + makeWrapperArgs = [ "--prefix PATH : ${lib.makeBinPath [ fw-ectool ]}" ]; + + postInstall = '' + mkdir -p $out/share/fw-fanctrl + install -m 644 $src/src/fw_fanctrl/_resources/config.json $out/share/fw-fanctrl/config.json + install -m 755 $src/services/system-sleep/fw-fanctrl-suspend $out/share/fw-fanctrl/fw-fanctrl-suspend + patchShebangs --build $out/share/fw-fanctrl/fw-fanctrl-suspend + substituteInPlace $out/share/fw-fanctrl/fw-fanctrl-suspend \ + --replace-fail '"%PYTHON_SCRIPT_INSTALLATION_PATH%"' $out/bin/fw-fanctrl + ''; + + meta = { + mainProgram = "fw-fanctrl"; + homepage = "https://github.com/TamtamHero/fw-fanctrl"; + description = "Simple systemd service to better control Framework Laptop's fan(s)"; + platforms = lib.platforms.linux; + license = lib.licenses.bsd3; + maintainers = [ lib.maintainers.Svenum ]; + }; +} From cfe95170f10473a188f4126e684d7c9408256e48 Mon Sep 17 00:00:00 2001 From: Svenum Date: Sun, 13 Jul 2025 18:22:47 +0200 Subject: [PATCH 2/2] nixos/fw-fanctrl: init --- .../manual/release-notes/rl-2511.section.md | 2 + nixos/modules/hardware/fw-fanctrl.nix | 129 ++++++++++++++++++ nixos/modules/module-list.nix | 1 + 3 files changed, 132 insertions(+) create mode 100644 nixos/modules/hardware/fw-fanctrl.nix diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index 171ea46102af..b91c05d3077f 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -56,6 +56,8 @@ - [Sharkey](https://joinsharkey.org), a Sharkish microblogging platform. Available as [services.sharkey](#opt-services.sharkey.enable). +- [fw-fanctrl](https://github.com/TamtamHero/fw-fanctrl), a simple systemd service to better control Framework Laptop's fan(s). Available as [hardware.fw-fanctrl](#opt-hardware.fw-fanctrl.enable). + - [mautrix-discord](https://github.com/mautrix/discord), a Matrix-Discord puppeting/relay bridge. Available as [services.mautrix-discord](#opt-services.mautrix-discord.enable). - [SuiteNumérique Meet](https://github.com/suitenumerique/meet) is an open source alternative to Google Meet and Zoom powered by LiveKit: HD video calls, screen sharing, and chat features. Built with Django and React. Available as [services.lasuite-meet](#opt-services.lasuite-meet.enable). diff --git a/nixos/modules/hardware/fw-fanctrl.nix b/nixos/modules/hardware/fw-fanctrl.nix new file mode 100644 index 000000000000..27ab50be3179 --- /dev/null +++ b/nixos/modules/hardware/fw-fanctrl.nix @@ -0,0 +1,129 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.hardware.fw-fanctrl; + + configFormat = pkgs.formats.json { }; + configOption = configFormat.generate "config.json" cfg.config; + + configFile = pkgs.runCommand "configFile" { } '' + ${lib.getExe pkgs.jq} -s '.[0] * .[1]' ${pkgs.fw-fanctrl}/share/fw-fanctrl/config.json ${configOption} > $out + ''; +in +{ + options.hardware.fw-fanctrl = { + enable = lib.mkEnableOption "the fw-fanctrl systemd service and install the needed packages"; + + disableBatteryTempCheck = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Disable checking battery temperature sensor + ''; + }; + + config = lib.mkOption { + default = { }; + description = '' + Additional config entries for the fw-fanctrl service (documentation: https://github.com/TamtamHero/fw-fanctrl/blob/main/doc/configuration.md) + ''; + type = lib.types.submodule { + freeformType = configFormat.type; + options = { + defaultStrategy = lib.mkOption { + type = lib.types.str; + default = "lazy"; + description = "Default strategy to use"; + }; + + strategyOnDischarging = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Default strategy on discharging"; + }; + + strategies = lib.mkOption { + default = null; + description = '' + Additional strategies which can be used by fw-fanctrl + ''; + type = lib.types.nullOr ( + lib.types.attrsOf ( + lib.types.submodule { + options = { + fanSpeedUpdateFrequency = lib.mkOption { + type = lib.types.ints.unsigned; + default = 5; + description = "How often the fan speed should be updated in seconds"; + }; + + movingAverageInterval = lib.mkOption { + type = lib.types.ints.unsigned; + default = 25; + description = "Interval (seconds) of the last temperatures to use to calculate the average temperature"; + }; + + speedCurve = lib.mkOption { + default = [ ]; + description = "How should the speed curve look like"; + type = lib.types.listOf ( + lib.types.submodule { + options = { + temp = lib.mkOption { + type = lib.types.int; + default = 0; + description = "Temperature in °C at which the fan speed should be changed"; + }; + + speed = lib.mkOption { + type = lib.types.ints.between 0 100; + default = 0; + description = "Percent how fast the fan should run at"; + }; + + }; + } + ); + }; + }; + } + ) + ); + }; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + fw-fanctrl + fw-ectool + ]; + + systemd.services.fw-fanctrl = { + description = "Framework Fan Controller"; + after = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = "${lib.getExe pkgs.fw-fanctrl} --output-format JSON run --config ${configFile} --silent ${lib.optionalString cfg.disableBatteryTempCheck "--no-battery-sensors"}"; + ExecStopPost = "${lib.getExe pkgs.fw-ectool} autofanctrl"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + # Create suspend config + environment.etc."systemd/system-sleep/fw-fanctrl-suspend.sh".source = + "${pkgs.fw-fanctrl}/share/fw-fanctrl/fw-fanctrl-suspend"; + }; + + meta = { + maintainers = pkgs.fw-fanctrl.meta.maintainers; + }; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index d0831c02e6d7..881050ef83dd 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -67,6 +67,7 @@ ./hardware/digitalbitbox.nix ./hardware/flipperzero.nix ./hardware/flirc.nix + ./hardware/fw-fanctrl.nix ./hardware/glasgow.nix ./hardware/gpgsmartcards.nix ./hardware/graphics.nix