User Tools

Site Tools


laptop_hacks

This is an old revision of the document!


Laptop Hacks

Ho boy, this got difficult really quickly - 4 years ago I had everything working on my laptop with the LXDE spin of fedora plus fluxbox. After a quick spurt of travel using all the laptoppy things like conserving battery life, suspend/resume and lid up and down, I left it alone, using it like a desktop on AC power but updating through various fedora's. Quite unbeknownst to me, systemd came in and the laptop got broken - I had to re-discover how to do everything again. Now I know and understand some of it and hopefully recording it here will help me next time.

Maybe it'll help you too - but you will almost certainly need to some make tweaks for your particular setup.

Why go through all this? Why not just use a full DE like KDE or gnome to take care of it? With KDE the best I could get (without digging just as deep as I have done here) was about 4 hours of battery life. By doing the hard work and understanding what's going on I can get up to 6.5 hours! Not bad.

Who's doing the work?

This section applies to NOT using a full desktop like gnome or KDE - those monsters do it all for you, nothing to see here, please move along.

For the rest of us using i3, fluxbox etc we need to first install acpid

It turns out that there are several players that respond to laptop events like lid opening & closing, ac power connection, suspend etc even without the distraction of gnome and KDE. Notably acpid and systemd. I got _really_ distracted thinking that systemd was the new, definitive way that had taken over the world - turns out, I was wrong, my machine was still using acpid.

How to tell? AFAICS you look at the logs - /var/log/messages or journalctl -r

How to change it? No idea - possibly installing acpid switches over to that.

Power Disconnect/Connect events

If using acpid I run this in my .xsession.

# pm-util no longer executes /etc/pm/power.d/* things so if there's a
# battery then listen on dbus for a/c connect/disconnect:
upower -e |grep -q battery && power-monitor &

Where, power-monitor is this bit of python which just runs the low-power script when the power/battery status changes:

#!/bin/env python

import gobject, os
gobject.threads_init()

from dbus import glib
glib.init_threads()
import dbus
bus = dbus.SystemBus()

def backtick(command):
    """
    Equivalent of Bourne shell's backtick
    See http://www.python.org/doc/2.5.1/lib/node534.html
    """
    from subprocess import Popen, PIPE
    #print "backtick: command='%s'\n" % command
    value = Popen(["sh", "-c", command], stdout=PIPE).communicate()[0].rstrip()
    #print "returning '%s'\n" % value
    return(value)

def ac(*args, **kwargs):
    if args[1]['Online'] == 0:
        print("unplugged")
        os.system("sudo /home/bhepple/bin/low-power true")
    else:
        print("plugged in")
        os.system("sudo /home/bhepple/bin/low-power false")
        
def check_battery(*args, **kwargs):
    battery_status = backtick("acpi -b")
    print(battery_status)
    if "Discharging" in battery_status:
        percent = int( backtick("acpi -b | awk '{print $4}' | tr -d '%,'"))
        print percent
        if percent < 10: backtick("battery-alarm&")
    gobject.timeout_add(60 * 1000, check_battery)

# get path from 'upower -e':
bus.add_signal_receiver(ac, signal_name="PropertiesChanged", dbus_interface="org.freedesktop.DBus.Properties", path="/org/freedesktop/UPower/devices/line_power_ADP0")

check_battery()

l = gobject.MainLoop()
l.run()

Put this in $HOME/bin/low-power:

#!/bin/sh

POWER="OFF"
[[ "${1:-}" && "$1" == "false" ]] && POWER="ON"

(( $(id -u) == 0 )) || {
    echo "$0: needs to run as root"
    exit 1
}

LOG=/tmp/low-power
echo "stdout and stderr will be sent to $LOG"
exec >$LOG 2>&1

case "$POWER" in
    OFF)
        battery-status
        
        logger -t $0 "power disconnect: killing bluetooth"
        systemctl stop bluetooth.target
        BT_PID=$(ps -ef |grep '[/]usr/libexec/bluetooth/bluetoothd' | awk '{print $2}')
        [[ "$BT_PID" ]] && kill -9 $BT_PID
        rmmod bnep btbcm btrtl btusb btintel bluetooth

        sudo /home/bhepple/bin/01-pm-power-display true
        sudo /home/bhepple/bin/02-pm-power-tweaks true
        sudo /home/bhepple/bin/03-pm-power-hda true

        powertop --auto-tune
        sleep 3

        battery-status

        echo "consider turning off wifi"
        echo "consider turning off camera: rmmod uvcvideo"
        echo "consider turning off ethernet: rmmod r8169 mii"
        ;;
    ON)
        sudo /home/bhepple/bin/01-pm-power-display false
        sudo /home/bhepple/bin/02-pm-power-tweaks false
        sudo /home/bhepple/bin/03-pm-power-hda false

        logger -t $0 "power connect: starting bluetooth"
        modprobe bluetooth
        systemctl start bluetooth.target

        modprobe uvcvideo r8169 mii
        ;;
esac

