{"id":13437962,"url":"https://github.com/markusressel/fan2go","last_synced_at":"2026-05-23T01:07:32.555Z","repository":{"id":37915781,"uuid":"330354128","full_name":"markusressel/fan2go","owner":"markusressel","description":"A simple daemon providing dynamic fan speed control based on temperature sensors.","archived":false,"fork":false,"pushed_at":"2024-10-16T17:10:47.000Z","size":1251,"stargazers_count":227,"open_issues_count":17,"forks_count":22,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-18T10:20:06.922Z","etag":null,"topics":["daemon","fan","fan-speed","fancontrol","golang","hacktoberfest","pwm","rpm","temperature"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markusressel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["markusressel"]}},"created_at":"2021-01-17T09:19:22.000Z","updated_at":"2024-10-16T17:10:49.000Z","dependencies_parsed_at":"2023-10-03T19:13:45.178Z","dependency_job_id":"fa5b0abe-5f03-4823-ab77-80149c9671dc","html_url":"https://github.com/markusressel/fan2go","commit_stats":{"total_commits":662,"total_committers":12,"mean_commits":"55.166666666666664","dds":"0.22809667673716016","last_synced_commit":"02679bed2b8b7a484f1e2870ff5809feae7205ce"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Ffan2go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Ffan2go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Ffan2go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Ffan2go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markusressel","download_url":"https://codeload.github.com/markusressel/fan2go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625479,"owners_count":21135512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["daemon","fan","fan-speed","fancontrol","golang","hacktoberfest","pwm","rpm","temperature"],"created_at":"2024-07-31T03:01:01.739Z","updated_at":"2026-05-23T01:07:32.541Z","avatar_url":"https://github.com/markusressel.png","language":"Go","funding_links":["https://github.com/sponsors/markusressel"],"categories":["HarmonyOS","Go"],"sub_categories":["Windows Manager"],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"screenshots/fan2go_icon.svg\" width=\"144\" height=\"144\" alt=\"fan2go icon\"\u003e\n  \u003cbr\u003e\n  fan2go\n  \u003cbr\u003e\n\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003eA daemon to control the fans of your computer.\u003c/h4\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Programming Language](https://img.shields.io/badge/Go-00ADD8?logo=go\u0026logoColor=white)]()\n[![Latest Release](https://img.shields.io/github/release/markusressel/fan2go.svg)](https://github.com/markusressel/fan2go/releases)\n[![License](https://img.shields.io/badge/license-AGPLv3-blue.svg)](/LICENSE)\n\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"screenshots/graph.png\" width=90% alt=\"Screenshot of Pyrra\"\u003e\u003c/p\u003e\n\n# Features\n\n* [x] Intuitive YAML based configuration\n* [x] Massive range of supported devices\n    * [x] lm-sensors (hwmon) based sensors and fans\n    * [x] Fans and temperature sensor on NVIDIA GPUs ([nvml](https://developer.nvidia.com/management-library-nvml))\n    * [x] File based fan/sensor for control/measurement of custom devices\n    * [x] Command based fan/sensor\n* [x] Per fan user-defined speed curves\n* [x] Fully customizable and composable curve definitions\n* [x] Works after resume from suspend\n* [x] **Stable** device paths after reboot\n* [x] Automatic analysis of fan properties, like:\n    * [x] RPM curve\n    * [x] minimum and maximum PWM\n* [x] Error notifications\n* [x] Prometheus exporter\n* [x] (optional) REST Api\n\n# UI\n\nfan2go is first and foremost a daemon that runs in the background. However, it also provides\na small set of CLI commands (see [CLI Commands](#cli-commands)) as well as an optional local HTTP API to allow\nexternal programs to interact with it. This API can be used to create UI clients or other tools.\n\n## UI Clients\n\n[fan2go-tui](https://github.com/markusressel/fan2go-tui) - (Official) Terminal UI for fan2go.\n\n[![asciicast](https://asciinema.org/a/1099673.svg)](https://asciinema.org/a/1099673)\n\n# How to use\n\nfan2go relies on [lm-sensors](https://github.com/lm-sensors/lm-sensors) to get both temperature and RPM sensor readings,\nas well as PWM controls, so you will have\nto [set it up first](https://wiki.archlinux.org/index.php/Lm_sensors#Installation).\n\n## Installation\n\n### Arch Linux ![](https://img.shields.io/badge/Arch_Linux-1793D1?logo=arch-linux\u0026logoColor=white)\n\n```shell\nyay -S fan2go-git\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eCommunity Maintained Packages\u003c/summary\u003e\n\n### Nix OS ![](https://img.shields.io/badge/nixpkgs-5277C3?logo=nixos\u0026logoColor=white)\n\n- Nix with [Flakes](https://nixos.wiki/wiki/Flakes):\n\n```shell\nnix profile install nixpkgs#fan2go\n```\n\n- Nix stable:\n\n```shell\nnix-env -f '\u003cnixpkgs\u003e' -iA fan2go\n```\n\n### Debian / Ubuntu\n\nSee: https://github.com/johnwbyrd/fan2go-package/\n\n\u003c/details\u003e\n\n### Manual\n\nDownload the latest release from GitHub:\n\n```shell\n# Install dependencies\nsudo pacman -S libnotify\n\ncurl -L -o fan2go https://github.com/markusressel/fan2go/releases/latest/download/fan2go-linux-amd64\nchmod +x fan2go\nsudo cp ./fan2go /usr/bin/fan2go\nfan2go -h\n```\n\nOr compile yourself:\n\n```shell\ngit clone https://github.com/markusressel/fan2go.git\ncd fan2go\nmake build\nsudo cp ./bin/fan2go /usr/bin/fan2go\nsudo chmod ug+x /usr/bin/fan2go\n```\n\n## Configuration\n\nThen configure fan2go by creating a YAML configuration file in **one** of the following locations:\n\n* `/etc/fan2go/fan2go.yaml` (recommended)\n* `/root/.fan2go/fan2go.yaml`\n* `./fan2go.yaml`\n\n```shell\nsudo mkdir /etc/fan2go\nsudo nano /etc/fan2go/fan2go.yaml\n```\n\nThe most important configuration options you need to define are the `fans:`, `sensors:` and `curves:` sections.\n\n### Fans\n\nUnder `fans:` you need to define a list of fan devices that you want to control using fan2go. To detect fans on your\nsystem run `fan2go detect`, which will print a list of devices exposed by the hwmon filesystem backend:\n\n```shell\n$ fan2go detect\n=========== hwmon: ============\n\n\u003e Platform: nct6798-isa-0290\n Fans     Index  Channel  Label        RPM   PWM  Mode\n          1      1        hwmon4/fan1  0     153  Manual\n          2      2        hwmon4/fan2  1223  104  Manual\n          3      3        hwmon4/fan3  677   107  Manual\n Sensors   Index   Label    Value\n           1       SYSTIN   41000\n           2       CPUTIN   64000\n\n\u003e Platform: amdgpu-pci-0031\n Fans     Index  Channel  Label        RPM   PWM  Mode\n          1      1        hwmon8/fan1  561   43   Manual\n Sensors   Index   Label      Value\n           1       edge       58000\n           2       junction   61000\n           3       mem        56000\n\n=========== nvidia: ===========\n\n\u003e Device: nvidia-10DE2489-0800\n  Fans     Index  Label  PWM  RPM   Mode\n           1      Fan 1  36   1300  Auto\n           2      Fan 2  36   1298  Auto\n  Sensors  Index  Label        Value\n           1      Temperature  59000\n```\n\nThe `hwmon` fan index is based on device enumeration and is not stable for a given fan if hardware configuration\nchanges.\nThe Linux kernel hwmon channel is a better identifier for configuration as it is largely based on the fan headers\nin use.\n\nFan RPM, PWM, and temperature sensors are independent and Linux does not associate them automatically. A given PWM\nmay control more than one fan, and a fan may not be under the control of a PWM. By default, fan2go guesses and sets\nthe pwm channel number for a given fan to the fan's RPM sensor channel. You can override this in the config.\n\nFor `nvidia` devices, the fan index *is* stable.\n\nNote that it can happen that the hardware only gives limited control over a fan and it, for example,\nalways runs with at least 30% speed - even if in automatic mode the hardware may make it stop entirely\nif the temperature is low enough.\n\n#### HwMon\n\nTo use detected hwmon devices in your configuration, use the `hwmon` fan type:\n\n```yaml\n# A list of fans to control\nfans:\n  # A user defined ID.\n  # Used for logging only\n  - id: cpu\n    # The type of fan configuration, one of: hwmon | file\n    hwmon:\n      # A regex matching a controller platform displayed by `fan2go detect`, f.ex.:\n      # \"nouveau\", \"coretemp\", \"it8620\", \"corsaircpro-.*\" etc.\n      platform: nct6798\n      # The channel of this fan's RPM sensor as displayed by `fan2go detect`\n      rpmChannel: 1\n      # The pwm channel that controls this fan; fan2go defaults to same channel number as fan RPM\n      pwmChannel: 1\n    # Indicates whether this fan should never stop rotating, regardless of\n    # how low the curve value is\n    neverStop: true\n    # The curve ID that should be used to determine the\n    # speed of this fan\n    curve: cpu_curve\n```\n\n#### NVIDIA\n\nTo use detected NVIDIA GPUs in your configuration, use the `nvidia` fan type:\n\n```yaml\nfans:\n  - id: gpufan1\n    nvidia:\n      # A regex matching a nvidia device as displayed by `fan2go detect`\n      # the following matches all nvidia devices in your system\n      # (good enough if you only have one), otherwise you could\n      # also use nvidia-10DE2489-0800 or similar\n      device: nvidia\n      # The fan's index as shown by `fan2go detect`\n      index: 1\n    curve: gpu_curve\n\n  # same for the second fan\n  - id: gpufan2\n    nvidia:\n      device: nvidia\n      index: 2\n    curve: gpu_curve\n```\n\nNote that the fan speed can only be controlled for GPUs of the \"Maxwell\" generation\n(Geforce 9xx) and newer, and that reading the fan speed in RPM requires nvidia driver 565\nor newer.\n\n#### File\n\n```yaml\nfans:\n  - id: file_fan\n    file:\n      # Path to a file to get/set the PWM target for this fan\n      path: /tmp/file_fan\n      # Path to a file to read the current RPM value of this fan\n      rpmPath: /tmp/file_fan_rpm\n```\n\n```shell\n\u003e cat /tmp/file_fan\n255\n\u003e cat /tmp/file_fan_rpm\n3421\n```\n\n#### CMD\n\nPlease also make sure to read the section about\n[considerations for using the cmd sensor/fan](#using-external-commands-for-sensorsfans).\n\n```yaml\nfans:\n  - id: cmd_fan\n    cmd:\n      # Command to apply a new PWM value (0..255)\n      # Use \"%pwm%\" to specify where the target pwm value should be used within the arguments\n      setPwm:\n        exec: /usr/bin/some-program\n        args: [ \"--set\", \"%pwm%\" ]\n      # Command to retrieve the current PWM value (0..255)\n      getPwm:\n        exec: /usr/bin/nvidia-settings\n        args: [ \"-a\", \"someargument\" ]\n      # (optional) Command to retrieve the current RPM value\n      getRpm:\n        exec: /usr/bin/nvidia-settings\n        args: [ \"-a\", \"someargument\" ]\n```\n\n#### Disk\n\nReads the temperature of a block device (SATA, NVMe, etc.) using a stable device path instead of an\nhwmon platform index that can change across reboots.\n\n```yaml\nsensors:\n  - id: ssd_temp\n    disk:\n      # Full path (recommended for clarity)\n      device: /dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_S1234567890\n      # Short form also accepted (prefix /dev/disk/by-id/ is auto-applied):\n      # device: ata-Samsung_SSD_870_EVO_1TB_S1234567890\n      # The /dev/ prefix is also optional (e.g. just \"sda\"):\n      # device: sda\n\n  - id: nvme_temp\n    disk:\n      device: /dev/disk/by-id/nvme-Samsung_SSD_980_1TB_S1234567890\n      # Short form: device: nvme-Samsung_SSD_980_1TB_S1234567890\n```\n\nRequires the `drivetemp` kernel module for SATA drives (standard since kernel 5.6) or `nvme-hwmon`\nfor NVMe (standard since kernel 4.15). Falls back to a direct ATA SMART ioctl for SATA drives\nwithout `drivetemp` loaded.\n\n#### Advanced Options\n\nIf the automatic fan curve analysis doesn't provide a good enough estimation\nfor how the fan behaves, you can use the following configuration options (per fan definition)\nto correct it:\n\n```yaml\nfans:\n  - id: ...\n    ...\n    # (Optional) Override for the lowest PWM value at which the\n    # fan is able to maintain rotation if it was spinning previously.\n    minPwm: 30\n    # (Optional) Override for the lowest PWM value at which the\n    # fan will still be able to start rotating.\n    # Note: Settings this to a value that is too small\n    #       may damage your fans. Use at your own risk!\n    startPwm: 30\n    # (Optional) Override for the highest PWM value which still yields\n    # an increased rotational speed compared to lower values.\n    # Note: you can also use this to limit the max speed of a fan.\n    maxPwm: 255\n    # (Optional) Override the global fanController.pwmSetDelay for this specific fan.\n    # Useful when a fan requires more or less time to respond to PWM changes than the global default.\n    # pwmSetDelay: 10ms\n    # (Optional) Configure how fan2go maps the internal [0..255] PWM range to\n    # hardware-specific PWM values. If omitted, fan2go auto-detects the mapping\n    # during fan initialization.\n    #\n    # Modes:\n    #\n    # autodetect (default): auto-detect the PWM map during fan initialization.\n    pwmMap: autodetect\n    #\n    # identity: assume a 1:1 mapping (0→0, 1→1, ..., 255→255).\n    # Use this if your fan supports the full PWM range and you want to skip\n    # the initialization measurement.\n    # pwmMap: identity\n    #\n    # linear: linearly interpolate between user-specified control points.\n    # Useful when you know the endpoints (or intermediate points) but want\n    # smooth values in between.\n    # Note: values must be strictly monotonically increasing.\n    # pwmMap:\n    #   linear:\n    #     0: 0\n    #     255: 255\n    #\n    # values: step-interpolate user-specified control points.\n    # Use for fans that only support a limited set of discrete PWM values\n    # (e.g. off / low / medium / high).\n    # Note: values must be strictly monotonically increasing.\n    # pwmMap:\n    #   values:\n    #     0: 0\n    #     64: 128\n    #     192: 255\n    # (Optional) Configure how fan2go determines the mapping from a PWM value it sets\n    # to the value the fan hardware reports back. Some fans do not echo the exact value\n    # written due to hardware or driver quirks. If omitted, fan2go auto-detects this\n    # during fan initialization.\n    #\n    # Modes:\n    #\n    # autodetect (default): sweep all PWM values and record what the fan reports back.\n    setPwmToGetPwmMap: autodetect\n    #\n    # identity: assume the fan reports back exactly what was set (1:1 mapping).\n    # Equivalent to the --assume-pwm-map-identity flag on `fan2go fan init`.\n    # setPwmToGetPwmMap: identity\n    #\n    # linear: linearly interpolate between user-specified control points.\n    # setPwmToGetPwmMap:\n    #   linear:\n    #     0: 0\n    #     255: 255\n    #\n    # values: step-interpolate user-specified control points.\n    # setPwmToGetPwmMap:\n    #   values:\n    #     0: 0\n    #     128: 128\n    #     255: 255\n    # (Optional) Configure the control mode fan2go uses while running and on exit.\n    # Both fields are optional; omitting controlMode entirely preserves existing behavior.\n    #\n    # active: the control mode to set when fan2go takes control of this fan.\n    #   Accepts: \"pwm\" (default, with \"disabled\" fallback), \"disabled\", \"auto\", or an integer.\n    # onExit: what to do when fan2go exits.\n    #   String shorthand:\n    #     onExit: restore   # restore original control mode (default)\n    #     onExit: none      # leave fan at last speed set by fan2go (useful for hardware controllers\n    #                       # that remember PWM settings — see issue #416)\n    #   Map form (set explicit values on exit):\n    #     onExit:\n    #       mode: auto      # set a specific control mode on exit\n    #       speed: 128      # set a fixed PWM speed on exit (0..255)\n    #     # controlMode and speed can be combined or used independently.\n    controlMode:\n      active: pwm\n      onExit: restore\n    # By default (useUnscaledCurveValues: false) speed values from the curve are scaled\n    # from 1..255 (or 1%..100%) to MinPwm..MaxPwm  and speed values \u003c 1(%) are set to 0,\n    # before they're mapped with pwmMap (the value looked up in pwmMap is then used to\n    # actually set the speed in the fan's controlling device).\n    # If useUnscaledCurveValues is set to true, the values from the curve for a specific temperature\n    # are directly mapped with PwmMap, *without* scaling them first.\n    # Note: If neverStop is also set to true, values smaller than MinPwm (including 0) are replaced with\n    #   MinPwm, otherwise values smaller than MinPwm are replaced with 0 (the fan wouldn't turn anyway).\n    #   But all values \u003e= MinPwm are used as is if this option is set to true.\n    useUnscaledCurveValues: true\n    # (Optional) Configuration options for sanity checks\n    sanityCheck:\n      # (Optional) Control the behavior of the \"pwmValueChangedByThirdParty\" sanity check\n      # This check is used to detect if the PWM value of a fan has changed between two consecutive\n      # control loop cycles, which is usually an indication that an external program is trying to control the fan\n      # at the same time as fan2go. This can lead to unexpected behavior and is usually not desired, so \n      # fan2go will log a warning if this happens.\n      pwmValueChangedByThirdParty:\n        # (Optional) Whether to enable this check or not\n        enabled: true\n      # (Optional) Control the behavior of the \"fanModeChangedByThirdParty\" sanity check\n      # This check is used to detect if the fan mode (automatic/manual) has changed between two consecutive\n      # control loop cycles, which is usually an indication that an external program is trying to control the fan\n      # at the same time as fan2go. This can lead to unexpected behavior and is usually not desired, so\n      # fan2go will reset the desired fan mode and log a warning if this happens.\n      fanModeChangedByThirdParty:\n        # (Optional) Whether to enable this check or not\n        enabled: true\n        # (Optional) Throttle duration for the execution of this check.\n        throttleDuration: 10s\n```\n\n### Sensors\n\nUnder `sensors:` you need to define a list of temperature sensor devices that you want to monitor and use to adjust\nfanspeeds. Like with fans, you can find usable devices using `fan2go detect`.\n\n#### HwMon\n\n```yaml\n# A list of sensors to monitor\nsensors:\n  # A user defined ID, which is used to reference\n  # a sensor in a curve configuration (see below)\n  - id: cpu_package\n    # The type of sensor configuration, one of: hwmon | nvidia | file | cmd | disk\n    hwmon:\n      # A regex matching a controller platform displayed by `fan2go detect`, f.ex.:\n      # \"coretemp\", \"it8620\", \"corsaircpro-*\" etc.\n      platform: coretemp\n      # The index of this sensor as displayed by `fan2go detect`\n      index: 1\n```\n\n#### NVIDIA\n\n```yaml\nsensors:\n  - id: gpu_temp\n    nvidia:\n      # A regex matching a nvidia device as displayed by `fan2go detect`\n      device: nvidia-10DE2489-0800\n      # The index of this sensor as displayed by `fan2go detect`\n      # (currently NVIDIA/nvml exposes only a single temperature sensor per GPU)\n      index: 1\n```\n\n#### File\n\n```yaml\nsensors:\n  - id: file_sensor\n    file:\n      # Path to the file containing sensor values\n      path: /tmp/file_sensor\n```\n\nThe file contains a value in milli-units, like f.ex. milli-degrees.\n\n```bash\n\u003e cat /tmp/file_sensor\n10000\n```\n\n#### CMD\n\nPlease also make sure to read the section about\n[considerations for using the cmd sensor/fan](#using-external-commands-for-sensorsfans).\n\nJust like the `file` sensor, the command must output the sensor value in milli-units,\nlike f.ex. milli-degrees.\n\n```yaml\nsensors:\n  - id: cmd_fan\n    cmd:\n      # Path to the executable to run to retrieve the current sensor value\n      exec: /usr/bin/bash\n      # (optional) arguments to pass to the executable\n      args: [ '/home/markus/myscript.sh' ]\n```\n\n### Curves\n\nUnder `curves:` you need to define a list of fan speed curves, which represent the speed of a fan based on one or more\ntemperature sensors.\n\n\u003e **Speed values:** Curve values range from `0` to `255` (equivalently `0%` to `100%`).\n\u003e By default, fan2go scales these to the fan's detected (or configured) `minPwm`..`maxPwm` range:\n\u003e - `0` / `0%` → fan off (unless `neverStop: true`, in which case the fan is held at `minPwm`)\n\u003e - `1`..`255` / `1%`..`100%` → linearly mapped to `minPwm`..`maxPwm`\n\u003e\n\u003e To use curve values as raw PWM values without scaling, set `useUnscaledCurveValues: true` in the fan config.\n\n#### Linear\n\nTo create a simple, linear speed curve, use a curve of type `linear`.\n\nThis curve type can be used with a min/max sensor value, where the min temp will result in a curve value of `0` and the\nmax temp will result in a curve value of `255`:\n\n```yaml\ncurves:\n  - id: cpu_curve\n    # The type of the curve, one of: linear | function\n    linear:\n      # The sensor ID to use as a temperature input\n      sensor: cpu_package\n      # Sensor input value (in degrees Celsius)\n      # at which the curve is at minimum speed\n      min: 40\n      # Sensor input value at which the curve is at maximum speed\n      max: 80\n```\n\nYou can also define the curve in multiple, linear sections using the `steps` parameter,\nwhere the left side refers to the sensor input value and the right side refers to the curve value at that sensor input.\n\n```yaml\ncurves:\n  - id: cpu_curve\n    # The type of the curve\n    linear:\n      # The sensor ID to use as a temperature input\n      sensor: cpu_package\n      # Steps to define a section-wise defined speed curve function.\n      steps:\n        # Sensor value (in degrees Celsius) -\u003e Speed\n        - 40: 0%   #   0% and speed value 0 are the same\n        - 41: 1%   #   1% and speed value 1 are the same and mean \"run at minimum speed\" (MinPwm)\n          # Note: between 41 and 50°C the fan speed will be interpolated between 1% and 20%\n        - 50: 20%  #  20% is equivalent to speed value ≈ 50\n          # Note: between 50 and 80°C the fan speed will be interpolated between 20% and 100%\n          #       for example, at 65°C it'll run at 60% speed\n        - 80: 100% # 100% is equivalent to speed value 255\n```\n\n\u003e NOTE: When using `useUnscaledCurveValues` in the fan configuration, the values specified in the curve are **not scaled\n**\n\u003e to the [MinPwm..MaxPwm] range of the fan, but are directly mapped with the `pwmMap` (if specified) or used as is (if\n\u003e no `pwmMap` is specified and a 1:1 mapping is assumed).\n\u003e In this case, it is recommended to specify curve values in the same range as the expected PWM values after scaling to\n\u003e avoid confusion.\n\u003e So if your fan has a MinPwm of 30 and a MaxPwm of 255, you should specify curve values in the [30..255] range.\n\nAlternatively the speeds can be specified in [0..255] range:\n\n```yaml\ncurves:\n  - id: cpu_curve\n    # The type of the curve\n    linear:\n      # The sensor ID to use as a temperature input\n      sensor: cpu_package\n      # Steps to define a section-wise defined speed curve function.\n      steps:\n        # Sensor value (in degrees Celsius) -\u003e Speed (0-255)\n        - 40: 0\n        - 41: 1\n        - 50: 50\n        - 80: 255\n```\n\n#### PID\n\nIf you want to get your hands dirty and use a PID based curve, you can use `pid`:\n\n```yaml\ncurves:\n  - id: pid_curve\n    pid:\n      sensor: cpu_package\n      setPoint: 60\n      p: -0.05\n      i: -0.005\n      d: -0.005\n```\n\nUnlike the other curve types, this one does not use the average of the sensor data\nto calculate its value, which allows you to create a completely custom behaviour.\nKeep in mind though that the fan controller may also be PID based (depending on the\nspecified `controlAlgorithm`) which would also affect how the curve is applied to the fan.\n\n`setPoint` is the target temperature.\n\nSee: [PID controller on Wikipedia](https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller)\nfor more information on what a PID controller is.\n\n#### Function\n\nTo create more complex curves you can combine existing curves using a curve of type `function`:\n\n```yaml\ncurves:\n  - id: case_avg_curve\n    function:\n      # Type of aggregation function to use, one of: minimum | maximum | average | delta | sum | difference\n      type: average\n      # A list of curve IDs to use\n      curves:\n        - cpu_curve\n        - mainboard_curve\n        - ssd_curve\n```\n\n### Example\n\nAn example configuration file including more detailed documentation can be found in [fan2go.yaml](/fan2go.yaml).\n\n### Verify your Configuration\n\nTo check whether your configuration is correct before actually running fan2go you can use:\n\n```shell\n\u003e sudo fan2go config validate\n INFO  Using configuration file at: /etc/fan2go/fan2go.yaml\n SUCCESS  Config looks good! :)\n```\n\nor to validate a specific config file:\n\n```shell\n\u003e fan2go -c \"./my_config.yaml\" config validate\n INFO  Using configuration file at: ./my_config.yaml\n WARNING  Unused curve configuration: m2_first_ssd_curve\n  ERROR   Validation failed: Curve m2_ssd_curve: no curve definition with id 'm2_first_ssd_curve123' found\n```\n\n## Using external commands for sensors/fans\n\nfan2go supports using external executables for use as both sensor input, as well as fan output (and rpm input). There\nare some considerations you should take into account before using this feature though:\n\n### Security\n\nSince fan2go requires root permissions to interact with lm-sensors, executables run by fan2go are also executed as root.\nTo prevent some malicious actor from taking advantage of this fan2go will only allow the execution of files that only\nallow the root user (UID 0) to modify the file.\n\n### Side effects\n\nRunning external commands repeatedly through fan2go can have unintended side effects. F.ex., on a laptop using hybrid\ngraphics, running `nvidia-settings` can cause the dedicated GPU to wake up, resulting in substantial increase in power\nconsumption while on battery. Also, fan2go expects to be able to update sensor values with a minimal delay, so using a\nlong running script or some network call with a long timeout could also cause problems. With great power comes great\nresponsibility, always remember that :)\n\n## Run\n\nAfter successfully verifying your configuration you can launch fan2go from the CLI and make sure the initial setup is\nworking as expected. Assuming you put your configuration file in `/etc/fan2go/fan2go.yaml` run:\n\n```shell\n\u003e fan2go help\nfan2go is a simple daemon that controls the fans\non your computer based on temperature sensors.\n\nUsage:\n  fan2go [flags]\n  fan2go [command]\n\nAvailable Commands:\n  completion  Generate the autocompletion script for the specified shell\n  config      Configuration related commands\n  curve       Curve related commands\n  detect      Detect fans and sensors\n  fan         Fan related commands\n  help        Help about any command\n  sensor      Sensor related commands\n  version     Print the version number of fan2go\n\nFlags:\n  -c, --config string   config file (default is $HOME/.fan2go.yaml)\n  -h, --help            help for fan2go\n      --no-color        Disable all terminal output coloration\n      --no-style        Disable all terminal output styling\n  -v, --verbose         More verbose output\n\nUse \"fan2go [command] --help\" for more information about a command.\n\u003e sudo fan2go\n```\n\nAlternatively you can specify the path to your configuration file like this:\n\n```shell\n\u003e sudo fan2go -c /home/markus/my_fan2go_config.yaml\n```\n\n## As a Service\n\n### Systemd\n\nWhen installing fan2go using a package, it comes with a [systemd unit file](./fan2go.service). To enable it simply run:\n\n```shell\nsudo systemctl daemon-reload\nsudo systemctl enable --now fan2go\n# follow logs\njournalctl -u fan2go -f\n```\n\n\u003e NOTE: If you want to use a config path that differs from the default one, make sure to edit the\n\u003e unit file and point the `-c` flag to the correct path.\n\n## CLI Commands\n\nAlthough fan2go is a fan controller daemon at heart, it also provides some handy cli commands to interact with the\ndevices that you have specified within your config.\n\n### Fans interaction\n\n```shell\n\u003e fan2go fan --id cpu speed 100\n\n\u003e fan2go fan --id cpu speed\n255\n\n\u003e fan2go fan --id cpu rpm\n546\n\n\u003e fan2go fan --id cpu mode\nNo control, 100% all the time (0)\n\n\u003e fan2go fan --id cpu mode auto\nAutomatic control by integrated hardware (2)\n```\n\n### Sensors\n\n```shell\n\u003e fan2go sensor --id cpu_package\n46000\n```\n\n### Print fan curve data\n\nFor each newly configured fan **fan2go** measures its fan curve and stores it in a db for future reference. You can take\na look at this measurement using the following command:\n\n```shell\n\u003e sudo fan2go fan --id cpu curve \ncpu\n                \n  Min PWM    30 \n  Start PWM  30 \n  Max PWM    255\n\nNo fan curve data yet...\n\n\u003e sudo fan2go fan --id in_front curve \nnct6798 -\u003e pwm2\n\n  Min PWM     0 \n  Start PWM   0\n  Max PWM     194\n\n 1994 ┤                                                                          ╭────────────────────────\n 1900 ┤                                                                       ╭──╯\n 1805 ┤                                                                  ╭────╯\n 1711 ┤                                                             ╭────╯\n 1616 ┤                                                        ╭────╯\n 1522 ┤                                                    ╭───╯\n 1427 ┤                                               ╭────╯\n 1333 ┤                                          ╭────╯\n 1238 ┤                                    ╭─────╯\n 1144 ┤                               ╭────╯\n 1049 ┤                         ╭─────╯\n  955 ┤                   ╭─────╯\n  860 ┤             ╭─────╯\n  766 ┤       ╭─────╯\n  671 ┤ ╭─────╯\n  577 ┼─╯\n                                                    RPM / PWM\n```\n\n## Statistics\n\nfan2go has a prometheus exporter built in, which you can use to extract data over time. Simply enable it in your\nconfiguration and you are good to go:\n\n```yaml\nstatistics:\n  # Whether to enable the prometheus exporter or not\n  enabled: true\n  # The port to expose the exporter on\n  port: 9000\n```\n\nYou can then see the metrics on [http://localhost:9000/metrics](http://localhost:9000/metrics) while the fan2go daemon\nis\nrunning.\n\n## API\n\nfan2go comes with a built-in REST Api. This API can be used by third party tools to display (and in the future possibly\nmodify) the state of fans, sensors and curves within fan2go.\n\n```yaml\napi:\n  # Whether to enable the API or not\n  enabled: false\n  # The host to listen for connections\n  host: localhost\n  # The port to listen for connections\n  port: 9001\n```\n\n### Endpoints\n\nCurrently, this API is read-only and only provides REST endpoints. If there is demand for it, this might be expanded to\nalso support realtime\ncommunication via websockets.\n\n#### Fans\n\n| Endpoint    | Type | Description                                       |\n|-------------|------|---------------------------------------------------|\n| `/fan`      | GET  | Returns a list of all currently configured fans   |\n| `/fan/\u003cid\u003e` | GET  | Returns the fan with the given `id`, if it exists |\n\n#### Sensors\n\n| Endpoint       | Type | Description                                          |\n|----------------|------|------------------------------------------------------|\n| `/sensor`      | GET  | Returns a list of all currently configured sensors   |\n| `/sensor/\u003cid\u003e` | GET  | Returns the sensor with the given `id`, if it exists |\n\n#### Curves\n\n| Endpoint      | Type | Description                                         |\n|---------------|------|-----------------------------------------------------|\n| `/curve`      | GET  | Returns a list of all currently configured curves   |\n| `/curve/\u003cid\u003e` | GET  | Returns the curve with the given `id`, if it exists |\n\n# How it works\n\n## Device detection\n\nfan2go uses [gosensors](https://github.com/md14454/gosensors) to directly interact with lm-sensors.\n\n## Initialization\n\nTo properly control a fan which fan2go has not seen before, its RPM curve is analyzed.\n\nfan2go uses an adaptive measurement process instead of sweeping all PWM values:\n\n1. Discover the start boundary (`startPwm`) using boundary search.\n2. Discover the max boundary (`maxPwm`) by scanning and confirming the upper PWM range.\n3. Sample interior points coarsely between these boundaries.\n4. Clean up the measured data by applying threshold-aware filtering, interpolation, monotonic enforcement, and interior\n   smoothing.\n\nThis produces a stable full-range PWM→RPM map while requiring far fewer measurements than a full linear sweep. Runtime\ndepends on fan response characteristics and the analysis config (`analysis.settleTimeout`, `analysis.sampleCount`,\n`analysis.sampleDelay`, and `fanResponseDelay`).\n\nAll of this is saved to a local database (path given by the `dbPath` config option), so it is only needed once per fan\nconfiguration.\n\nTo reduce risk while analyzing multiple fans, you can force fan2go to\ninitialize only one fan at a time, using the `runFanInitializationInParallel: false` config option.\n\nSome PWM controllers or fans may require more time to react to PWM changes. If fan2go is failing to characterize a fan,\nyou can try increasing the fan response delay by passing `--fan-response-delay \u003cseconds\u003e` to the `fan init` command or\nby setting `fanResponseDelay` in the config. The default value is 2 seconds.\n\n## Monitoring\n\nTemperature and RPM sensors are polled continuously at the rate specified by the `tempSensorPollingRate` config option.\n`tempRollingWindowSize`/`rpmRollingWindowSize` amount of measurements are always averaged and stored as the average\nsensor value.\n\n## Fan Controllers\n\nThe speed of a Fan is controlled using a combination of its curve, a control algorithm and the properties of\nthe fan controller itself.\n\nThe curve is used as the target value for the control algorithm to reach. The control algorithm then calculates the\nnext PWM value to apply to the fan to reach this target value. The fan controller then applies this PWM value to the\nfan, while respecting constraints like the minimum and maximum PWM values, as well as the `neverStop` flag.\n\n### Cycle\n\nA **cycle** refers to one iteration of a FanController's main control loop. fan2go creates one FanController per\nconfigured fan, each running its own independent control loop.\n\nDuring each cycle, the FanController:\n\n1. Evaluates the fan's associated curve to determine the target PWM value\n2. Runs the configured control algorithm (Direct or PID) to calculate the next PWM value\n3. Applies constraints such as min/max PWM and the `neverStop` flag\n4. Writes the PWM value to the hardware\n5. Performs sanity checks (e.g. detecting third-party PWM interference)\n\nThe rate at which cycles execute is configured globally via `fanController.adjustmentTickRate` (default: `200ms`):\n\n```yaml\nfanController:\n  # The rate at which fan speed targets are updated\n  adjustmentTickRate: 200ms\n```\n\nThis setting also determines the time unit implied by `maxPwmChangePerCycle` in the Direct control algorithm.\n\n### Control Algorithms\n\nA control algorithm\nis a function that returns the next PWM value to apply based on the target value calculated by the curve. The simplest\ncontrol algorithm is the direct control algorithm, which simply forwards the target value to the fan.\n\n#### Direct Control Algorithm\n\nThe simplest control algorithm is the direct control algorithm. It simply forwards the curve value to the fan\ncontroller.\n\n```yaml\nfans:\n  - id: some_fan\n    ...\n    controlAlgorithm: direct\n```\n\nThis control algorithm can also be used to approach the curve value more slowly:\n\n```yaml\nfans:\n  - id: some_fan\n    ...\n    controlAlgorithm:\n      direct:\n        maxPwmChangePerCycle: 10\n```\n\n### PID Control Algorithm\n\nThe PID control algorithm uses a PID loop to approach the target value. The default\nconfiguration is pretty non-aggressive using the following values:\n\n| P     | I      | D       |\n|-------|--------|---------|\n| `0.3` | `0.02` | `0.005` |\n\nIf you don't like the default behaviour you can configure your own in the config:\n\n```yaml\nfans:\n  - id: some_fan\n    ...\n    controlAlgorithm:\n      pid:\n        p: 0.3\n        i: 0.02\n        d: 0.005\n```\n\nThe loop is advanced at a constant rate, determined by the [cycle rate](#cycle) (`fanController.adjustmentTickRate`),\nwhich defaults to `200ms`.\n\nSee [PID controller on Wikipedia](https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller)\nfor more information on what a PID controller is.\n\n# FAQ\n\n## Why are my SATA HDD drives not detected?\n\n**TL;DR**: `modprobe drivetemp`\n\nWhile _lm-sensors_ doesn't provide temperature sensors of SATA drives by default, you can use the kernel module\n`drivetemp` to enable this. See [here](https://wiki.archlinux.org/title/Lm_sensors#S.M.A.R.T._drive_temperature)\n\n## WARNING: PWM of `\u003cfan\u003e` was changed by third party!\n\nIf you see this log message while running fan2go, fan2go detected a change of the PWM value for the given fan\nthat was not caused by fan2go itself. This usually means that fan2go is not the only program controlling the fan\nand something else (like f.ex. the mainboard or another fan control software) is also running and changing the speed\nof the fan, competing with fan2go. Since fan2go cannot figure out what other software is, you have to investigate\nthis yourself.\n\nAnother common reason this message can occur is when the driver of the fan in question does not actually support\nsetting the PWM directly and uses some kind of virtual PWM instead. This has been a problem mostly on AMD graphics\ncards but is probably not limited to them. See #64 for more detail.\n\nIf you are sure that this warning is not justified, you can disable this check on a per-fan basis.\nSee the `sanityCheck` section in the [fan configuration](#advanced-options) for more details.\n\n## My components are overheating during initialization, what can I do about this?\n\n**TL;DR**: Skip the initialization and configure your fans manually.\n\nThe initialization phase measures the RPM curve of each fan and tries to estimate the minimum and maximum\nboundaries. This can take quite a while though and can lead to overheating of components if they are\nunder load. To avoid this use the `minPwm` and `maxPwm` fan config options to set the boundaries yourself.\nThat way the initialization phase will be skipped and the control algorithm will start right away.\n\n# Dependencies\n\nSee [go.mod](go.mod)\n\n# Similar Projects\n\n* [nbfc-linux](https://github.com/nbfc-linux/nbfc-linux)\n* [thinkfan](https://github.com/vmatare/thinkfan)\n\n# License\n\n```\nfan2go\nCopyright (C) 2021  Markus Ressel\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusressel%2Ffan2go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkusressel%2Ffan2go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusressel%2Ffan2go/lists"}