User Tools

Site Tools


laptop_hacks

Laptop Hacks

Ho boy, this got difficult really quickly - in 2011 I had everything working on my laptop (Dell XPS-15 L502X) 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 laptoppy stuff 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 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?

Several players:

  • acpid: for suspend
  • DBus: for power connect/disconnect
  • acpi: to get battery status
  • systemctl: but, of course!
  • ???: DBus? lid opening & closing - just seems to work

Suspend

Install acpid and acpi and then:

systemctl enable acpid
systemctl start acpid

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

event=button/sleep
action=systemctl suspend

Tweaking touchpad

Seems the synaptics driver is deprecated in favour of libinput - put tweaks in /etc/X11/xorg.conf.d/30-touchpad.conf:

Section "InputClass"
    Identifier "touchpad"
    Driver "libinput"
    MatchIsTouchpad "on"
    Option "Tapping" "on"
    Option "TappingButtonMap" "lmr"
    Option "ScrollMethod" "edge"
EndSection

Power Disconnect/Connect events

These events come through DBus, so I run this in my .xsession.

# if there's a battery then listen on dbus for a/c connect/disconnect:
upower -e |grep -q battery && {
    power-monitor &
    xfce4-power-manager &
}

Where, power-monitor is this bit of python which keeps an eye on remaining battery life (and hibernate as it gets low) but also runs the low-power script when the power/battery status changes:

#!/bin/env python

# needs to run as normal user under X (so that battery-alarm can popup)
# requires dbus-python

import gobject, os, sys
gobject.threads_init()

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

sys.dont_write_bytecode = True

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)

# power connection events
def ac(*args, **kwargs):
    print("[" + backtick("date '+%Y%m%d:%H%M%S'") + "] power-monitor: ac: args = ")
    print args
    try:
        if args[1]['Online'] == 0:
            print("power-monitor: ac: unplugged - calling low-power true")
            os.system("low-power true")
        else:
            print("power-monitor: ac: plugged in - calling low-power false")
            os.system("low-power false")
    except:
        pass

# warn user or suspend
def check_battery(*args, **kwargs):
    battery_status = backtick("acpi -b")
    print("[" + backtick("date '+%Y%m%d:%H%M%S'") + "] power-monitor: " + battery_status)
    if "Discharging" in battery_status:
        percent = int( backtick("acpi -b | awk '{print $4}' | tr -d '%,'"))
        if percent < 5:
            print("power-monitor: check-battery: systemctl hibernate")
            os.system("pkill battery-alarm; sudo systemctl hibernate")
        if percent < 10:
            print("power-monitor: check-battery: battery-alarm")
            os.system("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:

#!/usr/bin/env bash 

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

echo "$0: POWER=$POWER"

case "$POWER" in
    OFF)
        battery-status

        #sudo $( which 01-pm-power-display) true
        sudo $( which brightness ) 20
        sudo $( which 02-pm-power-tweaks) true
        sudo $( which 03-pm-power-hda) true

        sudo powertop --auto-tune
        sleep 3

        battery-status
        ;;
    ON)
        #sudo $( which 01-pm-power-display) false
        sudo $( which brightness ) 100
        sudo $( which 02-pm-power-tweaks) false
        sudo $( which 03-pm-power-hda) false
        ;;
esac

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

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:

#!/usr/bin/env bash
# BH

logger -t $0 "$0 $@"
case "$1" in
true)
    logger -t $0 "power disconnect"
    systemctl stop bluetooth.target
    rfkill block bluetooth
    BT_PID=$(ps -ef |grep '[/]usr/libexec/bluetooth/bluetoothd' | awk '{print $2}')
    [[ "$BT_PID" ]] && kill -9 $BT_PID

    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 powersave > /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/devices/*/power/control; do echo auto > $i; done
    iw dev wlp3s0 set power_save on
    ;;
false)
    logger -t $0 "power connect"
    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 performance > /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/devices/*/power/control; do echo auto > $i; done

    modprobe bluetooth
    rfkill unblock bluetooth

    systemctl start bluetooth.target

    modprobe uvcvideo r8169 mii
    iw dev wlp3s0 set power_save off
    ;;
esac

exit 0

To run stuff on 'resume', put this in /etc/systemd/system/bhepple-resume.service:

[Unit]
Description=Run on 'resume'
After=suspend.target

[Service]
User=root
Type=oneshot
ExecStart=/sbin/hdparm -y /dev/sda # puts aux disc into standby - should test that it's not '/' !!

[Install]
WantedBy=suspend.target

and run systemctl enable bhepple-resume.service

brightness is this:

#!/bin/bash

# since xbacklight isn't working (nouveau?)
# https://bbs.archlinux.org/viewtopic.php?id=134972 and modified:

# needs to be run as root

NEW_VALUE=${1:-0}

# base dir for backlight class
basedir="/sys/class/backlight/"

# get the backlight handler
handler=$basedir$(ls $basedir |head -n 1)"/"

# get current brightness
old_brightness=$(cat $handler"brightness")

# get max brightness
max_brightness=$(cat $handler"max_brightness")

# get current brightness %
old_brightness_p=$(( 100 * $old_brightness / $max_brightness ))

# calculate new brightness %
if [[ $NEW_VALUE == [+-]* ]]; then
    new_brightness_p=$(($old_brightness_p + $NEW_VALUE))
else
    new_brightness_p=$NEW_VALUE
fi

# calculate new brightness value
new_brightness=$(( $max_brightness * $new_brightness_p / 100 ))

(( new_brightness <= max_brightness && new_brightness >= 0 )) && {
    # set the new brightness value
    echo $new_brightness > $handler"brightness"
}

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.txt · Last modified: 2020/02/08 16:41 by admin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki