Power Mode based on Charging Status

Since power modes were introduced in Gnome, there is now the option to change between Power Saver, Balanced, and Performance mode manually in the drop down menu. This is a welcome integration in Gnome! However, I’ve had a number of times where I’ve undocked my laptop for a meeting and set it to Power Saver, came back, docked it, and wondered why my compiles were taking so long only to then remember I hadn’t switched back to Performance mode.

Is there any way to set it to automatically default to Power Saver mode when switching to battery power and default back to Performance when docked or on A/C power?

2 Likes

Yes this is a issue i have seen but it is not a bug i think but it can be a feature request.

I understand that a GUI solution isn’t available, but I’m wondering if there may be a way in the meantime to set this based on an ACPI event for power source change triggering powerprofilesctl?

The ‘tlp’ package can do this, along with many other useful things.

It looks like upowerd is detecting the change when I dock. I assume there’s probably some way to hook powerprofilesctl based on that detection from upowerd.

You may want to investigate ‘tlp’ anyway; it can also manage charging thresholds to improve the lifetime of your battery, and with the ‘tlp-rdw’ package it can manage switching between wired and wireless networks smoothly.

It looks like upowerd can be read from dbus and power-profiles-daemon ships with a dbus integration: /etc/dbus-1/system.d/net.hadess.PowerProfiles.conf

I’m just not sure how to connect the two events so that when upowerd detects a change, it can trigger a power profile change via dbus.

I’d really like to find a way using the native Gnome tools since I still want to be able to simply override it on demand. I’ve used other profiling methods in the past. I really want to find a way to make this one work better for me.

So I can get the status from upower from dbus with this call:

dbus-send --print-reply=literal --system --dest=org.freedesktop.UPower /org/freedesktop/UPower/devices/battery_BAT0 org.freedesktop.DBus.Properties.Get  string:org.freedesktop.UPower.Device string:State | awk '{ print $3; }'

A value of 1 or 4 should trigger Performance and any other value should trigger Power Saver based on the Upowerd DBUS documentation.

Based on the power-profiles-daemon docs, the level could then be updated via dbus with:

gdbus call --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles --method org.freedesktop.DBus.Properties.Set 'net.hadess.PowerProfiles' 'ActiveProfile' "<'power-saver'>"

I could write a script to continuously poll this and wrap it in systemd, but I’d much rather there be a way to trigger it via dbus on a change in state of that value and that’s the part I’m currently missing.

I’m not sure if this is the proper way to do this, but it looks like I could write a systemd service to parse a readline out of this to trigger the power profile switch event:

dbus-monitor --system "type='signal',path='/org/freedesktop/UPower/devices/battery_BAT0',member='PropertiesChanged'"

Here’s what I came up with in case it’s helpful for anyone else. Obviously, use at your own risk.

EDIT- I updated it to work for machines that don’t support “performance” mode.

#!/bin/bash

dbus-monitor --system "type='signal',path='/org/freedesktop/UPower/devices/battery_BAT0',member='PropertiesChanged'" | while read LINE; do
    echo ${LINE} | grep battery_BAT0 | grep PropertiesChanged
    if [ $? -eq 0 ]; then
        BATT_STAT=$(dbus-send --print-reply=literal --system --dest=org.freedesktop.UPower /org/freedesktop/UPower/devices/battery_BAT0 org.freedesktop.DBus.Properties.Get  string:org.freedesktop.UPower.Device string:State | awk '{ print $3; }')
        if [ $BATT_STAT -eq 1 ] || [ $BATT_STAT -eq 4 ]; then
            LEVEL=$(powerprofilesctl list | grep -q performance && echo "performance" || echo "balanced")
        elif [ $BATT_STAT -eq 5 ]; then
            LEVEL="balanced"
        else
            LEVEL="power-saver"
        fi
	echo "Changing power level to ${LEVEL}"
	gdbus call --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles --method org.freedesktop.DBus.Properties.Set 'net.hadess.PowerProfiles' 'ActiveProfile' "<'${LEVEL}'>"
    fi
done

5 Likes

Glad to hear you found a solution, but if you’re looking for a more “visible” one, I’d recommend looking on https://extensions.gnome.org/ There are a number of extensions that monitor and display status and events from the power system, and I have to believe at least one of them would have a “react to these transitions” type of feature.

I’ve been running it for a few days now. I’m going to post any further tweaks in a GitHub gist to reduce noise here and better track revisions:

2 Likes