Пишем консольный будильник на BASH

/www/pages/modesco/ubuntovod

Задача "Проснуться утром" для меня, честно говоря, довольно сложная. Неделю назад пришла в голову идея: написать простой будильник, который будет проигрывать музыку все громче и громче пока не решишь математический пример.

В гугле есть некоторые статьи и темы, но все не то, что нужно.

Сразу оговорюсь, что компьютер (в моём случае ноутбук) ночью находится в спящем режиме, поэтому ему потребуется немного зарядки на ночь (у меня за ночь уходит около 30% батареи).
Если у вас настольный компьютер, есть перебои с электричеством и нет ИБП, то лучше не рискуйте.

Далее вы должны убедиться, что ваш компьютер поддерживает некоторые режимы "сна". Можете почитать об этом здесь.

Что нам потребуется:

  • Утилита rtcwake — для засыпания компьютера (встроена в ядро)
  • Утилита amixer — для постепенного увеличения громкости звука
  • Любой проигрыватель, позволяющий воспроизводить музыку в цикле (в моём случае mplayer)

Начнём

Зададим необходимые переменные:

# время по умолчанию
tm=`07:05`
 
# начальная громкость
volume=10
 
# максимальная громкость
volume_max=90
 
# время для смены задачи
sec=2
 
# папка с музыкой
folder=~username/Music/alarm/*
 
# временный файл для статуса
temp=`mktemp -t alarm_status_XXX.txt`

Здесь всё понятно.

  • "время для смены задачи" — время простоя перед генерацией новой задачи
  • "папка с музыкой" — папка, из которой нужно брать список музыки. Я просто создал папку alarm и создал жёсткие ссылки на необходимые мне музыкальные композиции
  • "временный файл для статуса" — нужен для завершения увеличения громкости. Если существует непустой файл, то завершаем фоновой процесс (кстати, можно просто через "jobs -l" найти наш процесс)

Теперь нужно написать функцию, которая будет убивать процессы mplayer-а и/или заново воспроизводить случайную музыку.

# включаем музыку
alarm_start()
{
    # убиваем все процессы mplayer-а
    jbs=(`ps al | grep [m]player | gawk -F ` ` `{print $3}``)
    for job in ${jbs[*]} ; do
        kill -15 $jbs
    done
 
    # включаем случайную мелодию с бесконечным повтором
    if [ -z "$1" ] ; then
        mplayer -loop 0 -shuffle $folder &> /dev/null &
    fi
}

Также нужно перехватывать сигналы завершения процесса.

trap "echo -e `
Неа, решите задачу!` && sleep 1 && alarm_start" SIGINT SIGTERM SIGHUP SIGQUIT SIGTSTP SIGSTOP

Для того, чтобы можно было указать время просыпания будем использовать необязательный параметр $1. Сразу сделаем все проверки валидности даты.

if [[ $# > 0 ]] ; then
    if [[ "$1" == [0-9]:[0-9][0-9] ]] || [[ "$1" == [0-9][0-9]:[0-9][0-9] ]] ; then
        tm=$1
    else
        echo `Установите правильное время. Пример: "07:00".` >&2
        exit 10
    fi
fi
 
date1=$(date -d "`date +%m/%d/%y` $tm" +%s)
date2=$(date -d "`date +%m/%d/%y` $tm tomorrow" +%s)
 
# последняя ошибка (если неверная дата)
err=$?
if [[ $err > 0 ]] ; then
    echo `Установите правильное время. Пример: "07:00".` >&2
    exit $err
fi
 
# если настоящее время больше времени для пробуждения, то ставим завтрашний день
if [[ $date1 < `date -u +%s` ]] ; then
    date=$date2
else
    date=$date1
fi

Переменные date1 и date2 нужны на случай, если пользователь укажет прошедшую дату, тогда время для просыпания будет установлено завтрашним днём. Если же время будет указано, например "07:99", то в переменную err будет занесён код ошибки.

Теперь можно "заставить" компьютер спать. rtcwake требует прав суперпользователя. Можно воспользоваться sudo. Всё, что вы делаете — вы делаете на свой страх и риск.

# засыпаем
sudo rtcwake -m mem -t $date
 
# устанавливаем громкость
amixer -q set Master $volume%
 
# включаем музыку
alarm_start

Про rtcwake, как уже говорил, вы можете прочитать здесь.

Осталось только сделать повышение громкости и пример для решения.

# повышаем уровень громкости
while true ; do
    amixer sset Master 1%+ &> /dev/null
    volume=$(( $volume+1 ))
 
    if [ $volume -eq $volume_max ] ; then
        break
    elif [ -s "$temp" ] ; then
        rm "$temp"
 
        # возвращаем нормальную громкость
        amixer -q set Master 50%
 
        break
    fi
    sleep 2
done &

Строчкой "amixer sset Master 1%+ &> /dev/null" мы указываем, что нужно повышать громкость на 1 процент и не нужно ничего выводить на экран.
Знак амперсанда & после оператора done нужен для того, чтобы увеличение громкости было в фоне.

И генерируем пример:

clear
echo `Чтобы выключить музыку решите пример:`
 
while true ; do
    # ждём
    echo "Ждите $sec сек."
    sleep $sec
 
    # пример который надо решить
    var1=$(( $RANDOM % 10000 - 5000 ))
    var2=$(( ($RANDOM % 100000 - 50000)/($RANDOM % 800 + 1) ))
 
    # операторы
    case $(( $RANDOM % 3 )) in
        0)
            opt=`+`
            result=$(( $var1 + $var2 ))
        ;;
        1)
            opt=`-`
            result=$(( $var1 - $var2 ))
        ;;
        2)
            opt=`*`
            var2=$(( ($RANDOM % 5 + 5) ))
            result=$(( $var1 * $var2 ))
        ;;
    esac
 
    # для красоты
    if [[ $var2 < 0 ]] ; then         if [[ "$opt" == `-` ]] ; then             opt=`+`             var2=$(( $var2 * -1 ))         elif [[ "$opt" == `+` ]] ; then             opt=`-`             var2=$(( $var2 * -1 ))         fi     fi          # ответ     read -p "$var1 $opt $var2 = " answer          # завершаем цикл если ответ был правильный     if [[ $answer == $result ]] ; then         echo "Правильно! Ответ: $result."         break     else         clear         echo -n "Неверно! Правильный ответ был: $var1 $opt $var2 = $result."         if [ -n "$answer" ] ; then             echo " Вы ответили: $answer."         else             echo ""         fi     fi done # параметром мы указываем, что не нужно воспроизводить музыку alarm_start false # для выключения увеличения громкости echo "done" > "$temp"

Вот и всё. Будильник был написан неделю назад. Телефонные будильники были выключены. За эту неделю я вполне мог проснуться пока решаю пример (задачка может быть очень простой (1020 — 120) или сложной (394 * 5). В одно утро мне попадался 13 раз подряд пример с умножением).

Можно создать alias в файле ~/.bashrc:

"alias alarm=`~/path_to_script/alarm.sh`"

Для того, чтобы будильник нельзя было выключить закрытием программы консоли, я выхожу из текущего сеанса и переключаюсь в другую консоль (Alt+Ctrl+F1 или другой F[1-7]).
При желании будильник можно отключить подав сигнал принудительного закрытия, но для этого нужно будет зайти в другую консоль, авторизоваться, найти этот процесс и убить. Быстрее, наверно, решить пример.

Для удобства код скопирован на pastebin, чтобы можно было скачать.

Надеюсь этот будильник заставит не проспать на учёбу или работу.

Задача "Проснуться утром" для меня, честно говоря, довольно сложная. Неделю назад пришла в голову идея: написать простой будильник, который будет проигрывать музыку все громче и громче пока не решишь математический пример.

В гугле есть некоторые статьи и темы, но все не то, что нужно.

Сразу оговорюсь, что компьютер (в моём случае ноутбук) ночью находится в спящем режиме, поэтому ему потребуется немного зарядки на ночь (у меня за ночь уходит около 30% батареи).
Если у вас настольный компьютер, есть перебои с электричеством и нет ИБП, то лучше не рискуйте.

Далее вы должны убедиться, что ваш компьютер поддерживает некоторые режимы "сна". Можете почитать об этом здесь.

Что нам потребуется:

  • Утилита rtcwake — для засыпания компьютера (встроена в ядро)
  • Утилита amixer — для постепенного увеличения громкости звука
  • Любой проигрыватель, позволяющий воспроизводить музыку в цикле (в моём случае mplayer)

Начнём

Зададим необходимые переменные:

# время по умолчанию
tm=`07:05`
 
# начальная громкость
volume=10
 
# максимальная громкость
volume_max=90
 
# время для смены задачи
sec=2
 
# папка с музыкой
folder=~username/Music/alarm/*
 
# временный файл для статуса
temp=`mktemp -t alarm_status_XXX.txt`

Здесь всё понятно.

  • "время для смены задачи" — время простоя перед генерацией новой задачи
  • "папка с музыкой" — папка, из которой нужно брать список музыки. Я просто создал папку alarm и создал жёсткие ссылки на необходимые мне музыкальные композиции
  • "временный файл для статуса" — нужен для завершения увеличения громкости. Если существует непустой файл, то завершаем фоновой процесс (кстати, можно просто через "jobs -l" найти наш процесс)

Теперь нужно написать функцию, которая будет убивать процессы mplayer-а и/или заново воспроизводить случайную музыку.

# включаем музыку
alarm_start()
{
    # убиваем все процессы mplayer-а
    jbs=(`ps al | grep [m]player | gawk -F ` ` `{print $3}``)
    for job in ${jbs[*]} ; do
        kill -15 $jbs
    done
 
    # включаем случайную мелодию с бесконечным повтором
    if [ -z "$1" ] ; then
        mplayer -loop 0 -shuffle $folder &> /dev/null &
    fi
}

Также нужно перехватывать сигналы завершения процесса.

trap "echo -e `
Неа, решите задачу!` && sleep 1 && alarm_start" SIGINT SIGTERM SIGHUP SIGQUIT SIGTSTP SIGSTOP

Для того, чтобы можно было указать время просыпания будем использовать необязательный параметр $1. Сразу сделаем все проверки валидности даты.

if [[ $# > 0 ]] ; then
    if [[ "$1" == [0-9]:[0-9][0-9] ]] || [[ "$1" == [0-9][0-9]:[0-9][0-9] ]] ; then
        tm=$1
    else
        echo `Установите правильное время. Пример: "07:00".` >&2
        exit 10
    fi
fi
 
date1=$(date -d "`date +%m/%d/%y` $tm" +%s)
date2=$(date -d "`date +%m/%d/%y` $tm tomorrow" +%s)
 
# последняя ошибка (если неверная дата)
err=$?
if [[ $err > 0 ]] ; then
    echo `Установите правильное время. Пример: "07:00".` >&2
    exit $err
fi
 
# если настоящее время больше времени для пробуждения, то ставим завтрашний день
if [[ $date1 < `date -u +%s` ]] ; then
    date=$date2
else
    date=$date1
fi

Переменные date1 и date2 нужны на случай, если пользователь укажет прошедшую дату, тогда время для просыпания будет установлено завтрашним днём. Если же время будет указано, например "07:99", то в переменную err будет занесён код ошибки.

Теперь можно "заставить" компьютер спать. rtcwake требует прав суперпользователя. Можно воспользоваться sudo. Всё, что вы делаете — вы делаете на свой страх и риск.

# засыпаем
sudo rtcwake -m mem -t $date
 
# устанавливаем громкость
amixer -q set Master $volume%
 
# включаем музыку
alarm_start

Про rtcwake, как уже говорил, вы можете прочитать здесь.

Осталось только сделать повышение громкости и пример для решения.

# повышаем уровень громкости
while true ; do
    amixer sset Master 1%+ &> /dev/null
    volume=$(( $volume+1 ))
 
    if [ $volume -eq $volume_max ] ; then
        break
    elif [ -s "$temp" ] ; then
        rm "$temp"
 
        # возвращаем нормальную громкость
        amixer -q set Master 50%
 
        break
    fi
    sleep 2
done &

Строчкой "amixer sset Master 1%+ &> /dev/null" мы указываем, что нужно повышать громкость на 1 процент и не нужно ничего выводить на экран.
Знак амперсанда & после оператора done нужен для того, чтобы увеличение громкости было в фоне.

И генерируем пример:

clear
echo `Чтобы выключить музыку решите пример:`
 
while true ; do
    # ждём
    echo "Ждите $sec сек."
    sleep $sec
 
    # пример который надо решить
    var1=$(( $RANDOM % 10000 - 5000 ))
    var2=$(( ($RANDOM % 100000 - 50000)/($RANDOM % 800 + 1) ))
 
    # операторы
    case $(( $RANDOM % 3 )) in
        0)
            opt=`+`
            result=$(( $var1 + $var2 ))
        ;;
        1)
            opt=`-`
            result=$(( $var1 - $var2 ))
        ;;
        2)
            opt=`*`
            var2=$(( ($RANDOM % 5 + 5) ))
            result=$(( $var1 * $var2 ))
        ;;
    esac
 
    # для красоты
    if [[ $var2 < 0 ]] ; then         if [[ "$opt" == `-` ]] ; then             opt=`+`             var2=$(( $var2 * -1 ))         elif [[ "$opt" == `+` ]] ; then             opt=`-`             var2=$(( $var2 * -1 ))         fi     fi          # ответ     read -p "$var1 $opt $var2 = " answer          # завершаем цикл если ответ был правильный     if [[ $answer == $result ]] ; then         echo "Правильно! Ответ: $result."         break     else         clear         echo -n "Неверно! Правильный ответ был: $var1 $opt $var2 = $result."         if [ -n "$answer" ] ; then             echo " Вы ответили: $answer."         else             echo ""         fi     fi done # параметром мы указываем, что не нужно воспроизводить музыку alarm_start false # для выключения увеличения громкости echo "done" > "$temp"

Вот и всё. Будильник был написан неделю назад. Телефонные будильники были выключены. За эту неделю я вполне мог проснуться пока решаю пример (задачка может быть очень простой (1020 — 120) или сложной (394 * 5). В одно утро мне попадался 13 раз подряд пример с умножением).

Можно создать alias в файле ~/.bashrc:

"alias alarm=`~/path_to_script/alarm.sh`"

Для того, чтобы будильник нельзя было выключить закрытием программы консоли, я выхожу из текущего сеанса и переключаюсь в другую консоль (Alt+Ctrl+F1 или другой F[1-7]).
При желании будильник можно отключить подав сигнал принудительного закрытия, но для этого нужно будет зайти в другую консоль, авторизоваться, найти этот процесс и убить. Быстрее, наверно, решить пример.

Для удобства код скопирован на pastebin, чтобы можно было скачать.

Надеюсь этот будильник заставит не проспать на учёбу или работу.

Купили себе новый телефон, но не знаете как раскрыть его потенциал? Тогда вам просто нужно скачать приложения и игры для телефона. Для этого вам стоит зайти на этот сайт и скачать всё то, что сами пожелаете.