From f7afb4937852980770267c6a73275fbe2007bd4a Mon Sep 17 00:00:00 2001 From: Svenum <43136984+Svenum@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:32:35 +0200 Subject: [PATCH 1/4] Add NixOS Flake (#26) * initial * update gitignore * update inputs * add fw-ectool dependencie * add module * fix tabs * fix package * fix typo * fix service * fix type * add options * fix service * fix build inputs * add Readme + add suspend script * remove unneeded }; * fix pkgs.writeShellScript * remvoe \ * try * add self * fix module * update package * fix package * use sleep script * add config options * fix typo * fix typo * add defaults * fix type * add prettyier * remove beautifyer * udpate readme * update installer script * add missing path * Update README.md Co-authored-by: Thomas Eizinger * Update flake.nix Co-authored-by: Thomas Eizinger * Update nix/module.nix Co-authored-by: Thomas Eizinger * add descriptions * fix uninstall * update readme * add description * remove requiremetns.txt + add github actions * update action * rename workflow test * fix service * try * try * Update README.md * Update README.md * chagne flake description * fix suspend script * fix script * fix path * fix install.sh * fix --no-sudo * add --no-sudo to other scripts * fix check * add option check * add missing " * Rename nix action --------- Co-authored-by: Thomas Eizinger --- .github/workflows/nix-build.yml | 14 ++++ .gitignore | 4 +- README.md | 92 ++++++++++++++----------- flake.lock | 44 ++++++++++++ flake.nix | 29 ++++++++ install.sh | 23 ++++--- nix/module.nix | 118 ++++++++++++++++++++++++++++++++ nix/packages/fw-ectool.nix | 43 ++++++++++++ nix/packages/fw-fanctrl.nix | 72 +++++++++++++++++++ post-install.sh | 20 +++--- pre-uninstall.sh | 21 +++--- 11 files changed, 415 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/nix-build.yml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/module.nix create mode 100644 nix/packages/fw-ectool.nix create mode 100644 nix/packages/fw-fanctrl.nix diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml new file mode 100644 index 0000000..27a5605 --- /dev/null +++ b/.github/workflows/nix-build.yml @@ -0,0 +1,14 @@ +name: "Nix packaging test" +on: + pull_request: + +jobs: + Build-Package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-unstable + - run: nix build + diff --git a/.gitignore b/.gitignore index 90e78cf..5847f2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Nix Build dir +/result + ### Intellij template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 @@ -343,4 +346,3 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser - diff --git a/README.md b/README.md index bdf383e..09ae03a 100644 --- a/README.md +++ b/README.md @@ -8,51 +8,65 @@ Under the hood, it uses [ectool](https://gitlab.howett.net/DHowett/ectool) to ch It is compatible with all kinds of 13" and 16" models, both AMD/Intel CPUs and with or without discrete GPU. # Install - -## Dependancies - -To communicate with the embedded controller the `ectool` is required. -You can either use the precompiled executable of `ectool` in this repo or -disable its installation (`--no-ectool`) and add your own by recompiling it from [this repo](https://gitlab.howett.net/DHowett/ectool) and putting it in `[dest-dir(/)]/bin`. - -You also need to disable secure boot of your device for `ectool` to work (more details about why [here](https://www.howett.net/posts/2021-12-framework-ec/#using-fw-ectool)) - -Then run: +For NixOS this repo contains an Flake. You could add it to your config like this: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + fw-fanctrl = { + url = "github:TamtamHero/fw-fanctrl/packaging/nix; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + outputs = {nixpkgs, fw-fanctrl}: { + nixosConfigurations.foo = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + fw-fanctrl.nixosModules.default + configuration.nix + ]; + }; + } +} ``` -sudo ./install.sh +and then add in your *configuration.nix*: +```nix +# Enable fw-fanctrl +programs.fw-fanctrl.enable = true; + +# Add a custom config +programs.fw-fanctrl.config = { + defaultStrategy = "lazy"; + strategies = { + "lazy" = { + fanSpeedUpdateFrequency = 5; + movingAverageInterval = 30; + speedCurve = [ + { temp = 0; speed = 15; } + { temp = 50; speed = 15; } + { temp = 65; speed = 25; } + { temp = 70; speed = 35; } + { temp = 75; speed = 50; } + { temp = 85; speed = 100; } + ]; + }; + }; +}; + +# Add a custom config from an existing JSON file +programs.fw-fanctrl.config = builtins.fromJSON (builtins.readFile ./config.json) + +# Or just change the default strategy form the default config +programs.fw-fanctrl.config.defaultStrategy = "medium"; ``` -This bash script will to create and activate a service that runs this repo's main script, `fanctrl.py`. -It will copy `fanctrl.py` (to an executable file `fw-fanctrl`) and `./bin/ectool` to `[dest-dir(/)]/bin` and create a config file -in `[dest-dir(/)][sysconf-dir(/etc)]/fw-fanctrl/config.json` +Non NixOS install is described [here](https://github.com/TamtamHero/fw-fanctrl/blob/main/README.md#Install) -this script also includes options to: -- specify an installation destination directory (`--dest-dir `). -- specify an installation prefix directory (`--prefix-dir `). -- specify a default configuration directory (`--sysconf-dir `). -- disable ectool installation and service activation (`--no-ectool`) -- disable post-install process (`--no-post-install`) -- disable pre-uninstall process (`--no-pre-uninstall`) - -# Update - -To install an update, you can pull the latest commit on the `main` branch of this repository, and run the install script again. - -# Uninstall -``` -sudo ./install.sh --remove -``` # Configuration -There is a single `config.json` file located at `[dest-dir(/)][sysconf-dir(/etc)]/fw-fanctrl/config.json`. - -(You will need to reload the configuration with) -``` -fw-fanctrl --reload -``` - -It contains different strategies, ranked from the most silent to the noisiest. It is possible to specify two different strategies for charging/discharging allowing for different optimization goals. +The default config contains different strategies, ranked from the most silent to the noisiest. It is possible to specify two different strategies for charging/discharging allowing for different optimization goals. On discharging one could have fan curve optimized for low fan speeds in order to save power while accepting a bit more heat. On charging one could have a fan curve that focuses on keeping the CPU from throttling and the system cool, at the expense of fan noise. You can add new strategies, and if you think you have one that deserves to be shared, feel free to make a PR to this repo :) @@ -61,7 +75,7 @@ Strategies can be configured with the following parameters: - **SpeedCurve**: - This is the curve points for `f(temperature) = fan speed` + This is the curve points for `f(temperature) = fan speeds` `fw-fanctrl` measures the CPU temperature, compute a moving average of it, and then find an appropriate `fan speed` value by interpolation on the curve. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8de5f21 --- /dev/null +++ b/flake.lock @@ -0,0 +1,44 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1713564160, + "narHash": "sha256-YguPZpiejgzLEcO36/SZULjJQ55iWcjAmf3lYiyV1Fo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bc194f70731cc5d2b046a6c1b3b15f170f05999c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1c8816a --- /dev/null +++ b/flake.nix @@ -0,0 +1,29 @@ +{ + description = "A simple systemd service to better control Framework Laptop's fan(s)"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + }; + + outputs = { self, nixpkgs, flake-compat }: { + packages.x86_64-linux.default = self.packages.x86_64-linux.fw-fanctrl; + packages.x86_64-linux.fw-fanctrl = ( + import nixpkgs { + currentSystem = "x86_64-linux"; + localSystem = "x86_64-linux"; + }).pkgs.callPackage ./nix/packages/fw-fanctrl.nix {}; + + packages.x86_64-linux.fw-ectool = ( + import nixpkgs { + currentSystem = "x86_64-linux"; + localSystem = "x86_64-linux"; + }).pkgs.callPackage ./nix/packages/fw-ectool.nix {}; + + nixosModules.default = import ./nix/module.nix; + }; +} diff --git a/install.sh b/install.sh index 03cf29d..4aced48 100755 --- a/install.sh +++ b/install.sh @@ -1,14 +1,10 @@ #!/bin/bash set -e -if [ "$EUID" -ne 0 ] - then echo "This program requires root permissions" - exit 1 -fi # Argument parsing SHORT=r,d:,p:,s:,h -LONG=remove,dest-dir:,prefix-dir:,sysconf-dir:,no-ectool,no-pre-uninstall,no-post-install,help +LONG=remove,dest-dir:,prefix-dir:,sysconf-dir:,no-ectool,no-pre-uninstall,no-post-install,no-sudo,help VALID_ARGS=$(getopt -a --options $SHORT --longoptions $LONG -- "$@") if [[ $? -ne 0 ]]; then exit 1; @@ -21,6 +17,7 @@ SHOULD_INSTALL_ECTOOL=true SHOULD_PRE_UNINSTALL=true SHOULD_POST_INSTALL=true SHOULD_REMOVE=false +NO_SUDO=false eval set -- "$VALID_ARGS" while true; do @@ -49,8 +46,11 @@ while true; do '--no-post-install') SHOULD_POST_INSTALL=false ;; + '--no-sudo') + NO_SUDO=true + ;; '--help' | '-h') - echo "Usage: $0 [--remove,-r] [--dest-dir,-d ] [--prefix-dir,-p ] [--sysconf-dir,-s system configuration destination directory (defaults to $SYSCONF_DIR)] [--no-ectool] [--no-post-install] [--no-pre-uninstall]" 1>&2 + echo "Usage: $0 [--remove,-r] [--dest-dir,-d ] [--prefix-dir,-p ] [--sysconf-dir,-s system configuration destination directory (defaults to $SYSCONF_DIR)] [--no-ectool] [--no-post-install] [--no-pre-uninstall] [--no-sudo]" 1>&2 exit 0 ;; --) @@ -59,7 +59,12 @@ while true; do esac shift done -# + +# Root check +if [ "$EUID" -ne 0 ] && [ "$NO_SUDO" = false ] + then echo "This program requires root permissions" + exit 1 +fi SERVICES_DIR="./services" SERVICE_EXTENSION=".service" @@ -86,7 +91,7 @@ function uninstall_legacy() { function uninstall() { if [ "$SHOULD_PRE_UNINSTALL" = true ]; then - ./pre-uninstall.sh + ./pre-uninstall.sh "$([ "$NO_SUDO" = true ] && echo "--no-sudo")" fi # remove program services based on the services present in the './services' folder echo "removing services" @@ -171,7 +176,7 @@ function install() { done done if [ "$SHOULD_POST_INSTALL" = true ]; then - ./post-install.sh --dest-dir "$DEST_DIR" --sysconf-dir "$SYSCONF_DIR" + ./post-install.sh --dest-dir "$DEST_DIR" --sysconf-dir "$SYSCONF_DIR" "$([ "$NO_SUDO" = true ] && echo "--no-sudo")" fi } diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 0000000..7aa53c9 --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,118 @@ +{ options, config, lib, pkgs, stdenv, ... }: + +with lib; +with lib.types; +let + cfg = config.programs.fw-fanctrl; + fw-ectool = pkgs.callPackage ./packages/fw-ectool.nix {}; + fw-fanctrl = pkgs.callPackage ./packages/fw-fanctrl.nix {}; + defaultConfig = builtins.fromJSON (builtins.readFile ../config.json); +in +{ + options.programs.fw-fanctrl = { + enable = mkOption { + type = bool; + default = false; + description = '' + Enable fw-fanctrl systemd service and install the needed packages. + ''; + }; + config = { + defaultStrategy = mkOption { + type = str; + default = defaultConfig.defaultStrategy; + description = "Default strategy to use"; + }; + strategyOnDischarging = mkOption { + type = str; + default = defaultConfig.strategyOnDischarging; + description = "Default strategy on discharging"; + }; + batteryChargingStatusPath = mkOption { + type = str; + default = "/sys/class/power_supply/BAT1/status"; + description = ""; + }; + strategies = mkOption { + default = defaultConfig.strategies; + type = attrsOf (submodule ( + { options, name, ... }: + { + options = { + name = mkOption { + type = str; + default = ""; + description = "Name of the strategy"; + }; + fanSpeedUpdateFrequency = mkOption { + type = int; + default = 5; + description = "How often the fan speed should be updated in seconds"; + }; + movingAverageInterval = mkOption { + type = int; + default = 25; + description = "Interval (seconds) of the last temperatures to use to calculate the average temperature"; + }; + speedCurve = mkOption { + default = []; + description = "How should the speed curve look like"; + type = listOf (submodule ( + { options, ... }: + { + options = { + temp = mkOption { + type = int; + default = 0; + description = "Temperature at which the fan speed should be changed"; + }; + speed = mkOption { + type = int; + default = 0; + description = "Percent how fast the fan should run at"; + }; + }; + } + )); + }; + }; + } + )); + }; + }; + }; + + config = mkIf cfg.enable { + # Install package + environment.systemPackages = [ + fw-fanctrl + fw-ectool + ]; + + # Create config + environment.etc."fw-fanctrl/config.json" = { + text = builtins.toJSON cfg.config; + }; + + # Create Service + systemd.services.fw-fanctrl = { + description = "Framework Fan Controller"; + after = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = "${fw-fanctrl}/bin/fw-fanctrl --run --config /etc/fw-fanctrl/config.json --no-log"; + ExecStopPost = "${fw-ectool}/bin/ectool autofanctrl"; + }; + enable = true; + wantedBy = [ "multi-user.target" ]; + }; + + # Create suspend config + environment.etc."systemd/system-sleep/fw-fanctrl-suspend.sh".source = pkgs.writeShellScript "fw-fanctrl-suspend" ( + builtins.replaceStrings [ ''/usr/bin/python3 "%PREFIX_DIRECTORY%/bin/fw-fanctrl"'' "/bin/bash" ] [ "${fw-fanctrl}/bin/fw-fanctrl" "" ] ( + builtins.readFile ../services/system-sleep/fw-fanctrl-suspend + ) + ); + }; +} diff --git a/nix/packages/fw-ectool.nix b/nix/packages/fw-ectool.nix new file mode 100644 index 0000000..1900116 --- /dev/null +++ b/nix/packages/fw-ectool.nix @@ -0,0 +1,43 @@ +{ + stdenv, + lib, + autoPatchelfHook, + libusb1, + libftdi1 +}: + +stdenv.mkDerivation { + version = "20-04-2024"; + name = "fw-ectool"; + src = ../../.; + + outputs = [ "out" ]; + + nativeBuildInputs = [ + autoPatchelfHook + ]; + + propagatedBuildInputs = [ + libusb1 + libftdi1 + ]; + + installPhase = '' + mkdir -p $out/bin + runHook preInstall + install -m755 ./bin/ectool $out/bin/ectool + ln -s $out/bin/ectool $out/bin/fw-ectool + chmod -R 755 $out/bin/* + ''; + + doCheck = false; + + meta = with lib; { + mainProgram = "ectool"; + homepage = "https://github.com/TamtamHero/fw-fanctrl"; + description = "fw-ectool customized for fw-fanctrl"; + platforms = with platforms; linux; + license = licenses.bsd3; + maintainers = with maintainers; [ "Svenum" ]; + }; +} diff --git a/nix/packages/fw-fanctrl.nix b/nix/packages/fw-fanctrl.nix new file mode 100644 index 0000000..0e207fa --- /dev/null +++ b/nix/packages/fw-fanctrl.nix @@ -0,0 +1,72 @@ +{ +lib, +python3Packages, +python3, +bash, +callPackage, +getopt +}: + +let + pversion = "20-04-2024"; + description = "A simple systemd service to better control Framework Laptop's fan(s)"; + url = "https://github.com/TamtamHero/fw-fanctrl"; +in +python3Packages.buildPythonPackage rec{ + pname = "fw-fanctrl"; + version = pversion; + + src = ../../.; + + outputs = [ "out" ]; + + preBuild = '' + cat > setup.py << EOF + from setuptools import setup + + setup( + name="fw-fanctrl", + description="${description}", + url="${url}", + platforms=["linux"], + py_modules=[], + + scripts=[ + "fanctrl.py", + ], + ) + EOF + ''; + + nativeBuildInputs = [ + python3 + getopt + bash + ]; + + propagatedBuildInputs = [ + (callPackage ./fw-ectool.nix {}) + ]; + + doCheck = false; + + postPatch = '' + patchShebangs --build fanctrl.py + patchShebangs --build install.sh + ''; + + installPhase = '' + ./install.sh --dest-dir $out --prefix-dir "" --no-ectool --no-post-install --no-sudo + rm -rf $out/etc + rm -rf $out/lib + ''; + + meta = with lib; { + mainProgram = "fw-fanctrl"; + homepage = url; + description = description; + platforms = with platforms; linux; + license = licenses.bsd3; + maintainers = with maintainers; [ "Svenum" ]; + }; +} diff --git a/post-install.sh b/post-install.sh index c92e74a..f3108db 100755 --- a/post-install.sh +++ b/post-install.sh @@ -1,16 +1,12 @@ #!/bin/bash set -e -if [ "$EUID" -ne 0 ] - then echo "This program requires root permissions" - exit 1 -fi - HOME_DIR="$(eval echo "~$(logname)")" # Argument parsing +NO_SUDO=false SHORT=d:,s:,h -LONG=dest-dir:,sysconf-dir:,help +LONG=dest-dir:,sysconf-dir:,no-sudo,help VALID_ARGS=$(getopt -a --options $SHORT --longoptions $LONG -- "$@") if [[ $? -ne 0 ]]; then exit 1; @@ -30,8 +26,11 @@ while true; do SYSCONF_DIR=$2 shift ;; + '--no-sudo') + NO_SUDO=true + ;; '--help' | '-h') - echo "Usage: $0 [--dest-dir,-d ] [--sysconf-dir,-s system configuration destination directory (defaults to $SYSCONF_DIR)]" 1>&2 + echo "Usage: $0 [--dest-dir,-d ] [--sysconf-dir,-s system configuration destination directory (defaults to $SYSCONF_DIR)] [--no-sudo]" 1>&2 exit 0 ;; --) @@ -40,7 +39,12 @@ while true; do esac shift done -# + +# Root check +if [ "$EUID" -ne 0 ] && [ "$NO_SUDO" = false ] + then echo "This program requires root permissions" + exit 1 +fi SERVICES_DIR="./services" SERVICE_EXTENSION=".service" diff --git a/pre-uninstall.sh b/pre-uninstall.sh index 9ca3953..ad21f5d 100755 --- a/pre-uninstall.sh +++ b/pre-uninstall.sh @@ -1,16 +1,12 @@ #!/bin/bash set -e -if [ "$EUID" -ne 0 ] - then echo "This program requires root permissions" - exit 1 -fi - HOME_DIR="$(eval echo "~$(logname)")" # Argument parsing +NO_SUDO=false SHORT=h -LONG=help +LONG=no-sudo,help VALID_ARGS=$(getopt -a --options $SHORT --longoptions $LONG -- "$@") if [[ $? -ne 0 ]]; then exit 1; @@ -19,8 +15,11 @@ fi eval set -- "$VALID_ARGS" while true; do case "$1" in + '--no-sudo') + NO_SUDO=true + ;; '--help' | '-h') - echo "Usage: $0" 1>&2 + echo "Usage: $0 [--no-sudo]" 1>&2 exit 0 ;; --) @@ -29,7 +28,13 @@ while true; do esac shift done -# + +# Root check +if [ "$EUID" -ne 0 ] && [ "$NO_SUDO" = false ] + then echo "This program requires root permissions" + exit 1 +fi + SERVICES_DIR="./services" SERVICE_EXTENSION=".service" From d6d384b919282f6876e630926d552156c0a522ae Mon Sep 17 00:00:00 2001 From: Philip Nelson Date: Tue, 18 Jun 2024 02:45:10 -0400 Subject: [PATCH 2/4] Update README.md (#49) added closing double quote on line 18. will prevent users from encountering an error when copy/pasting. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09ae03a..03d29bd 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ For NixOS this repo contains an Flake. You could add it to your config like this inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix; + url = "github:TamtamHero/fw-fanctrl/packaging/nix"; inputs.nixpkgs.follows = "nixpkgs"; }; }; From c51335beb9ccbe19b2eeb37b01da214c523d1885 Mon Sep 17 00:00:00 2001 From: Svenum <43136984+Svenum@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:16:38 +0200 Subject: [PATCH 3/4] Update branch to main branch (#54) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding @Svenum as an assignee to nix-related issues (#43) * Fixing adding @Svenum as an assignee to nix-related issues (#44) (non contributors cannot be assigned to issues) * Reload will report if config couldn't be parsed and the service keeps running. (#46) Authored-by: Nina Alexandra Klama * Removing binary blobs from the project (#51) * removing binary blobs from the project. we now fetch the ectool from the gitlab artifacts and confirm the checksum. * remove bin references from README.md * extracting $TEMP_FOLDER from installEctool * Fix README spelling/grammer, fix "FrameWork" capitalization in service description (#52) * Review README spelling/grammar * Fix "FrameWork" capitalization in service * use ectool form nixpkgs * update flake * remove old deps * remove duplicated pkgs --------- Co-authored-by: Léopold Hubert Co-authored-by: Nina Alexandra Klama Co-authored-by: DeflateAwning <11021263+DeflateAwning@users.noreply.github.com> --- .../bug-report---packaging-nix.md | 3 ++ .gitignore | 2 + README.md | 8 ++-- bin/ectool | Bin 319120 -> 0 bytes fanctrl.py | 16 +++++-- {bin => fetch/ectool}/LICENSE | 0 fetch/ectool/linux/gitlab_job_id | 1 + fetch/ectool/linux/hash.sha256 | 1 + flake.lock | 6 +-- flake.nix | 6 --- install.sh | 42 ++++++++++++++++- nix/module.nix | 7 ++- nix/packages/fw-ectool.nix | 43 ------------------ nix/packages/fw-fanctrl.nix | 5 +- services/fw-fanctrl.service | 2 +- 15 files changed, 72 insertions(+), 70 deletions(-) delete mode 100755 bin/ectool rename {bin => fetch/ectool}/LICENSE (100%) create mode 100644 fetch/ectool/linux/gitlab_job_id create mode 100644 fetch/ectool/linux/hash.sha256 delete mode 100644 nix/packages/fw-ectool.nix diff --git a/.github/ISSUE_TEMPLATE/bug-report---packaging-nix.md b/.github/ISSUE_TEMPLATE/bug-report---packaging-nix.md index 39410ee..921bfdb 100644 --- a/.github/ISSUE_TEMPLATE/bug-report---packaging-nix.md +++ b/.github/ISSUE_TEMPLATE/bug-report---packaging-nix.md @@ -36,3 +36,6 @@ If applicable, add the full error message. **Additional context** Add any other context about the problem here. + +**Assigned maintainers** +- @Svenum diff --git a/.gitignore b/.gitignore index 5847f2c..7bb0dc6 100644 --- a/.gitignore +++ b/.gitignore @@ -346,3 +346,5 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser + +.temp diff --git a/README.md b/README.md index 03d29bd..26d2973 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ This is a simple Python service for Linux that drives Framework Laptop's fan(s) speed according to a configurable speed/temp curve. Its default configuration targets very silent fan operation, but it's easy to configure it for a different comfort/performance trade-off. Its possible to specify two separate fan curves depending on whether the Laptop is charging/discharging. -Under the hood, it uses [ectool](https://gitlab.howett.net/DHowett/ectool) to change parameters in FrameWork's embedded controller (EC). +Under the hood, it uses [ectool](https://gitlab.howett.net/DHowett/ectool) to change parameters in Framework's embedded controller (EC). -It is compatible with all kinds of 13" and 16" models, both AMD/Intel CPUs and with or without discrete GPU. +It is compatible with all kinds of 13" and 16" models, both AMD/Intel CPUs, with or without a discrete GPU. # Install For NixOS this repo contains an Flake. You could add it to your config like this: @@ -90,11 +90,11 @@ Strategies can be configured with the following parameters: ## Charging/Discharging strategies -The strategy active by default is the one specified in the `defaultStrategy` entry. Optionally a separate strategy only active during discharge can be defined, using the `strategyOnDischarging` entry. By default no extra strategy for discharging is provided, the default stratgy is active during all times. +The strategy active by default is the one specified in the `defaultStrategy` entry. Optionally a separate strategy only active during discharge can be defined, using the `strategyOnDischarging` entry. By default no extra strategy for discharging is provided, the default strategy is active during all times. # Commands -| option | contexte | description | +| Option | Context | Description | |-------------------|-----------------|---------------------------------| | \ | run & configure | the name of the strategy to use | | --run | run | run the service | diff --git a/bin/ectool b/bin/ectool deleted file mode 100755 index fb967e3ab2ac30ff24f97d9e2ecf9c01a5fdf621..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319120 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

O$wh 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 diff --git a/fanctrl.py b/fanctrl.py index 24ad2ae..b605378 100644 --- a/fanctrl.py +++ b/fanctrl.py @@ -49,7 +49,11 @@ def __init__(self, path): def reload(self): with open(self.path, "r") as fp: - self.data = json.load(fp) + try: + self.data = json.load(fp) + except json.JSONDecodeError: + return False + return True def getStrategies(self): return self.data["strategies"].keys() @@ -161,10 +165,12 @@ def bindSocket(self): if args.list_strategies: client_socket.sendall('\n'.join(self.configuration.getStrategies()).encode()) if args.reload: - self.configuration.reload() - if self.overwrittenStrategy is not None: - self.overwriteStrategy(self.overwrittenStrategy.name) - client_socket.sendall("Success".encode()) + if self.configuration.reload(): + if self.overwrittenStrategy is not None: + self.overwriteStrategy(self.overwrittenStrategy.name) + client_socket.sendall("Success".encode()) + else: + client_socket.sendall("Error: Config file could not be parsed due to JSON Error".encode()) except: pass finally: diff --git a/bin/LICENSE b/fetch/ectool/LICENSE similarity index 100% rename from bin/LICENSE rename to fetch/ectool/LICENSE diff --git a/fetch/ectool/linux/gitlab_job_id b/fetch/ectool/linux/gitlab_job_id new file mode 100644 index 0000000..2a0f68f --- /dev/null +++ b/fetch/ectool/linux/gitlab_job_id @@ -0,0 +1 @@ +899 \ No newline at end of file diff --git a/fetch/ectool/linux/hash.sha256 b/fetch/ectool/linux/hash.sha256 new file mode 100644 index 0000000..a926f8b --- /dev/null +++ b/fetch/ectool/linux/hash.sha256 @@ -0,0 +1 @@ +ab94a1e9a33f592d5482dbfd4f42ad351ef91227ee3b3707333c0107d7f2b1b0 \ No newline at end of file diff --git a/flake.lock b/flake.lock index 8de5f21..3f71c3e 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1713564160, - "narHash": "sha256-YguPZpiejgzLEcO36/SZULjJQ55iWcjAmf3lYiyV1Fo=", + "lastModified": 1719234068, + "narHash": "sha256-1AjSIedDC/aERt24KsCUftLpVppW61S7awfjGe7bMio=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc194f70731cc5d2b046a6c1b3b15f170f05999c", + "rev": "90bd1b26e23760742fdcb6152369919098f05417", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 1c8816a..4f319cf 100644 --- a/flake.nix +++ b/flake.nix @@ -18,12 +18,6 @@ localSystem = "x86_64-linux"; }).pkgs.callPackage ./nix/packages/fw-fanctrl.nix {}; - packages.x86_64-linux.fw-ectool = ( - import nixpkgs { - currentSystem = "x86_64-linux"; - localSystem = "x86_64-linux"; - }).pkgs.callPackage ./nix/packages/fw-ectool.nix {}; - nixosModules.default = import ./nix/module.nix; }; } diff --git a/install.sh b/install.sh index 4aced48..b437bbb 100755 --- a/install.sh +++ b/install.sh @@ -10,6 +10,9 @@ if [[ $? -ne 0 ]]; then exit 1; fi +TEMP_FOLDER='./.temp' +trap 'rm -rf $TEMP_FOLDER' EXIT + PREFIX_DIR="/usr" DEST_DIR="" SYSCONF_DIR="/etc" @@ -128,10 +131,12 @@ function uninstall() { function install() { uninstall_legacy + rm -rf "$TEMP_FOLDER" mkdir -p "$DEST_DIR$PREFIX_DIR/bin" if [ "$SHOULD_INSTALL_ECTOOL" = true ]; then - cp "./bin/ectool" "$DEST_DIR$PREFIX_DIR/bin/ectool" - chmod +x "$DEST_DIR$PREFIX_DIR/bin/ectool" + mkdir "$TEMP_FOLDER" + installEctool "$TEMP_FOLDER" || (echo "an error occurred when installing ectool." && echo "please check your internet connection or consider installing it manually and using --no-ectool on the installation script." && exit 1) + rm -rf "$TEMP_FOLDER" fi mkdir -p "$DEST_DIR$SYSCONF_DIR/fw-fanctrl" cp "./fanctrl.py" "$DEST_DIR$PREFIX_DIR/bin/fw-fanctrl" @@ -180,6 +185,39 @@ function install() { fi } +function installEctool() { + workingDirectory=$1 + echo "installing ectool" + + ectoolDestPath="$DEST_DIR$PREFIX_DIR/bin/ectool" + + ectoolJobId="$(cat './fetch/ectool/linux/gitlab_job_id')" + ectoolSha256Hash="$(cat './fetch/ectool/linux/hash.sha256')" + + artifactsZipFile="$workingDirectory/artifact.zip" + + echo "downloading artifact from gitlab" + curl -s -S -o "$artifactsZipFile" -L "https://gitlab.howett.net/DHowett/ectool/-/jobs/${ectoolJobId}/artifacts/download?file_type=archive" || (echo "failed to download the artifact." && return 1) + if [[ $? -ne 0 ]]; then return 1; fi + + echo "checking artifact sha256 sum" + actualEctoolSha256Hash=$(sha256sum "$artifactsZipFile" | cut -d ' ' -f 1) + if [[ "$actualEctoolSha256Hash" != "$ectoolSha256Hash" ]]; then + echo "Incorrect sha256 sum for ectool gitlab artifact '$ectoolJobId' : '$ectoolSha256Hash' != '$actualEctoolSha256Hash'" + return 1 + fi + + echo "extracting artifact" + { + unzip -q -j "$artifactsZipFile" '_build/src/ectool' -d "$workingDirectory" && + cp "$workingDirectory/ectool" "$ectoolDestPath" && + chmod +x "$ectoolDestPath" + } || (echo "failed to extract the artifact to its designated location." && return 1) + if [[ $? -ne 0 ]]; then return 1; fi + + echo "ectool installed" +} + if [ "$SHOULD_REMOVE" = true ]; then uninstall else diff --git a/nix/module.nix b/nix/module.nix index 7aa53c9..9cd79ad 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -4,7 +4,6 @@ with lib; with lib.types; let cfg = config.programs.fw-fanctrl; - fw-ectool = pkgs.callPackage ./packages/fw-ectool.nix {}; fw-fanctrl = pkgs.callPackage ./packages/fw-fanctrl.nix {}; defaultConfig = builtins.fromJSON (builtins.readFile ../config.json); in @@ -84,9 +83,9 @@ in config = mkIf cfg.enable { # Install package - environment.systemPackages = [ + environment.systemPackages = with pkgs; [ fw-fanctrl - fw-ectool + ectool ]; # Create config @@ -102,7 +101,7 @@ in Type = "simple"; Restart = "always"; ExecStart = "${fw-fanctrl}/bin/fw-fanctrl --run --config /etc/fw-fanctrl/config.json --no-log"; - ExecStopPost = "${fw-ectool}/bin/ectool autofanctrl"; + ExecStopPost = "${pkgs.ectool}/bin/ectool autofanctrl"; }; enable = true; wantedBy = [ "multi-user.target" ]; diff --git a/nix/packages/fw-ectool.nix b/nix/packages/fw-ectool.nix deleted file mode 100644 index 1900116..0000000 --- a/nix/packages/fw-ectool.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ - stdenv, - lib, - autoPatchelfHook, - libusb1, - libftdi1 -}: - -stdenv.mkDerivation { - version = "20-04-2024"; - name = "fw-ectool"; - src = ../../.; - - outputs = [ "out" ]; - - nativeBuildInputs = [ - autoPatchelfHook - ]; - - propagatedBuildInputs = [ - libusb1 - libftdi1 - ]; - - installPhase = '' - mkdir -p $out/bin - runHook preInstall - install -m755 ./bin/ectool $out/bin/ectool - ln -s $out/bin/ectool $out/bin/fw-ectool - chmod -R 755 $out/bin/* - ''; - - doCheck = false; - - meta = with lib; { - mainProgram = "ectool"; - homepage = "https://github.com/TamtamHero/fw-fanctrl"; - description = "fw-ectool customized for fw-fanctrl"; - platforms = with platforms; linux; - license = licenses.bsd3; - maintainers = with maintainers; [ "Svenum" ]; - }; -} diff --git a/nix/packages/fw-fanctrl.nix b/nix/packages/fw-fanctrl.nix index 0e207fa..50df35c 100644 --- a/nix/packages/fw-fanctrl.nix +++ b/nix/packages/fw-fanctrl.nix @@ -4,7 +4,8 @@ python3Packages, python3, bash, callPackage, -getopt +getopt, +ectool }: let @@ -45,7 +46,7 @@ python3Packages.buildPythonPackage rec{ ]; propagatedBuildInputs = [ - (callPackage ./fw-ectool.nix {}) + ectool ]; doCheck = false; diff --git a/services/fw-fanctrl.service b/services/fw-fanctrl.service index 40ca920..7f70d58 100644 --- a/services/fw-fanctrl.service +++ b/services/fw-fanctrl.service @@ -1,5 +1,5 @@ [Unit] -Description=FrameWork Fan Controller +Description=Framework Fan Controller After=multi-user.target [Service] Type=simple From c79c43e566d46b1767fa5af95d36f5a7049b3818 Mon Sep 17 00:00:00 2001 From: Svenum <43136984+Svenum@users.noreply.github.com> Date: Sat, 3 Aug 2024 21:38:50 +0200 Subject: [PATCH 4/4] Update to main branch + switch to fw-ectool (#61) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding @Svenum as an assignee to nix-related issues (#43) * Fixing adding @Svenum as an assignee to nix-related issues (#44) (non contributors cannot be assigned to issues) * Reload will report if config couldn't be parsed and the service keeps running. (#46) Authored-by: Nina Alexandra Klama * Removing binary blobs from the project (#51) * removing binary blobs from the project. we now fetch the ectool from the gitlab artifacts and confirm the checksum. * remove bin references from README.md * extracting $TEMP_FOLDER from installEctool * Fix README spelling/grammer, fix "FrameWork" capitalization in service description (#52) * Review README spelling/grammar * Fix "FrameWork" capitalization in service * Clarify behaviour on service stop or pause (#53) (#55) * Separating FanController into different subclasses to allow HardwareController and SocketController diversity. 2 (Repost of #50) (#58) * separating `FanController` into different subclasses to allow `HardwareController` and `SocketController` diversity * adding the new arguments into the README.md * fixing an indentation error causing `--strategy ` not to work (the simple `` still worked) * add fw-ectool in module * fixing missing print for command execution (#63) --------- Co-authored-by: Léopold Hubert Co-authored-by: Nina Alexandra Klama Co-authored-by: DeflateAwning <11021263+DeflateAwning@users.noreply.github.com> --- README.md | 27 ++-- fanctrl.py | 315 ++++++++++++++++++++++++------------ nix/module.nix | 4 +- nix/packages/fw-fanctrl.nix | 4 +- 4 files changed, 231 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index 26d2973..1dafd35 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Under the hood, it uses [ectool](https://gitlab.howett.net/DHowett/ectool) to ch It is compatible with all kinds of 13" and 16" models, both AMD/Intel CPUs, with or without a discrete GPU. +If the service is paused or stopped, the fans will revert to their default behaviour. + # Install For NixOS this repo contains an Flake. You could add it to your config like this: @@ -94,15 +96,16 @@ The strategy active by default is the one specified in the `defaultStrategy` ent # Commands -| Option | Context | Description | -|-------------------|-----------------|---------------------------------| -| \ | run & configure | the name of the strategy to use | -| --run | run | run the service | -| --config | run | specify the configuration path | -| --no-log | run | disable state logging | -| --query, -q | configure | print the current strategy name | -| --list-strategies | configure | print the available strategies | -| --reload, -r | configure | reload the configuration file | -| --pause | configure | temporarily disable the service | -| --resume | configure | resume the service | - +| Option | Context | Description | +|-----------------------------|-----------------|-------------------------------------------------------------------------------| +| \ | run & configure | the name of the strategy to use | +| --run | run | run the service | +| --config | run | specify the configuration path | +| --no-log | run | disable state logging | +| --query, -q | configure | print the current strategy name | +| --list-strategies | configure | print the available strategies | +| --reload, -r | configure | reload the configuration file | +| --pause | configure | temporarily disable the service and reset the fans to their default behaviour | +| --resume | configure | resume the service | +| --hardware-controller, --hc | run | select the hardware controller. choices: ectool | +| --socket-controller, --sc | run & configure | select the socket controller. choices: unix | diff --git a/fanctrl.py b/fanctrl.py index b605378..9c75bbd 100644 --- a/fanctrl.py +++ b/fanctrl.py @@ -10,6 +10,7 @@ import sys import threading from time import sleep +from abc import ABC, abstractmethod DEFAULT_CONFIGURATION_FILE_PATH = "/etc/fw-fanctrl/config.json" SOCKETS_FOLDER_PATH = "/run/fw-fanctrl" @@ -18,10 +19,22 @@ parser = None +class JSONException(Exception): + pass + + +class UnimplementedException(Exception): + pass + + class InvalidStrategyException(Exception): pass +class SocketAlreadyRunningException(Exception): + pass + + class Strategy: name = None fanSpeedUpdateFrequency = None @@ -76,7 +89,138 @@ def getDischargingStrategy(self): return self.getStrategy("strategyOnDischarging") +class SocketController(ABC): + @abstractmethod + def startServerSocket(self, commandCallback=None): + raise UnimplementedException() + + @abstractmethod + def stopServerSocket(self): + raise UnimplementedException() + + @abstractmethod + def isServerSocketRunning(self): + raise UnimplementedException() + + @abstractmethod + def sendViaClientSocket(self, command): + raise UnimplementedException() + + +class UnixSocketController(SocketController, ABC): + server_socket = None + + def startServerSocket(self, commandCallback=None): + if self.server_socket: + raise SocketAlreadyRunningException(self.server_socket) + self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + if os.path.exists(COMMANDS_SOCKET_FILE_PATH): + os.remove(COMMANDS_SOCKET_FILE_PATH) + try: + if not os.path.exists(SOCKETS_FOLDER_PATH): + os.makedirs(SOCKETS_FOLDER_PATH) + self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.server_socket.bind(COMMANDS_SOCKET_FILE_PATH) + os.chmod(COMMANDS_SOCKET_FILE_PATH, 0o777) + self.server_socket.listen(1) + while True: + client_socket, _ = self.server_socket.accept() + try: + # Receive data from the client + data = client_socket.recv(4096).decode() + args = parser.parse_args(shlex.split(data)) + commandReturn = commandCallback(args) + if not commandReturn: + commandReturn = "Success!" + client_socket.sendall(commandReturn.encode()) + except Exception as e: + client_socket.sendall(f"[Error] > An error occurred: {e}".encode()) + finally: + client_socket.shutdown(socket.SHUT_WR) + client_socket.close() + finally: + self.server_socket.close() + + def stopServerSocket(self): + if self.server_socket: + self.server_socket.close() + self.server_socket = None + + def isServerSocketRunning(self): + return self.server_socket is not None + + def sendViaClientSocket(self, command): + client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + client_socket.connect(COMMANDS_SOCKET_FILE_PATH) + client_socket.sendall(command.encode()) + received_data = b"" + while True: + data_chunk = client_socket.recv(1024) + if not data_chunk: + break + received_data += data_chunk + # Receive data from the server + data = received_data.decode() + if data.startswith("Error:"): + raise Exception(data) + return data + finally: + if client_socket: + client_socket.close() + + +class HardwareController(ABC): + @abstractmethod + def getTemperature(self): + raise UnimplementedException() + + @abstractmethod + def setSpeed(self, speed): + raise UnimplementedException() + + @abstractmethod + def pause(self): + pass + + @abstractmethod + def resume(self): + pass + + @abstractmethod + def isOnAC(self): + raise UnimplementedException() + + +class EctoolHardwareController(HardwareController, ABC): + + def getTemperature(self): + rawOut = subprocess.run("ectool temps all", stdout=subprocess.PIPE, shell=True, text=True).stdout + rawTemps = re.findall(r'\(= (\d+) C\)', rawOut) + temps = sorted([x for x in [int(x) for x in rawTemps] if x > 0], reverse=True) + # safety fallback to avoid damaging hardware + if len(temps) == 0: + return 50 + return round(temps[0], 1) + + def setSpeed(self, speed): + subprocess.run(f"ectool fanduty {speed}", stdout=subprocess.PIPE, shell=True) + + def isOnAC(self): + rawOut = subprocess.run("ectool battery", stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True, + text=True).stdout + return len(re.findall(r"Flags.*(AC_PRESENT)", rawOut)) > 0 + + def pause(self): + subprocess.run("ectool autofanctrl", stdout=subprocess.PIPE, shell=True) + + def resume(self): + pass + + class FanController: + hardwareController = None + socketController = None configuration = None overwrittenStrategy = None speed = 0 @@ -84,23 +228,35 @@ class FanController: active = True timecount = 0 - def __init__(self, configPath, strategyName): + def __init__(self, hardwareController, socketController, configPath, strategyName): + self.hardwareController = hardwareController + self.socketController = socketController self.configuration = Configuration(configPath) if strategyName is not None and strategyName != "": self.overwriteStrategy(strategyName) - t = threading.Thread(target=self.bindSocket) + t = threading.Thread(target=self.socketController.startServerSocket, args=[self.commandManager]) t.daemon = True t.start() + def getActualTemperature(self): + return self.hardwareController.getTemperature() + + def setSpeed(self, speed): + self.speed = speed + self.hardwareController.setSpeed(speed) + + def isOnAC(self): + return self.hardwareController.isOnAC() + def pause(self): self.active = False - bashCommand = f"ectool autofanctrl" - subprocess.run(bashCommand, stdout=subprocess.PIPE, shell=True) + self.hardwareController.pause() def resume(self): self.active = True + self.hardwareController.resume() def overwriteStrategy(self, strategyName): self.overwrittenStrategy = self.configuration.getStrategy(strategyName) @@ -113,88 +269,37 @@ def clearOverwrittenStrategy(self): def getCurrentStrategy(self): if self.overwrittenStrategy is not None: return self.overwrittenStrategy - if self.getBatteryChargingStatus(): + if self.isOnAC(): return self.configuration.getDefaultStrategy() return self.configuration.getDischargingStrategy() - def getBatteryChargingStatus(self): - bashCommand = "ectool battery" - rawOut = subprocess.run(bashCommand, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True, - text=True).stdout - return len(re.findall(r'Flags.*(AC_PRESENT)', rawOut)) > 0 - - def bindSocket(self): - server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - if os.path.exists(COMMANDS_SOCKET_FILE_PATH): - os.remove(COMMANDS_SOCKET_FILE_PATH) - try: - if not os.path.exists(SOCKETS_FOLDER_PATH): - os.makedirs(SOCKETS_FOLDER_PATH) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(COMMANDS_SOCKET_FILE_PATH) - os.chmod(COMMANDS_SOCKET_FILE_PATH, 0o777) - server_socket.listen(1) - while True: - client_socket, _ = server_socket.accept() - try: - # Receive data from the client - data = client_socket.recv(4096).decode() - print("Received command:", data) - - args = parser.parse_args(shlex.split(data)) - if args.strategy or args._strategy: - strategy = args.strategy - if strategy is None: - strategy = args._strategy - try: - if strategy == "defaultStrategy": - self.clearOverwrittenStrategy() - else: - self.overwriteStrategy(strategy) - client_socket.sendall(self.getCurrentStrategy().name.encode()) - except InvalidStrategyException: - client_socket.sendall(("Error: unknown strategy: " + strategy).encode()) - if args.pause: - self.pause() - client_socket.sendall("Success".encode()) - if args.resume: - self.resume() - client_socket.sendall("Success".encode()) - if args.query: - client_socket.sendall(self.getCurrentStrategy().name.encode()) - if args.list_strategies: - client_socket.sendall('\n'.join(self.configuration.getStrategies()).encode()) - if args.reload: - if self.configuration.reload(): - if self.overwrittenStrategy is not None: - self.overwriteStrategy(self.overwrittenStrategy.name) - client_socket.sendall("Success".encode()) - else: - client_socket.sendall("Error: Config file could not be parsed due to JSON Error".encode()) - except: - pass - finally: - client_socket.shutdown(socket.SHUT_WR) - client_socket.close() - finally: - server_socket.close() - - def setSpeed(self, speed): - self.speed = speed - bashCommand = f"ectool fanduty {speed}" - subprocess.run(bashCommand, stdout=subprocess.PIPE, shell=True) - - def getActualTemperature(self): - bashCommand = "ectool temps all" - rawOut = subprocess.run(bashCommand, stdout=subprocess.PIPE, shell=True, text=True).stdout - rawTemps = re.findall(r'\(= (\d+) C\)', rawOut) - temps = sorted([x for x in [int(x) for x in rawTemps] if x > 0], reverse=True) - - # safety fallback to avoid damaging hardware - if len(temps) == 0: - return 50 - - return round(temps[0], 1) + def commandManager(self, command): + if command.strategy or command._strategy: + strategy = command.strategy + if strategy is None: + strategy = command._strategy + try: + if strategy == "defaultStrategy": + self.clearOverwrittenStrategy() + else: + self.overwriteStrategy(strategy) + return self.getCurrentStrategy().name + except InvalidStrategyException: + raise InvalidStrategyException(f"The specified strategy is invalid: {strategy}") + elif command.pause: + self.pause() + elif command.resume: + self.resume() + elif command.query: + return self.getCurrentStrategy().name + elif command.list_strategies: + return '\n'.join(self.configuration.getStrategies()) + elif command.reload: + if self.configuration.reload(): + if self.overwrittenStrategy is not None: + self.overwriteStrategy(self.overwrittenStrategy.name) + else: + raise JSONException("Config file could not be parsed due to JSON Error") # return mean temperature over a given time interval (in seconds) def getMovingAverageTemperature(self, timeInterval): @@ -269,12 +374,14 @@ def main(): bothGroup.add_argument( "_strategy", nargs="?", - help='Name of the strategy to use e.g: "lazy" (check config.json for others). Use "defaultStrategy" to go back to the default strategy', + help='Name of the strategy to use e.g: "lazy" (check config.json for others). Use "defaultStrategy" to go ' + 'back to the default strategy', ) bothGroup.add_argument( "--strategy", nargs="?", - help='Name of the strategy to use e.g: "lazy" (check config.json for others). Use "defaultStrategy" to go back to the default strategy', + help='Name of the strategy to use e.g: "lazy" (check config.json for others). Use "defaultStrategy" to go ' + 'back to the default strategy', ) runGroup = parser.add_argument_group("run") @@ -295,34 +402,36 @@ def main(): ) commandGroup.add_argument("--pause", help="Pause the program", action="store_true") commandGroup.add_argument("--resume", help="Resume the program", action="store_true") + commandGroup.add_argument("--hardware-controller", "--hc", help="Select the hardware controller", type=str, + choices=["ectool"], default="ectool") + commandGroup.add_argument("--socket-controller", "--sc", help="Select the socket controller", type=str, + choices=["unix"], default="unix") args = parser.parse_args() + socketController = None + if args.socket_controller == "unix": + socketController = UnixSocketController() + if args.run: + hardwareController = None + if args.hardware_controller == "ectool": + hardwareController = EctoolHardwareController() + strategy = args.strategy if strategy is None: strategy = args._strategy - fan = FanController(configPath=args.config, strategyName=args.strategy) + fan = FanController(hardwareController=hardwareController, socketController=socketController, + configPath=args.config, strategyName=args.strategy) fan.run(debug=not args.no_log) else: - client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: - client_socket.connect(COMMANDS_SOCKET_FILE_PATH) - client_socket.sendall(' '.join(sys.argv[1:]).encode()) - received_data = b"" - while True: - data_chunk = client_socket.recv(1024) - if not data_chunk: - break - received_data += data_chunk - # Receive data from the server - data = received_data.decode() - print(data) - if data.startswith("Error:"): - exit(1) - finally: - if client_socket: - client_socket.close() + commandResult = socketController.sendViaClientSocket(' '.join(sys.argv[1:])) + if commandResult: + print(commandResult) + except Exception as e: + print(f"[Error] > An error occurred: {e}", file=sys.stderr) + exit(1) if __name__ == "__main__": diff --git a/nix/module.nix b/nix/module.nix index 9cd79ad..4ed6d5d 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -85,7 +85,7 @@ in # Install package environment.systemPackages = with pkgs; [ fw-fanctrl - ectool + fw-ectool ]; # Create config @@ -101,7 +101,7 @@ in Type = "simple"; Restart = "always"; ExecStart = "${fw-fanctrl}/bin/fw-fanctrl --run --config /etc/fw-fanctrl/config.json --no-log"; - ExecStopPost = "${pkgs.ectool}/bin/ectool autofanctrl"; + ExecStopPost = "${pkgs.fw-ectool}/bin/ectool autofanctrl"; }; enable = true; wantedBy = [ "multi-user.target" ]; diff --git a/nix/packages/fw-fanctrl.nix b/nix/packages/fw-fanctrl.nix index 50df35c..749d56b 100644 --- a/nix/packages/fw-fanctrl.nix +++ b/nix/packages/fw-fanctrl.nix @@ -5,7 +5,7 @@ python3, bash, callPackage, getopt, -ectool +fw-ectool }: let @@ -46,7 +46,7 @@ python3Packages.buildPythonPackage rec{ ]; propagatedBuildInputs = [ - ectool + fw-ectool ]; doCheck = false;