Ubuntu – Alarm clock from suspended mode

power-management

I want my laptop to wake up from suspended mode in the morning and alarm me to wake up using my mp3 file.
How do I do it?

I tried apmsleep, but it doesn't work cause my PC doesnt have "suspend to RAM" feature in BIOS. What can I do?
Thanks!

Best Answer

  • 1.Basic alarm clock function

    Entering suspend mode

    for this solution, you need to enter suspend mode by running the script below. It makes the computer go into suspend mode and wakes you up at a (clock-) time, defined by you (in the script). playing your song.

    Of course you can simply run the script manually to use it, but it is more convenient to make it available via a key combination, set in System Settings > Keyboard > Shortcuts > Custom Shortcuts.

    Set up

    • Paste the script below in an empty file, set the wake up (clock) time (in 1-24 hours, 1-60 minutes), set the path to your wake up song, and save it as wakeup.py.

      #!/usr/bin/env python3
      
      import datetime
      import subprocess
      
      ###############################################
      # set wakeuptime and location of the mp3:
      hour = 7
      minutes = 15
      command = "rhythmbox /path/to/wakeupsong.mp3"
      ###############################################
      
      currtime = str(datetime.datetime.now().time()).split(":")[:2]
      minutes_set = hour*60 + minutes
      minutes_curr = int(currtime[0])*60 + int(currtime[1])
      if minutes_curr < minutes_set:
          minutes_togo = minutes_set - minutes_curr
      else:
          minutes_togo = minutes_set + 1440-minutes_curr
      interval = minutes_togo*60
      
      run = "rtcwake -m disk -s "+str(interval)+" && "+"sleep 20 &&"+command
      subprocess.call(['/bin/bash', '-c', run])
      
    • make the script executable

    • Set a key combination to run the script; open System Preferences > Keyboard > Shortcuts > Custom Shortcuts, add the command

      sudo /path/to/wakeup.py (sudo = assuming you do the next step below)
      

      and choose a key combination

    • The script needs administrator's privileges. To run it without having to enter the password, open the sudoers file:

      sudo visudo
      

      add the line to the very bottom of the file:

      [your_username] ALL=NOPASSWD: [/path/to/wakeup.py]
      

      Note that the sudoers file is an essential file; errors in the file possibly lead to serious problems, so be careful!

    N.B.

    • After wake up, the computer is idle for 20 seconds before the alarm starts.
    • If you do not want to edit the sudoers file, you need to install gksu: sudo apt-get install gksu. In that case, the command to run the script is gksu /path/to/wakeup.py, and you will be prompted for your password each time you run it.

    Now you can enter suspend mode with your key combination and you'll get woken by your wake up song.

    2.Extended version including stop function when (any) key or mouse is hit

    The differences between this one and the "basic" version is that in this one the alarm stops when any keystroke or mouse movement is detected (more convenient than stopping Rhythmbox on the computer when you just woke up), and that the alarm automatically exits after a defined period of time.

    The setup is pretty much the same as the basic version, but xprintidle needs to be installed, to detect keystroke- or mouse movement events:

    sudo apt-get install xprintidle
    

    The script:

    #!/usr/bin/env python3
    
    import subprocess
    import time
    import datetime
    from threading import Thread
    
    #-------------------------- edit settings below -------------------------------
    max_wakeupduration = 1              # max time the song will play (minutes)
    wakeup_hour = 7                     # wake up hour (0-24)
    wakeup_minute = 15                  # wake up minute
    wakeup_song = "/path/to/song.mp3"   # path to wake up song
    #------------------------------------------------------------------------------
    
    def stop_wakeup():
        time1 = int(time.time()); time2 = time1
        last_idle = 0
        playtime = max_wakeupduration*60
        while time2 - time1 < playtime:
            get_idle = subprocess.Popen(["xprintidle"], stdout=subprocess.PIPE)
            curr_idle = int(get_idle.communicate()[0].decode("utf-8"))
            if curr_idle < last_idle:
                break
            else:
                last_idle = curr_idle
                time.sleep(1)
                time2 = int(time.time())
        subprocess.Popen(["pkill", "rhythmbox"])
    
    def calculate_time():
        currtime = str(datetime.datetime.now().time()).split(":")[:2]
        minutes_set = wakeup_hour*60 + wakeup_minute
        minutes_curr = int(currtime[0])*60 + int(currtime[1])
        if minutes_curr < minutes_set:
            minutes_togo = minutes_set - minutes_curr
        else:
            minutes_togo = minutes_set + 1440-minutes_curr
        return minutes_togo*60
    
    def go_asleep():
        sleeptime = calculate_time()   
        run = "rtcwake -m disk -s "+str(sleeptime)+" && "+"sleep 20"
        subprocess.call(['/bin/bash', '-c', run])
        combined_actions()
    
    def play_song():
        command = "rhythmbox "+wakeup_song
        subprocess.Popen(['/bin/bash', '-c', command])
    
    def combined_actions():
        Thread(target = play_song).start()
        Thread(target = stop_wakeup).start()
    
    go_asleep()
    

    Explanation

    rtcwake

    Both scripts are written around the rtcwake command, as explained here. The command can be used to put the computer into suspend and wake up after a defined amount of time (and optionally run a command after wake up). The -m disk option is used, since OP mentioned his computer does not support "suspend to RAM" feature in BIOS. See also man rtcwake.

    The stop function

    The stop function works by a function that measures idle time every second while the song is playing, and remembers the last idle time. IF the last idle time exceeds the current one, it means a keystroke or mouse event has taken place, and Rhythmbox is killed.