Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # Requires mph123 rtcwake notify-send amixer
- LOW_VOLUME=20
- HIGH_VOLUME=30 #64
- VOLUME_STEP_DURATION=1s
- DEFAULT_ALARM_SONG='/home/lukaschmela/Hudba/Doobie Brothers - Long train running.mp3'
- STANDBY_TIMEOUT=180
- CRON_FINGERPRINT='Alarm daemon fingerprint - DO NOT REMOVE!'
- WAIT_FOR_PID=true
- WAIT_FOR_PID_MAX=3
- CONFIG_FILE=/etc/alarm.conf
- ALARM_LIST_FILE=/etc/alarm.list
- ACTIVE_ALARM_FILE=/etc/alarm.active
- PID_FILE=/dev/shm/alarm.pid
- if [ ! -f "$CONFIG_FILE" ]; then
- echo "VAROVÁNÍ! Konfigurační soubor neexistuje, budou použity výchozí hodnoty."
- else
- . $CONFIG_FILE
- fi
- # 0 :1 :2 :3 :4 :5 :6 :7 :8
- # enabled:timestamp:song_seconds:number_of_song_repeats:repeat_song_after:repeat_alarm_how_many_times:repeat_alarm_after:alarm_name:song
- #ALARMS="1:1378931426:0:0:0:-1:86400:Testovací budík:"
- #ALARM="1:1378921426:3:0:3:-1:86400:Večerní budík:"
- volume () { # Syntax: volume [set|get] [mixer_ID] [value] [unmute]
- amixer -c0 $1 $2 $3 # > /dev/null
- }
- #alarm_task () {
- # touch "$LOCK_FILE"
- # mpg123 "$alarm_song" > /dev/null 2>&1
- # rm "$LOCK_FILE"
- #}
- parse_alarm () {
- IFS=':' read -a alarm <<< "$1"
- alarm_timestamp=${alarm[1]}
- echo $1 # FIXME
- echo "Timestamp: ${alarm[1]}"
- if [[ ${alarm[2]=0} != *[!0-9]* && ${alarm[2]} -lt 1 ]]; then # Default to play whole song
- alarm[2]=0
- fi
- if [ ${alarm[3]=1} -lt 1 ]; then # Safeguard for number of song repeats
- alarm[3]=2147483647 # 2^31 - 1
- fi
- if [ ${alarm[4]=0} -lt 0 ]; then # Default pause between song repeatings is 0s
- alarm[4]=0
- fi
- if [ ${alarm[5]=0} -lt 0 ]; then # Safeguard for number of alarm repeats FIXME OK?
- alarm[5]=2147483647 # 2^31 - 1
- fi
- alarm_song="${alarm[8]:=$DEFAULT_ALARM_SONG}"
- echo "Písnička: $alarm_song"
- }
- notify () {
- echo "Spouštím alarm ${alarm[7]}"
- notify-send -i '/usr/share/icons/gnome/32x32/status/stock_appointment-reminder.png' "Budík ${alarm[7]}" "`date -d @${alarm[1]} +%c`"
- }
- __ensure_root () {
- if [ `id -u` -ne 0 ]; then
- echo 'CHYBA! Služba musí být spuštěna pod superuživatelem.'
- exit 1
- fi
- }
- __alarm_running () {
- # return [ -f $LOCK_FILE ]
- ps -o pid= -p $alarm_PID > /dev/null 2>&1
- [ $? -eq 1 ] && return 1 || return 0
- }
- __stop_alarm () {
- kill -INT $alarm_PID > /dev/null 2>&1
- return $?
- }
- __toggle_alarm () {
- sed -i "$(($1+1))s/[01]\(.*\)/$2\1/g" "$ALARM_LIST_FILE"
- return $?
- }
- __generate_cron_entry () {
- echo "`date -d @$1 '+%M %H %d %m'` * $0 start # $CRON_FINGERPRINT"
- }
- __regex_escape () {
- echo "$1" | sed -e 's/[]\/()$*.^|[]/\\&/g'
- }
- __alarm_syntax_check () {
- if [ `echo "$1" | wc -l` -ne 1 -o `str="${1//[^:]/}"; echo ${#str}` -ne 8 ]; then
- echo "SYNTAKTICKÁ CHYBA! Ujistěte se, že jste nastavení budíku uzavřeli do uvozovek."
- exit 3
- fi
- }
- __set_active_alarm () {
- IFS=':'; echo "${alarm[*]}" > "$ACTIVE_ALARM_FILE"
- chmod 600 "$ACTIVE_ALARM_FILE"
- chown root:root "$ACTIVE_ALARM_FILE"
- }
- __set_rtc_wakeup () {
- __set_active_alarm
- rtcwake -m no -l -t ${alarm[1]}
- #echo 0 > /sys/class/rtc/rtc0/wakealarm
- #echo `date '+%s' -d @$1` > /sys/class/rtc/rtc0/wakealarm
- }
- __remove_rtc_wakeup () {
- echo "" > "$ACTIVE_ALARM_FILE"
- rtcwake -m disable
- }
- __update_alarm_schedule () {
- local next_alarm[1]=2147483647 # the greatest timestamp (2^31 - 1)
- #local alarm_index=-1
- local repeats_needed
- local current_timestamp=`date +%s`
- for ((i=0; i<${#ALARMS[*]}; i++)); do
- if [ "${ALARMS[$i]:0:1}" == "1" ]; then # Check if alarm is enabled.
- IFS=':' read -a array <<< "${ALARMS[$i]}"
- if [ ${next_alarm[1]} -gt ${array[1]} ]; then
- if [ ${array[1]} -gt $current_timestamp ]; then # Found one of next alarms - save temporary information and check if it is the earliest.
- #alarm_index=$i
- IFS=':' read -a next_alarm <<< "${ALARMS[$i]}"
- else
- if [ ${array[5]=0} == 0 ]; then # This alarm is outdated - disable.
- __toggle_alarm $i 0
- continue
- else
- repeats_needed=$(( ( $current_timestamp - ${array[1]} - 1 + ${array[6]} ) / ${array[6]} )) # Number of repeats needed for the alarm to be set in future (rounded up)
- if [ ${array[5]} -lt 0 -o ${array[5]} -ge $repeats_needed ]; then # Found one of next alarms - save temporary information and check if it is the earliest.
- IFS=':' read -a next_alarm <<< "${ALARMS[$i]}"
- let next_alarm[1]+=$(( ${array[6]} * $repeats_needed )) # Update the timestamp so that we don't get confused
- let next_alarm[5]-=repeats_needed
- break
- else
- __toggle_alarm $i 0 # Outdated - disable.
- fi
- fi
- fi
- fi
- fi
- done
- unset array
- if [ -z "${next_alarm[0]}" ]; then # No alarms left - exiting.
- __remove_rtc_wakeup
- echo "Nejsou nastaveny žádné alarmy - končím."
- exit 0
- fi
- ALARM=$( IFS=':'; echo "${next_alarm[*]}" )
- }
- __update_alarm_list_and_start () {
- ALARMS=`cat "$ALARM_LIST_FILE"`
- __update_alarm_schedule
- __set_active_alarm
- $0 start
- exit $?
- }
- alarm_task() {
- if ( set -o noclobber; echo $BASHPID > "$PID_FILE" ) 2> /dev/null; then
- chmod 400 "$PID_FILE"
- chown root:root "$PID_FILE"
- trap "rm -f \"$PID_FILE\"" INT TERM EXIT
- else
- exit 255
- fi
- ALARM=`cat "$ACTIVE_ALARM_FILE"`
- ALARMS=`cat "$ALARM_LIST_FILE"`
- if [ -z "$ALARM" ]; then
- __update_alarm_schedule
- fi
- while true; do
- parse_alarm "$ALARM"
- cron_used=$([ -n "`crontab -l | grep "# $(__regex_escape "$CRON_FINGERPRINT")"`" ] && echo true || echo false)
- current_timestamp=`date +%s`
- if [ $alarm_timestamp -gt $current_timestamp ]; then # Wait until the time specified by the user (in %H%M format) to wake up.
- if (( $alarm_timestamp - $current_timestamp > $STANDBY_TIMEOUT )); then # Do not wait that long - create a cron job instead and exit.
- if ! $cron_used; then # Safe to create a cron job - none exists within the schedule table.
- crontab -l | { cat; __generate_cron_entry $alarm_timestamp; } | crontab -
- else # Our cron job is already created - update it.
- crontab -l | { sed -r "s/^.*# $(__regex_escape "$CRON_FINGERPRINT")$/$(__regex_escape "$(__generate_cron_entry $alarm_timestamp)")/g"; } | crontab -
- fi
- __set_rtc_wakeup
- exit 4 # Exit for now - cron will call us when needed
- else # We will wait this little time.
- $cron_used && crontab -l | { sed "/^.*# $(__regex_escape "$CRON_FINGERPRINT")$/d"; } | crontab - # Delete existing cron job.
- #echo "Sleeping for $(( $alarm_timestamp - `date +%s` )) seconds."
- sleep $(( $alarm_timestamp - `date +%s` ))
- fi
- fi
- # In case we are connected to an amplifier.
- volume set PCM 255 unmute
- # We can start scrobbling again.
- volume_output=`volume set Master $LOW_VOLUME unmute` # Initial value.
- # Alarm loop.
- user_woken=false
- i=0
- while true; do
- notify
- mpg123 "$alarm_song" > /dev/null 2>&1 &
- alarm_PID=$!
- trap "__stop_alarm" INT TERM EXIT
- #alarm_task > /dev/null 2>&1 &
- #alarm_task_PID=$!
- #sleep 1
- #alarm_PID=`ps -o pid= -o comm= --ppid $alarm_task_PID | grep mpg123`
- if [ ${alarm[2]} -ne 0 ]; then
- sleep ${alarm[2]} && __stop_alarm &
- fi
- # Gracefully increase the volume of the music until user wakes up.
- for ((vol=$LOW_VOLUME; vol<=$HIGH_VOLUME; vol++)); do
- echo $vol # FIXME
- if ! __alarm_running; then
- break;
- elif [ "$volume_output" != "`volume get Master`" ]; then # User woken up!
- __stop_alarm
- user_woken=true
- break
- fi
- volume_output=`volume set Master $vol`
- sleep $VOLUME_STEP_DURATION
- done # Music turned up or ended.
- # Wait for user to wake up (change volume) or music to end.
- if ! $user_woken; then # User stil sleeps!
- while [ "$volume_output" == "`volume get Master`" ]; do # Spy volume level to find out if user has finally woken up.
- if ! __alarm_running; then # Song ended - repeat?
- let i++
- if [ $i -lt ${alarm[3]} ]; then
- sleep ${alarm[4]}
- if [ "$volume_output" == "`volume get Master`" ]; then # User haven't managed to get up during the pause.
- continue 2
- else
- break 2
- fi
- else
- break 2 # No repeatings left, give up.
- fi
- fi
- sleep 1
- done
- #else
- # echo "woken!"
- fi
- __stop_alarm # Volume changed - user woken up!
- break
- done
- __update_alarm_schedule
- done
- }
- case $1 in
- start)
- __ensure_root
- if [ -f $PID_FILE ]; then
- pid=`cat $PID_FILE`
- if [ $(ps -o pid= -p $pid > /dev/null 2>&1; echo $?) -eq 0 ]; then
- echo "CHYBA! Služba již běží jako proces $pid."
- exit 2
- else
- rm -f "$PID_FILE"
- fi
- fi
- alarm_task #&
- task_pid=$!
- if $WAIT_FOR_PID; then
- for ((i=0; i<$WAIT_FOR_PID_MAX; i++)); do
- if [ -f "$PID_FILE" ]; then
- if [ `cat "$PID_FILE"` -eq $task_pid ]; then
- exit 0
- else
- echo "CHYBA! Služba již běží jako proces $pid."
- exit 2
- fi
- fi
- done
- echo "CHYBA! Službu se nepodařilo spustit."
- exit 3
- fi
- exit 0
- ;;
- stop)
- __ensure_root
- if [ -f $PID_FILE ]; then
- pid=`cat $PID_FILE`
- if [ $(ps -o pid= -p $pid > /dev/null 2>&1; echo $?) -eq 0 ]; then
- kill $pid > /dev/null 2>&1
- if [ $? -ne 0 ]; then
- echo 'CHYBA! Službu se nepodařilo vypnout.'
- exit 2
- fi
- exit 0
- fi
- fi
- ;;
- restart)
- $0 stop && $0 start
- exit $?
- ;;
- list)
- echo -e "\e[1;39mID Alarm\e[0m"
- id=0
- while read line; do
- echo "$id $line"
- ((id++))
- done < "$ALARM_LIST_FILE"
- ;;
- add)
- __ensure_root
- if [ -z "$2" ]; then
- echo "Použití: $0 add nastavení_budíku"
- exit 2
- fi
- __alarm_syntax_check "$2"
- $0 stop
- if [ $? -ne 0 ]; then
- exit 4
- fi
- echo "$2" >> "$ALARM_LIST_FILE"
- #sed -i '/^$/d' "$ALARM_LIST_FILE" # Remove all empty lines.
- __update_alarm_list_and_start
- ;;
- remove)
- __ensure_root
- # TODO Matching by alarm name
- if [ -z "$2" ]; then
- echo "Použití: $0 remove ID_budíku"
- exit 2
- fi
- $0 stop
- if [ $? -ne 0 ]; then
- exit 3
- fi
- sed -i "$(($2+1))d" "$ALARM_LIST_FILE"
- #sed -i '/^$/d' "$ALARM_LIST_FILE" # Remove all empty lines.
- cat "$ALARM_LIST_FILE"
- __update_alarm_list_and_start
- ;;
- update)
- __ensure_root
- # TODO Matching by alarm name
- if [ -z "$2" -o -z "$3" ]; then
- echo "Použití: $0 update ID_budíku nastavení_budíku"
- exit 2
- fi
- __alarm_syntax_check "$3"
- $0 stop
- if [ $? -ne 0 ]; then
- exit 4
- fi
- sed -i "$(($2+1))s/.*/$(__regex_escape "$3")/g" "$ALARM_LIST_FILE"
- #sed -i '/^$/d' "$ALARM_LIST_FILE" # Remove all empty lines.
- __update_alarm_list_and_start
- ;;
- enable)
- __ensure_root
- # TODO Matching by alarm name
- if [ -z "$2" ]; then
- echo "Použití: $0 enable ID_budíku"
- exit 2
- fi
- $0 stop
- if [ $? -ne 0 ]; then
- exit 3
- fi
- __toggle_alarm $2 1 || echo "CHYBA! Možná jste zadali neplatné ID budíku."
- #sed -i '/^$/d' "$ALARM_LIST_FILE" # Remove all empty lines.
- __update_alarm_list_and_start
- ;;
- disable)
- __ensure_root
- # TODO Matching by alarm name
- if [ -z "$2" ]; then
- echo "Použití: $0 disable ID_budíku"
- exit 2
- fi
- $0 stop
- if [ $? -ne 0 ]; then
- exit 3
- fi
- __toggle_alarm $2 0 || echo "CHYBA! Možná jste zadali neplatné ID budíku."
- #sed -i '/^$/d' "$ALARM_LIST_FILE" # Remove all empty lines.
- __update_alarm_list_and_start
- ;;
- install)
- touch "$CONFIG_FILE" "$ACTIVE_ALARM_FILE" "$ALARM_LIST_FILE"
- chmod 644 "$CONFIG_FILE" "$ALARM_LIST_FILE"
- chmod 600 "$ACTIVE_ALARM_FILE"
- chown root:root "$CONFIG_FILE" "$ACTIVE_ALARM_FILE" "$ALARM_LIST_FILE"
- ;;
- help|h|--help|-h)
- echo "Použití: $0 [start|restart|stop|list|add|remove|update|enable|disable] [volby]"
- ;;
- *)
- if [ -n "$1" ]; then
- echo "Neznámý přepínač \"$1\"\n"
- fi
- $0 help
- exit 3
- esac
- exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement