Framework Control (Linux/Windows) - A tool for: Fan Control (Curve), Sensors, Power Control, Battery Information

Thanks! This is great software! Was using this on Windows, now can also use it on my Arch!

Here is a package (binary version, no rebuild) for Arch in AUR: AUR (en) - framework-control-bin

1 Like

Ahaa, you put us on the map in AUR! :raising_hands:
I’ll work on getting up a build from source version. Probably will want to automate both in the future through GH Actions

I was trying to figure out how to update to the new version, when I found out that it was already up to date! Remarkable! I’m not sure if that’s because it auto-updates itself, or if it’s because I ran system updates the other day, but either way that was pretty seamless!

This project seems to have a level of polish uncharacteristic of community software.

1 Like

The only way it would auto update would be if you toggled the auto update in the settings inside the app. Please let me know if not.

Thank you for the kind words, I’m known to be a slow but reliable dev :wink:.

1 Like

Ah, yup. I do

1 Like

@Kemal_Ozturk

Love the tool! It looks like I found a minor issue in Fedora.

It seems that setting the EPP profile will fight against tuned-ppd settings. For example, when I have my power profile set to “balanced” and EPP set to “power” - the tuned profile seems to honor what I have set in the gnome settings.

This is word-vomit to try and explain - but in gnome (at least with Fedora), tuned-ppd handles the “power settings” in the gui. You can use this command to get the value:

gdbus call --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles --method org.freedesktop.DBus.Properties.Get net.hadess.PowerProfiles ActiveProfile

When I set Framework-Control’s energy preference to any value (power for example) it is initally honored:

cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference
power

But, If I chance my power profile in gnome, for example to performance, and back to balanced, the EPP will also fall back to the “balanced” preset and does not honor the value set in Framework-Control:

cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference
balance_performance

I know that was a shit way to try and explain all this - if I need to clarify anywhere - please let me know. I did run the above through my LLM to have it help try and make more sense:


EPP setting is overridden by tuned-ppd on power profile changes

On Fedora (43+), GNOME’s power profile dropdown is backed by tuned-ppd, which translates the three PPD profiles (balanced, power-saver, performance) into tuned profiles. Each tuned profile sets its own energy_performance_preference (EPP) value on all CPUs.

When Framework Control sets an EPP value (e.g. power), it is applied correctly. However, any subsequent power profile change in GNOME — even toggling away and back to the same profile — causes tuned-ppd to reapply its own EPP value, overwriting what Framework Control set.

Steps to reproduce:

  1. In Framework Control, set battery EPP to power
  2. Confirm: cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference → power
  3. In GNOME Settings > Power, switch to “Performance”, then back to “Balanced”
  4. Check again: EPP is now balance_power (tuned’s default for balanced-battery), not power

Root cause: Both Framework Control and tuned write to the same sysfs file (energy_performance_preference). Whichever writes last wins, and tuned reapplies on every profile switch.

Possible solutions:
• Framework Control could listen for net.hadess.PowerProfiles D-Bus PropertiesChanged signals and reapply its EPP setting after tuned-ppd finishes a profile switch
• Document that users should disable EPP in Framework Control if they rely on tuned-ppd profiles, or vice versa

1 Like

One more observation - and this one may be intentional - but Im not certain:

Charge rate threshold appears inverted

When charge_rate_c is set to 0.25 with charge_rate_soc_threshold_pct at 70, the 0.25C limit is applied when SoC is below 70% rather than above it.

Observed behavior:
• SoC at 64%, charge rate is 0.25C (1.369A) — limited
• Expected: full-speed charging below 70%, 0.25C limit only above 70%

Confirmed via:
Additionally, on service restart, the charge_rate_c value is written to the EC immediately without checking SoC against the threshold — so even if the runtime logic is correct, a restart at low SoC will still apply the limit prematurely.

1 Like

Hey @knipp30 welcome to the thread. Good observations!

For the OS power setting clash:
I’m not sure if I will have time to implement specific logic for each distro/power-config but this is something I knew that could cause some friction in some distros or with some power management daemons. In my app, the power apply logic is very patient. It allows the OS to do its thing, and if it detects a change, it waits for a while until things are quiet to change it back again.

