scripts / rtcwake /
671adf1 5 years ago
2 contributor
100 lines | 3.79kb
#!/bin/bash
# /lib/systemd/system-sleep/rtcwake
# chmod a+rx

AWAKE_TIME="01:23:45" # hour:minute:second
GAP="10 seconds"      # precision of awake time in date(1) format
WAIT_TRIGGER='true'   # test to go back to sleep when action is finished 
                      # typically pgrep on user or for specific process
WAIT_TRIGGER_DELAY=60 # sleep duration in seconds between two tests with WAIT_TRIGGER
MAX_TRIGGER=60        # don't go back to sleep if WAIT_TRIGGER isn't true
                      # after WAIT_TRIGGER_DELAY * MAX_TRIGGER seconds
LOG=/dev/null

# same format than AWAKE_TIME but as an array of times in increase order
#AWAKE_TIMES=("01:23:45" "02:46:00" "13:57:00" "20:00:00")
#WAIT_TRIGGER_DELAYS=(60 60 60 60)
#WAIT_TRIGGERS=("true" "true" "true" "true")
#MAX_TRIGGERS=(60 60 60 60)
#ON_ERRORS=()

unset RTCWAKE_TIME AWAKE_TIME

test -r $0.conf && source $0.conf # all previous variables can be set here

echo -e "\n$(date) $1/$2" >> $LOG

function set_RTCWAKE_TIME () {
    NOW=$(date +%_H%M%S)
    if test -z "$AWAKE_TIME"; then
        for ((i=0; i<${#AWAKE_TIMES[@]}; i++)); do
            echo "set_RTCWAKE_TIME: test $NOW -lt ${AWAKE_TIMES[i]//:}" >> $LOG
            if test $NOW -lt ${AWAKE_TIMES[i]//:}; then
                RTCWAKE_TIME=$(date +%s -d ${AWAKE_TIMES[i]})
                echo "next wake up at ${AWAKE_TIMES[i]}" >> $LOG
                break
            elif test $i -eq $((${#AWAKE_TIMES[@]} - 1)); then
                RTCWAKE_TIME=$(date +%s -d "tomorrow ${AWAKE_TIMES[0]}")
                echo "next wake up tomorrow at ${AWAKE_TIMES[0]}" >> $LOG
            fi
        done
    else
        RTCWAKE_TIME=$([ $NOW -lt ${AWAKE_TIME//:} ] && date +%s -d $AWAKE_TIME || date +%s -d "tomorrow $AWAKE_TIME")
    fi
    suspend_duration=$(( $RTCWAKE_TIME - $(date +%s) ))
    date_awake=$(date -d "$suspend_duration seconds")
    echo "will be awaken in $suspend_duration seconds ($date_awake) (mode=$1)" >> $LOG
    rtcwake -m $1 -s $suspend_duration
}

case "$1/$2" in
    pre/suspend)
        set_RTCWAKE_TIME no
        ;;
    post/suspend)
        at -M now <<< "$0 post wait-for-trigger" > /dev/null 2>&1
        ;;
    post/wait-for-trigger)
        NOW=$(date +%_H%M%S)
        if test -z "$AWAKE_TIME"; then
            for ((i=0; i<${#AWAKE_TIMES[@]}; i++)); do
                if test $NOW -ge ${AWAKE_TIMES[i]//:} -a $NOW -le $(date +%_H%M%S -d "${AWAKE_TIMES[i]} $GAP"); then
                    AWAKE_TIME=${AWAKE_TIMES[i]}
                    WAIT_TRIGGER_DELAY=${WAIT_TRIGGER_DELAYS[i]:-60}
                    MAX_TRIGGER=${MAX_TRIGGERS[i]:-60}
                    WAIT_TRIGGER=${WAIT_TRIGGERS[i]:-true}
                    test -n "${ON_ERRORS[i]}" && ON_ERROR=${ON_ERRORS[i]}
                    test -n "${AWAKE_ACTIONS[i]}" && AWAKE_ACTION=${AWAKE_ACTIONS[i]}
                    break
                fi
            done
        fi
        test -n "$AWAKE_ACTION" && at -M now <<< $AWAKE_ACTION > $LOG 2>&1
        if test -n "$AWAKE_TIME" && test $NOW -ge ${AWAKE_TIME//:} -a $NOW -le $(date +%_H%M%S -d "$AWAKE_TIME $GAP"); then
            cat >> $LOG << EOL
NOW: $NOW
AWAKE_TIME: $AWAKE_TIME
WAIT_TRIGGER_DELAY: $WAIT_TRIGGER_DELAY
WAIT_TRIGGER: $WAIT_TRIGGER
MAX_TRIGGER: $MAX_TRIGGER
EOL

            COUNT=1
            while sleep $WAIT_TRIGGER_DELAY && eval "$WAIT_TRIGGER"; do
                let COUNT++
                if test $COUNT -eq $MAX_TRIGGER; then
                    if test -n "$ON_ERROR"; then
                        eval "$ON_ERROR"
                    fi
                    break
                fi
            done

            unset AWAKE_TIME
            set_RTCWAKE_TIME mem
        else
            echo "rtcwake -m disable" >> $LOG
            rtcwake -m disable
        fi
        ;;
esac