High-Performance ASUS VivoBook & ZenBook Thermal, Dynamic Fan Curve, and Battery Care Management Suite for Linux.
KühlerProfil is a lightweight, zero-bloat system utility tailored specifically for ASUS laptops running Linux. Written entirely in pure Go with a companion GNOME Shell 45+ Quick Settings extension, KühlerProfil gives you seamless control over ASUS hardware thermal profiles, dual-fan RPM monitoring, automated thermal curve hysteresis, and hardware battery charge health limiting (60% / 80% / 100%).
- Key Features
- Architecture Overview
- Hardware Safety & Thermal Architecture
- Supported Hardware & Models
- Quick Start & Installation
- CLI Reference
- Interactive TUI Dashboard
- GNOME Shell Quick Settings Extension
- Configuration Reference
- D-Bus IPC API Specification
- Troubleshooting & Diagnostics
- Contributing
- License
- Hardware Thermal Profiles: Instant switching between ASUS hardware modes (
Silent,Standard,Boost) viaasus-nb-wmisysfs and Linux ACPI platform profiles. - ASUS Battery Care Health Limiter: Protect lithium-ion health by locking battery charge threshold to 60%, 80%, or 100% (
charge_control_end_threshold). - Dynamic Auto-Governor: Intelligent hysteresis thermal governor that steps thermal profiles up under sustained load and safely steps them down when cool, eliminating noisy fan hunting.
- Real-time Dual Fan & CPU Telemetry: Non-blocking asynchronous sampling of CPU package temperature and primary/secondary fan RPMs via Linux
hwmon. - Interactive Bubbletea TUI: Gorgeous terminal dashboard with real-time ASCII telemetry gauges, battery status bars, and responsive single-key controls.
- GNOME Shell 45+ Quick Settings: Native GNOME top-bar integration with live telemetry subtitle, symbolic icons, and quick-toggle menu cards.
- Security-Hardened D-Bus IPC: Centralized
kuhlerprofilddaemon running overorg.freedesktop.kuhlerprofilsystem bus with polkit/D-Bus security policies allowing unprivileged desktop clients. - 100% Mockable & Tested: Zero required external C dependencies with fully mockable sysfs layers for deterministic unit and race testing.
flowchart TD
subgraph Hardware ["Kernel & Sysfs Layer"]
SYSFS_THROTTLE["/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"]
SYSFS_BATTERY["/sys/class/power_supply/BAT0/charge_control_end_threshold"]
SYSFS_HWMON["/sys/class/hwmon/hwmon* (CPU Temp, Fan 1 & 2 RPM)"]
end
subgraph CoreDaemon ["kuhlerprofild Background Service"]
DRIVER["pkg/driver: Hardware Sysfs Driver"]
ENGINE["pkg/engine: Telemetry Engine & Auto-Governor"]
CONFIG["pkg/config: TOML Config Manager"]
DBUS_SERVER["pkg/dbusapi: D-Bus IPC Server"]
SYSFS_THROTTLE <--> DRIVER
SYSFS_BATTERY <--> DRIVER
SYSFS_HWMON --> DRIVER
DRIVER <--> ENGINE
CONFIG <--> ENGINE
ENGINE <--> DBUS_SERVER
end
subgraph Clients ["User Interfaces & Clients"]
DBUS_BUS["System D-Bus: org.freedesktop.kuhlerprofil"]
CLI["cmd/kuhlerprofil: Cobra CLI (aliases: kp, kuhler)"]
TUI["pkg/tui: Bubbletea Terminal Dashboard"]
GNOME_EXT["extension: GNOME Shell Quick Settings"]
DBUS_SERVER <==> DBUS_BUS
DBUS_BUS <==> CLI
DBUS_BUS <==> TUI
DBUS_BUS <==> GNOME_EXT
end
When managing system thermals, fan curves, and power thresholds on Linux, hardware safety and transparency are paramount. KühlerProfil is designed to be completely non-destructive and failsafe by design.
- No Direct Register or Port Bypasses: KühlerProfil does not write to raw memory registers, raw I/O ports (
/dev/port), or bypass EC firmware safety trips with forced PWM voltage overrides. - Kernel-Standard Driver Communication: All thermal mode operations interface strictly through the official Linux kernel driver:
(with standard fallbacks to
/sys/devices/platform/asus-nb-wmi/throttle_thermal_policyfan_boost_modeand ACPIplatform_profile). - Vendor Thermal Tables: This interface corresponds directly to ASUS's built-in Embedded Controller (EC) profile tables (equivalent to pressing
Fn + Fon your keyboard or toggling modes in ASUS Armoury Crate / MyASUS on Windows):0: Standard / Balanced1: Boost / Performance2: Silent / Whisper
- Emergency Hardware Overrides Remain Active: Modern AMD and Intel ASUS laptops enforce autonomous safety fuses at the silicon level. If CPU/GPU package temperatures spike toward dangerous trip points (e.g., 90°C–95°C), the laptop's hardware EC firmware and CPU hardware thermal trip (BD PROCHOT) will always automatically override any user-space profile to spin fans to maximum RPM or throttle CPU clocks, preventing heat damage even if KühlerProfil is active in "Silent" mode.
- Strict Input Validation: Writes to
/sys/class/power_supply/BAT*/charge_control_end_thresholdare strictly validated before any sysfs operation occurs. Only the manufacturer-supported thresholds (60%, 80%, and 100%) are accepted. - Hardware-Managed Charging: This threshold communicates directly with the battery management IC on the motherboard to stop charging when the set capacity is reached. It does not stress the battery cells; keeping lithium-ion batteries capped at 60% or 80% while connected to AC power significantly mitigates degradation and prolongs battery lifespan.
Before deploying the background daemon, users can non-destructively probe their system without root privileges using the built-in dry-run diagnostic:
./bin/kuhlerprofild -dry-run
# or
make dry-runThis inspects and reports detected kernel endpoints, hwmon sensor channels, and battery controls before any daemon operations are initiated.
KühlerProfil supports ASUS laptops featuring the asus_nb_wmi or asus_wmi kernel module, as well as laptops supporting Linux ACPI platform profiles:
- ASUS VivoBook Series:
- VivoBook S14 / S15 / S16 (K5404, S5404, M5402, M5502, S533, etc.)
- VivoBook Pro 14 / 15 / 16 OLED (K3400, K3500, K3502, K6502, N7600)
- VivoBook Go 14 / 15, Flip 14
- VivoBook 15 / 17 (X512, X515, M515, X712)
- ASUS ZenBook Series:
- ZenBook 13 / 14 / 15 / Flip / Duo (UX325, UX425, UX434, UX482, UM425, etc.)
- ZenBook Pro 14 / 16 OLED
- ASUS ROG & TUF Series (Thermal mode & battery limiter compatibility):
- ROG Zephyrus G14, G15, G16, M16
- ASUS TUF Gaming A15, A16, F15, F17
- ROG Flow X13, Z13, X16
Kernel Requirement: Linux 5.15+ (Linux 6.2+ recommended for complete multi-fan hwmon support).
Ensure you have the standard build toolchain installed on your Linux distribution:
- Go: Version 1.22 or higher
- Make: Standard GNU Make
- D-Bus & systemd: Standard on Fedora, Ubuntu, Debian, Arch Linux, openSUSE, etc.
- Node.js (optional, for running extension tests)
sudo dnf install golang make dbus-develsudo apt update && sudo apt install -y golang make dbussudo pacman -S go make# 1. Clone the repository
git clone https://github.com/katon26/kuhler-profil.git
cd kuhler-profil
# 2. Compile both binaries (CLI & Daemon)
make build
# 3. Install daemon, CLI, symlinks (kp, kuhler), systemd service, and D-Bus policy (requires root)
sudo make install
# 4. Reload systemd & D-Bus, then enable the daemon
sudo systemctl daemon-reload
sudo systemctl reload dbus
sudo systemctl enable --now kuhlerprofil.serviceVerify the daemon is running properly:
systemctl status kuhlerprofil.service
kp status
# or:
kuhlerprofil statusTo install the KühlerProfil Quick Settings menu for GNOME 45, 46, 47, 48, 49, 50:
# Install extension to ~/.local/share/gnome-shell/extensions/
make install-extension
# If running Wayland, log out and log back in, or enable directly:
gnome-extensions enable kuhlerprofil@katon26.github.ioPre-built distribution packages can be generated directly using the build automation suite:
# Build Debian/Ubuntu (.deb) binary package
make package-deb
# Build Fedora/RHEL (.rpm) spec and archive
make package-rpm
# Build and validate Arch Linux (PKGBUILD) package
make package-arch
# Build all packages simultaneously (including GNOME Shell ZIP)
make package-allGenerated packages are placed into the dist/ directory:
- Debian / Ubuntu:
dist/kuhlerprofil_0.1.0_amd64.deb(sudo dpkg -i dist/kuhlerprofil_0.1.0_amd64.deb) - Fedora / RHEL:
packaging/rpm/kuhlerprofil.spec - Arch Linux:
packaging/arch/PKGBUILD(cd packaging/arch && makepkg -si) - GNOME Shell Extension:
dist/kuhlerprofil@katon26.github.io.shell-extension.zip
The kuhlerprofil CLI (and convenient kp short alias) provides full control over hardware profiles, battery thresholds, governor settings, and telemetry output.
Both kuhlerprofil and kp (as well as kuhler) are symlinked and can be used interchangeably:
# Human-readable dashboard summary
kp status
# or:
kuhlerprofil status
# Machine-readable JSON output (ideal for scripts, Waybar, Polybar, Conky)
kp status --jsonJSON Output Example:
{
"cpu_temp": 52.4,
"fan1_rpm": 2400,
"fan2_rpm": 0,
"battery_percent": 79,
"battery_limit": 80,
"on_ac": true,
"active_mode": "standard",
"auto_mode": false
}# View active profile
kp mode
# Set thermal mode: silent (whisper quiet), standard (balanced), boost (max cooling)
kp mode silent
kp mode standard
kp mode boost# View active charge limit
kp battery
# Set battery charging limit to 60%, 80%, or 100%
kp battery 60
kp battery 80
kp battery 100# Query auto governor status
kp auto
# Enable / disable dynamic thermal curve governor
kp auto on
kp auto off
# Enable auto governor with a specific curve profile
kp auto on --profile quietQuery or set active temperature-to-fan curve profiles:
# View active curve profile and hardware ACPI support status
kp curve
# List all available curve profiles
kp curve list
# Switch to a curve profile: quiet, balanced, aggressive, or custom
kp curve set quiet
kp curve set balanced
kp curve set aggressive# Launch full-screen interactive dashboard
kp tui
# or simply:
kp
# or:
kuhlerprofilKühlerProfil includes a responsive terminal UI powered by Bubbletea and Lipgloss.
Run:
kp tui
# or simply:
kp┌──────────────────────── KühlerProfil ASUS Control ─────────────────────────┐
│ Profile: [ STANDARD ] Governor: [ OFF ] Power: [ AC Power ]│
├────────────────────────────────────────────────────────────────────────────┤
│ CPU Temperature: 54.0°C [██████████████████░░░░░░░░░░░░░░░░░░░░░░░░] │
│ Fan 1 (CPU): 2400 RPM [████████████████████████░░░░░░░░░░░░░░░░░░] │
│ Fan 2 (GPU): 0 RPM [░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░] │
│ Battery Health: 78% [█████████████████████████████████░░░] Limit: 80%│
├────────────────────────────────────────────────────────────────────────────┤
│ [1] Silent [2] Standard [3] Boost [B] Cycle Battery Limit │
│ [A] Auto-Curve Governor [R] Refresh [Q/Esc] Quit │
└────────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
1 |
Switch to Silent mode (ASUS Quiet / Whisper profile) |
2 |
Switch to Standard mode (ASUS Balanced profile) |
3 |
Switch to Boost mode (ASUS Performance / Overboost profile) |
b / B |
Cycle Battery Charge Limit (60% ➔ 80% ➔ 100%) |
a / A |
Toggle Dynamic Auto-Governor (ON / OFF) |
r / R |
Force immediate telemetry refresh |
q / Esc / Ctrl+C |
Quit TUI |
The GNOME Shell extension integrates directly into the Quick Settings menu on GNOME 45, 46, 47, and 48+:
- Top Bar Indicator: Displays active profile icon and live subtitle metric (e.g.
Standard · 52°C · 2400 RPM). - Telemetry Cards: Real-time 2x2 grid showing CPU Temperature, Battery Charge, Fan 1 RPM, and Fan 2 RPM.
- One-Click Controls: Toggle Silent / Standard / Boost, set 60% / 80% / 100% battery caps, and toggle auto-governor.
- Asynchronous D-Bus: Zero UI freezing, event-driven updates via D-Bus signal subscriptions.
# Package extension for distribution
make extension-pack
# Install from local directory
make install-extensionConfiguration files are loaded from /etc/kuhlerprofil/config.toml (system-wide) or ~/.config/kuhlerprofil/config.toml (user-level override).
# /etc/kuhlerprofil/config.toml
# Default ASUS thermal profile on daemon boot: "silent", "standard", or "boost"
default_mode = "standard"
# Default battery charge health limit percentage: 60, 80, or 100
default_battery_limit = 80
# Hardware telemetry sensor polling interval in milliseconds
poll_interval_ms = 1500
# Enable automated dynamic thermal curve hysteresis governor
auto_curve = false
# Thermal governor hysteresis thresholds (Celsius)
hysteresis_step_up_temp = 75.0 # Temperature to step Standard -> Boost
hysteresis_step_down_temp = 55.0 # Temperature to step Boost -> Standard / SilentThe kuhlerprofild daemon registers on the Linux System Bus:
- Service Name:
org.freedesktop.kuhlerprofil - Object Path:
/org/freedesktop/kuhlerprofil - Interface:
org.freedesktop.kuhlerprofil
| Method | Signature | Description |
|---|---|---|
GetStatus |
() -> (a{sv}) |
Returns a dictionary containing all real-time telemetry metrics. |
SetThermalMode |
(s) -> () |
Sets active thermal mode ("silent", "standard", or "boost"). |
SetBatteryLimit |
(i) -> () |
Sets battery health charging threshold (60, 80, or 100). |
SetAutoMode |
(b) -> () |
Enables (true) or disables (false) dynamic auto-governor. |
| Signal | Signature | Description |
|---|---|---|
ThermalModeChanged |
(s) |
Emitted when thermal mode changes with new mode name. |
BatteryLimitChanged |
(i) |
Emitted when battery charge limit threshold is updated. |
TelemetryTick |
(a{sv}) |
Broadcast on every telemetry polling cycle with updated values. |
# Query status dictionary
busctl call org.freedesktop.kuhlerprofil /org/freedesktop/kuhlerprofil org.freedesktop.kuhlerprofil GetStatus
# Set thermal mode to boost
busctl call org.freedesktop.kuhlerprofil /org/freedesktop/kuhlerprofil org.freedesktop.kuhlerprofil SetThermalMode s "boost"
# Set battery limit to 80%
busctl call org.freedesktop.kuhlerprofil /org/freedesktop/kuhlerprofil org.freedesktop.kuhlerprofil SetBatteryLimit i 80Run a capability dry-run to inspect detected sysfs endpoints without needing root privileges:
make dry-run
# or:
./bin/kuhlerprofild -dry-runExpected Output:
[kuhlerprofild] Hardware capability probe:
[kuhlerprofild] • Thermal mode control: true (policy: true, boost: false, profile: false, path: /sys/devices/platform/asus-nb-wmi/throttle_thermal_policy)
[kuhlerprofild] • Battery charge limiter: true (path: /sys/class/power_supply/BAT0/charge_control_end_threshold)
[kuhlerprofild] • Telemetry sensors: CPU temp=true, Fan1=true, Fan2=false (hwmon: /sys/class/hwmon/hwmon0)
Ensure asus_nb_wmi or asus_wmi is loaded in your Linux kernel:
lsmod | grep asusIf not loaded, check modprobe:
sudo modprobe asus_nb_wmiEnsure /etc/dbus-1/system.d/org.freedesktop.kuhlerprofil.conf exists and D-Bus is reloaded (sudo systemctl reload dbus).
Run all unit tests and race condition checks:
# Run unit test suite
make test
# Run Go race detector (checks for concurrency issues)
make test-race
# Run GNOME extension automated tests
make test-extension
# Run complete verification suite (race tests + extension tests)
make test-allProbe your laptop's real sensors and ACPI interfaces without root or system changes:
make dry-run
# or
./bin/kuhlerprofild -dry-runTo test the daemon and CLI locally in real-time:
# Terminal 1: Run the daemon in foreground (requires sudo for sysfs access)
sudo ./bin/kuhlerprofild
# Terminal 2: Test commands against the running daemon
./bin/kuhlerprofil status
./bin/kuhlerprofil curve list
./bin/kuhlerprofil curve set quiet
./bin/kuhlerprofil tuiContributions are welcome! KühlerProfil is an open-source project designed for Linux laptop enthusiasts.
- Fork the repository on GitHub.
- Create a feature branch (
git checkout -b feature/amazing-feature). - Commit your changes (
git commit -m 'feat: my cool feature'). - Ensure all tests pass (
make test-all). - Open a Pull Request.
- Custom multi-point RPM fan curve profiles (Dual-Path ACPI & Software Governor)
- Zero-RPM cooldown recovery governor (Instant Reset / Cooldown Decay)
- Packaging & Distribution: Add .deb, .rpm, or Arch Linux PKGBUILD scripts to prepare for publishing
- ROG keyboard RGB backlight integration (
asus::kbd_backlight) - Waybar & Polybar native integration scripts
- KDE Plasma 6 Quick Settings Widget
KühlerProfil is open-source software licensed under the MIT License.