pkill -0 i3blocks && pkill  -RTMIN+9 i3blocks

cat $LOG
  

Put this in $HOME/bin/01-pm-power-display to dim/brighten the display - requires xbacklight:

#!/bin/sh

logger -t $0 "$0 $@"
case "$1" in
true)
    # called by pm-powersave on power disconnect
                
    xbacklight -display :0 -set 1
    logger -t $0 "power disconnect: xbacklight -set 10"
    ;;
false)
    xbacklight -display :0 -set 40
    logger -t $0 "power connect: xbacklight -set 40"
    ALARM_PID_FILE="/var/run/battery-alarm"
    [[ -f $ALARM_PID_FILE ]] && {
        logger -t $0 "alarm pids = $( cat $ALARM_PID_FILE )"
        for PID in $(cat $ALARM_PID_FILE); do
            [[ $PID > 0 ]] && kill $PID
        done
        rm $ALARM_PID_FILE
    }
    ;;
esac
exit 0

Put this in $HOME/bin/03-pm-power-hda to maximise battery or performance on the hard disc:

#!/bin/sh
logger -t $0 "$0 $@"

case "$1" in
        true)
                # called by pm-powersave on power disconnect
                logger -t $0 "power disconnect: hdparm -B1 -S5 /dev/sda"
                hdparm -B1 -S5 /dev/sda
                ;;
        false)
                # called by pm-powersave on power connect
                logger -t $0 "power connect: hdparm -B128 -S60 /dev/sda"
                hdparm -B128 -S60 /dev/sda
                ;;
esac
exit 0

Put this in $HOME/bin/02-pm-power-tweaks for general tweaking - most of this originates from powertop:

#!/bin/sh
# BH

logger -t $0 "$0 $@"
case "$1" in
true)
    # called by pm-powersave on power disconnect

    echo 5 > /proc/sys/vm/laptop_mode
    echo 0 > /proc/sys/kernel/nmi_watchdog
    echo 1 > /sys/devices/system/cpu/sched_smt_power_savings
    echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    echo 1500 > /proc/sys/vm/dirty_writeback_centisecs
    for i in /sys/bus/usb/devices/*/power/autosuspend; do echo 1 > $i; done
    for i in /sys/bus/usb/devices/*/power/level; do echo auto > $i; done
    echo min_power > /sys/class/scsi_host/host0/link_power_management_policy
    echo min_power > /sys/class/scsi_host/host1/link_power_management_policy
    echo Y > /sys/module/snd_hda_intel/parameters/power_save_controller
    echo 1 > /sys/module/snd_hda_intel/parameters/power_save
    for i in /sys/bus/{pci,i2c}/devices/*/power/control; do echo auto > $i; done
    ;;
false)
    echo 0 > /proc/sys/vm/laptop_mode
    echo 1 > /proc/sys/kernel/nmi_watchdog
    echo 0 > /sys/devices/system/cpu/sched_smt_power_savings
    echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    echo 500 > /proc/sys/vm/dirty_writeback_centisecs
    for i in /sys/bus/usb/devices/*/power/autosuspend; do echo 2 > $i; done
    # for i in /sys/bus/usb/devices/*/power/level; do echo auto > $i; done
    echo max_performance > /sys/class/scsi_host/host0/link_power_management_policy
    echo max_performance > /sys/class/scsi_host/host1/link_power_management_policy
    #echo Y > /sys/module/snd_hda_intel/parameters/power_save_controller
    #echo 1 > /sys/module/snd_hda_intel/parameters/power_save
    #for i in /sys/bus/{pci,i2c}/devices/*/power/control; do echo auto > $i; done
    ;;
esac

exit 0

hibernate/suspend events

Put this into /etc/acpi/events/sleepconf:

event=button/sleep
action=systemctl suspend

I need to reset my synaptics touch pad on resume - this is /usr/local/bin/set-synaptics:

#!/bin/sh

[ "$DISPLAY" ] || {
    echo $0': $DISPLAY not set' >&2
    exit 1
}

pkill syndaemon
syndaemon -i 1 -d -K
synclient VertEdgeScroll=1 HorizEdgeScroll=1 VertTwoFingerScroll=1 HorizTwoFingerScroll=1 PalmDetect=1 TapButton1=1 TapButton2=2 # RTCornerButton=2

If using systemd then you would put this into /etc/systemd/system/resume@.service:

[Unit]
Description=User resume actions
After=suspend.target

[Service]
User=%I
Type=simple
ExecStart=/usr/local/bin/set-synaptics

[Install]
WantedBy=suspend.target

then run systemctl enable resume@bhepple.service

Disable nouveau

I find it slow & buggy so /etc/modprobe.d/blacklist.conf gets:

blacklist nouveau

and /etc/default/grub gets:

rdblacklist=nouveau

Run this to get grub updated:

grub2-mkconfig >/boot/grub2/grub.cfg
laptop_hacks.1488615280.txt.gz · Last modified: 2017/03/04 01:14 by admin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki