fw-fanctrl
fw-fanctrl is a Python CLI service for Linux that controls Framework Laptop fan speed according to a configurable speed/temperature curve. Developed by community member Jean (GitHub: TamtamHero), it was originally created in April 2022 to address the overly aggressive default fan behaviour on the Framework Laptop 13 Intel, which many users found too loud for light workloads12.
Under the hood, fw-fanctrl uses ectool (by DHowett) to communicate with Framework's Embedded Controller (EC), overriding the built-in fan curve with user-defined strategies2. It is compatible with all Framework Laptop 13 and 16 models, both AMD and Intel CPUs, with or without a discrete GPU2. When the service is stopped or paused, fans revert to their default behaviour2.
How It Works
fw-fanctrl reads CPU temperature sensors, computes a moving average to smooth out spikes, interpolates the corresponding fan speed from the active strategy's speed curve, and sends the duty percentage to the EC via ectool fanduty. The service runs as a systemd daemon and communicates with CLI commands through a Unix socket2.
Temperature Pipeline
- Sensor reading — CPU temperature is read from
lm-sensors/hwmon - Moving average — temperature is averaged over a configurable window (default 20 seconds) to prevent rapid fan oscillation
- Curve interpolation — the averaged temperature is mapped to a fan speed percentage via the active strategy's speed curve
- EC command —
ectool fanduty <percentage>sets the fan duty cycle
Features
| Feature | Details |
|---|---|
| Language | Python (≥ 3.12) |
| EC communication | ectool (DHowett's build) |
| Speed curve | Configurable multi-point temperature→speed mapping (0.01°C precision) |
| Strategies | Multiple named fan profiles, switchable at runtime via CLI |
| AC/battery profiles | Separate strategies for charging vs discharging |
| Moving average | Configurable smoothing window (1–100 seconds) |
| Update frequency | Configurable adjustment interval (1–10 seconds) |
| Suspend support | Fan properly stopped on sleep/resume |
| Service | systemd daemon with socket-based IPC |
| Supported models | FW13 Intel (11th–13th gen), FW13 AMD (7040, AI 300), FW16 AMD (with/without dGPU) |
Installation
Dependencies
| Dependency | Version | Notes |
|---|---|---|
| Linux kernel | ≥ 6.11.x | Required for EC access |
| Python | ≥ 3.12.x | |
| ectool | DHowett build #899 | Downloaded automatically by install script |
| lm-sensors | any | CPU temperature readings |
Install Script (Generic Linux)
git clone https://github.com/TamtamHero/fw-fanctrl.git
cd fw-fanctrl
sudo ./install.sh
The install script downloads ectool, installs the Python package, creates the systemd service, and enables it2.
Distribution Packages
| Distribution | Package |
|---|---|
| Arch Linux | AUR: fw-fanctrl or fw-fanctrl-git |
| NixOS (≤ 25.04) | Flake |
| NixOS (Unstable) | nixpkgs: fw-fanctrl |
| Fedora / RPM | COPR |
Configuration
Configuration is stored in /etc/fw-fanctrl/config.json3.
Built-in Strategies
The default configuration includes several strategies ranked from quietest to most aggressive3:
| Strategy | Description |
|---|---|
lazy | Very quiet; fan off until high temperature |
quiet | Low fan speeds with slow ramp-up |
medium | Balanced comfort and cooling |
agile | Faster response to temperature changes |
very-agile | Rapid fan response |
Custom Strategy Example
{
"strategies": {
"my-custom": {
"fanSpeedUpdateFrequency": 5,
"movingAverageInterval": 30,
"speedCurve": [
{ "temp": 0, "speed": 0 },
{ "temp": 45, "speed": 0 },
{ "temp": 55, "speed": 15 },
{ "temp": 65, "speed": 30 },
{ "temp": 75, "speed": 60 },
{ "temp": 85, "speed": 100 }
]
}
},
"defaultStrategy": "my-custom",
"strategyOnDischarging": "lazy"
}
Strategy Parameters
| Parameter | Default | Range | Description |
|---|---|---|---|
speedCurve | (required) | ≥ 1 point | Array of {temp, speed} objects defining the fan curve |
fanSpeedUpdateFrequency | 5 | 1–10 | Seconds between fan speed adjustments |
movingAverageInterval | 20 | 1–100 | Seconds over which temperature is averaged |
AC/Battery Profiles
The defaultStrategy is used on AC power, while strategyOnDischarging activates automatically on battery. This allows quieter operation when mobile (more heat, less noise, better battery) and more aggressive cooling when plugged in3.
CLI Commands
fw-fanctrl lazy # Switch to "lazy" strategy temporarily
fw-fanctrl medium # Switch to "medium" strategy
fw-fanctrl reload # Reload config from disk
fw-fanctrl pause # Pause service (fans revert to EC default)
fw-fanctrl resume # Resume service
fw-fanctrl reset # Reset to default strategy from config
Version History
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | February 2025 | Major rewrite; socket-based IPC, JSON config schema, strategy live-switching |
| 1.0.1 | April 2025 | Auto tag and release CI |
| 1.0.3 | April 2025 | Script installation path fixes |
| 1.0.4 | September 2025 | Version bump |
Development Milestones
- April 2022 — Initial release as ~100-line Python script for FW13 Intel1
- October 2022 — Live strategy switching via CLI, suspend/resume fix1
- November 2022 — 12th-gen Intel CPU temperature fix1
- June 2023 — Cinnamon applet by not-a-feature1
- March 2024 — AMD and Framework 16 support (dual-fan, dGPU), contributed by hasechris1
- June 2024 — GNOME Shell extension by joax; cross-DE tray UI by Wai1
- February 2025 — v1.0.0 release with major rewrite (socket IPC, JSON schema, modular architecture) | | September 2025 — v1.0.4, latest release |
Third-Party Projects
Multiple community projects have been built on top of fw-fanctrl to provide GUI frontends2:
| Project | Description |
|---|---|
| fw-fanctrl-gui | Customtkinter Python GUI with system tray (by leopoldhub) |
| fw-fanctrl-revived-gnome-shell-extension | GNOME Shell quick settings integration (by ghostdevv) |
| fw_fanctrl_applet | Cinnamon desktop applet (by not-a-feature) |
| fw-fanctrl-ui | Cross-DE tray icon UI (by Wai, available on AUR) |
| ulauncher-fw-fanctrl | Ulauncher extension for quick strategy switching |
Related Projects
| Project | Description |
|---|---|
| DHowett/ectool | Embedded Controller tool for Framework laptops |
| Framework Fan Control GNOME Extension | GNOME Shell extension for fw-fanctrl |
| YAFI | GTK4 GUI with EC fan set-point control |
| Framework Deck | All-in-one Tauri desktop companion with fan control |
Technical Details
| Detail | Value |
|---|---|
| License | BSD 3-Clause2 |
| Stars | 4252 |
| Forks | 582 |
| Contributors | 20 (top: TamtamHero, leopoldhub, Svenum, emrebicer)2 |
| Releases | 4 (latest: v1.0.4, September 2025)2 |
| Created | April 4, 20222 |
| Community thread | 27 replies, 14,000+ views (thread #17208)1 |