If the distro/OS is aggressively setting the power governor or epp, it’s best to keep the framework-control one disabled and only use the top bar as a “read-only” feature. Not sure where would be the best place to document this…

For the SoC ask:
There might be a bug there, please feel free to create an issue on GitHub, even if not, I will eventually fix it. Thanks for the feedback!

1 Like

What I liked about RyzenAdj rather than the other options is that I could manually set my own preferred TDP target. That’s useful for fitting within the constraints of whatever PSU I happen to have plugged in, as well as making sure the thermals stay below what they need to.

What kind of issues did you run into when using RyzenAdj? I haven’t actually used it much, partly because it’s a pain to remember the commands and adjust my numeric values to mW or whatever it is they use.

I have a bug where it seems to be unable to read my fw laptop’s temperature sensors? I can confirm there are sensors that work with HWMonitor, but this program can’t pick it up. If anyone’s seen this issue, any help would be appreciated <3

It actually looks like the only thing that’s working is the fan control. Perhaps this is because you’re on a FW 13 instead of 16? Idk if it’s been tested on a 13 yet.

I’ve tried setting my fan control but I’m not even sure if it works due to the undefined C in the top left of that panel

I’m assuming you’re not able to click the “sensors” and select them right?

Also, it says “bad gateway” in the bottom. Maybe the framework_tool is outdated or something?

Could you try uninstalling the framework_tool from “apps” in settings if it’s there and restarting?

Finally, do you have logs when you go into settings?

Updated! If you’d like I could move it to General? Let me know if you have a preference on a category and I’ll update it.

1 Like

Either General or Creators & Developers would work. I’ll leave it up to you to decide where it fits better. Thank you!

Ill try and get some time to file an issue on your github this week. Probably start with just the base SoC statement for tracking - any data you need once there, just let me know!

No rush at all, the tool overall is amazing and very well done - I definitely get needing a break to focus on other things in life :slight_smile:

Updated, I also removed the Framework Laptop 16 tag, but I can add others if you think they fit.

1 Like

Hi Kemal,

Thanks for keeping the updates coming. However it looks like the update broke some functionality on my FW16.

I did a complete wipe & reinstall, and FW control worked after that, however since the 0.5.1 update the TDP control doesn’t work on the ‘local’ page, but it does work through the ‘online’ page (Framework Control).

On the local page I can’t install ryzenadj:

I already whitelisted the entire C:\Program Files\FrameworkControl folder in defender, but no change.

Log does throw an error (this is after pressing ‘install’

Do you have any idea what the cause might be?

Thanks!

Correct, the menus are empty, but I didn’t want to send a ton of screenshots with every dropdown open

It says its fully updated to 0.5.1 (I recently downloaded this), and even after a reinstall its showing the same data

Sure! I can post them

called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::telemetrye[0me[2m:e[0m telemetry read failed: exit exit code: 101: [ERROR] Failed to find Windows driver. Error { code: HRESULT(0x80070002), message: “The system cannot find the file specified.” }
[ERROR] Failed to communicate with EC. Reason: “Failed to initialize”

thread ‘main’ (16008) panicked at framework_lib\src\power.rs:356:61:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::telemetrye[0me[2m:e[0m telemetry read failed: exit exit code: 101: [ERROR] Failed to find Windows driver. Error { code: HRESULT(0x80070002), message: “The system cannot find the file specified.” }
[ERROR] Failed to communicate with EC. Reason: “Failed to initialize”

thread ‘main’ (28008) panicked at framework_lib\src\power.rs:356:61:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::fan_curvee[0me[2m:e[0m Failed to select temperature, continuing…
e[33m WARNe[0m e[2mframework_control_service::tasks::telemetrye[0me[2m:e[0m telemetry read failed: exit exit code: 101: [ERROR] Failed to find Windows driver. Error { code: HRESULT(0x80070002), message: “The system cannot find the file specified.” }
[ERROR] Failed to communicate with EC. Reason: “Failed to initialize”

It repeats this a lot ^

1 Like

you have intel based FW13 it is not supported by framework-tool in windows

1 Like