Bluetooth Power On after Sleep

Bluetooth Power On after Sleep
Photo by Conny Schneider / Unsplash

Do you also always have to enable your Bluetooth on your Linux device when login after wakeup from suspend?

Then prepare your system with this systemd system-sleep hook script!
The just updated version also restores the state from before suspend, when ENABLE_STATUS is yes.

# cat >/usr/lib/systemd/system-sleep/bluetooth-resume.sh <<'EOF'
#!/bin/sh

CONFIG_FILE="/etc/systemd/bluetooth-resume.conf"

PATH="/usr/bin:/usr/sbin:/bin:/sbin"

DEVICE=hci0
ENABLED=yes
ENABLE_STATUS=yes
STATUS=on

[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"

[ "X$ENABLED" = "Xyes" ] || {
    echo "bluetooth-resume: not enabled" | logger
    exit 0
}

rc=0

[ "$1" = "pre" ] && [ "X$ENABLE_STATUS" = "Xyes" ] && {
    busctl get-property org.bluez /org/bluez/$DEVICE org.bluez.Adapter1 Powered | grep -q true && {
        sed -i 's/^STATUS=.*$/STATUS=on  # this is set by bluetooth-resume/' "$CONFIG_FILE"
        echo "bluetooth-resume: updated status to <on>" | logger
    } || {
        sed -i 's/^STATUS=.*$/STATUS=off # this is set by bluetooth-resume/' "$CONFIG_FILE"
        echo "bluetooth-resume: updated status to <off>" | logger
    }
}

[ "$1" = "post" ] && {
    status=$(echo "$STATUS" | tr 'A-Z' 'a-z')
    [ "X$ENABLE_STATUS" = "Xyes" ] && [ "X$STATUS" != "Xon" ] && status=off

    i=0
    while [ $i -lt 10 ]; do
        controller=$(bluetoothctl list 2>/dev/null | head -n 1)
        [ -n "$controller" ] && {
            echo "bluetooth-resume: controller ready" | logger
            break
        } || {
            echo "bluetooth-resume: controller not ready" | logger
            i=$((i + 1))
            sleep 1
        }
    done

    busctl get-property org.bluez /org/bluez/$DEVICE org.bluez.Adapter1 Powered | grep -q true && {
        echo "bluetooth-resume: status <on>" | logger
        [ "X$status" = "Xon" ] && exit 0
    } || {
        echo "bluetooth-resume: status <off>" | logger
        [ "X$status" != "Xon" ] && exit 0
    }

    rfkill list | grep -A2 "$DEVICE" | cut -d':' -f2 | grep -q yes && {
        devnr=$(rfkill list | grep "$DEVICE" | cut -d':' -f1)
        [ -n "$devnr" ] && rfkill unblock "$devnr" && {
            i=0
            while rfkill list | grep -A2 "$DEVICE" | cut -d':' -f2 | grep -q yes ; do
                i=$((i + 1))
                [ $i -lt 10 ] || break
                sleep 1
            done
            echo "bluetooth-resume: $DEVICE unblocked" | logger
        } || {
            echo "bluetooth-resume: rfkill unblock fail" | logger
        }
    }

    i=0    
    while [ $i -lt 3 ] ; do
        sleep 1
        busctl get-property org.bluez /org/bluez/$DEVICE org.bluez.Adapter1 Powered | grep -q true && {
            echo "bluetooth-resume: status <on>" | logger
            [ "X$status" = "Xon" ] && exit 0
        } || {
            echo "bluetooth-resume: status <off>" | logger
            [ "X$status" != "Xon" ] && exit 0
        }
        i=$((i + 1))
    done

    bluetoothctl power $status
    rc=$?
    [ $rc -eq 0 ] && {
        echo "bluetooth-resume: bluetoothctl power $status" | logger
    } || {
        echo "bluetooth-resume: bluetoothctl fail (rc $rc)" | logger
    } 
}

exit $rc
EOF

chmod +x /usr/lib/systemd/system-sleep/bluetooth-resume.sh

And the optional configuration file to have a place to disable the hook temporarly:

# cat >/etc/systemd/bluetooth-resume.conf <<'EOF'
# config file for /usr/lib/systemd/system-sleep/bluetooth-resume.sh

DEVICE=hci0
ENABLED=yes
ENABLED_STATUS=yes
STATUS=on  # this is set by bluetooth-resume
EOF