Legofan613

Q: Alarm Clock

I'm trying to use Automator to make an alarm clock that, upon reaching a designated time, will turn on my iTunes. I've seen tutorials for making an alarm, which all involve building a program that boots up iTunes and starts a playlist, prompted by a Calendar event. However, none of them have an option to input the end time when you start the program. Is there such a way to do that, or do I have to edit my Calendar every time I want to run the program?

Side question: if I were to make such a program, would it run if my MacBook is closed, or does it have to be open and awake to play?

MacBook Pro, OS X El Capitan (10.11), Late 2010

Posted on Oct 9, 2015 10:43 AM

Close

Q: Alarm Clock

  • All replies
  • Helpful answers

  • by Camelot,

    Camelot Camelot Oct 9, 2015 11:41 PM in response to Legofan613
    Level 8 (47,243 points)
    Mac OS X
    Oct 9, 2015 11:41 PM in response to Legofan613

    However, none of them have an option to input the end time when you start the program

     

    What do you mean by this?

    Do you want the script to prompt you for a duration and then stop the playback at that time? How do you envision this working? Do you expect an active user input? What if there's no user in front of the system at the time?

     

    Side question: if I were to make such a program, would it run if my MacBook is closed, or does it have to be open and awake to play?

     

    If your laptop is asleep, no script will fire. The laptop will not wake just due to some random calendar event.

     

    If you want the MacBook to wake then you'll have to schedule a wake event in addition to the iTunes play. You can do this via a pmset command via do shell script.

  • by Legofan613,

    Legofan613 Legofan613 Oct 10, 2015 6:21 PM in response to Camelot
    Level 1 (14 points)
    iPhone
    Oct 10, 2015 6:21 PM in response to Camelot

    Ultimately, I'd like the program to run as follows:

    1. Prompt user to input a time.
    2. Wait for said time to arrive.
    3. Boot up iTunes.
  • by Camelot,

    Camelot Camelot Oct 11, 2015 12:58 AM in response to Legofan613
    Level 8 (47,243 points)
    Mac OS X
    Oct 11, 2015 12:58 AM in response to Legofan613

    The first part - prompting the user - is trivial. The tricky part is parsing the input to understand the date/time since there are so many possible formats. Since you're on El Capitan you can use Apple Data Detectors to do that part.

     

    Once you have a date you can sit around idle until the specified time. You probably want/need to add some boundaries, so make sure you're not sitting around waiting for some date years in the future.

     

    This is a first-hack at the idea, using Shane Stanley's solution for Data Detectors to parse the date.

    It uses a tacky 'delay' approach to pause the script until the specified time - there are other (better?) solutions which you might want depending on what kind of time intervals you're expecting (are you expecting days? hours?)

     

    set theStr to text returned of (display dialog "when?" default answer "2:30pm")

     

     

    use AppleScript version "2.4"

    use framework "Foundation"

    use scripting additions

     

     

    set theDate to my getDatesIn:theStr

     

    -- convert the input to a date object

    considering numeric strings

      if AppleScript's version < "2.5" then

      set theDate to my makeASDateFrom:theDate

      else

      set theDate to theDate as date

      end if

    end considering

     

    -- now we have the date, so work out how far away that is

     

    -- first sanity check for past dates

    set curDate to (get current date)

    if curDate > theDate then

      -- user entered a date in the past

      display dialog "Can't travel back in time, sorry."

      return

    end if

     

    -- now work out how far forward this is

    set timeOffset to theDate - curDate

     

    if (timeOffset > (2 * days)) then

      -- too far in the future

      display dialog "Sorry, that's too far in the future"

      return

    else

      -- if we get here we know how far to delay

      delay timeOffset

      tell application "iTunes" to play

    end if

     

     

    on getDatesIn:aString

      -- convert string to Cocoa string

      set anNSString to current application's NSString's stringWithString:aString

      -- create data detector

      set theDetector to current application's NSDataDetector's dataDetectorWithTypes: (current application's NSTextCheckingTypeDate) |error|: (missing value)

      -- find first match in string; returns an NSTextCheckingResult object

      set theMatch to theDetector's firstMatchInString:anNSString options: 0 range:{0, anNSString's |length|()}

      if theMatch = missing value then error "No date found"

      -- get the date property of the NSTextCheckingResult

      set theDate to theMatch's |date|()

      return theDate

    end getDatesIn:

     

    -- required before 10.11

    on makeASDateFrom:theNSDate

      set theCalendar to current application's NSCalendar's currentCalendar()

      set comps to theCalendar's componentsInTimeZone: (missing value) fromDate:theNSDate -- 'missing value' means current time zone

      tell (current date) to set {theASDate, year, day, its month, day, time} to ¬

      {it, comps's |year|(), 1, comps's |month|(), comps's |day|(), (comps's hour()) * hours + (comps's minute()) * minutes + (comps's |second|())}

      return theASDate

    end makeASDateFrom:


  • by Legofan613,

    Legofan613 Legofan613 Oct 11, 2015 5:15 AM in response to Camelot
    Level 1 (14 points)
    iPhone
    Oct 11, 2015 5:15 AM in response to Camelot

    It looks good, with one slight problem.

    On the first "use", I keep getting an error that says that it expected "end" and got "use".

  • by Hiroto,Solvedanswer

    Hiroto Hiroto Oct 11, 2015 11:44 AM in response to Legofan613
    Level 5 (7,281 points)
    Oct 11, 2015 11:44 AM in response to Legofan613

    Hello

     

    Here's a primitive script you may try.

     

    repeat
        try
            tell (current date) + 1 * hours
                set s to short date string & " " & time string
            end tell
            set r to display dialog "Enter time which alarm clock is set for" default answer s
            set t to date (r's text returned)
            set d to t - (current date)
            if d > 0 then exit repeat
        end try
    end repeat
    do shell script "sleep " & d
    tell application "iTunes" to play
    

     

     

    H

  • by Legofan613,

    Legofan613 Legofan613 Oct 11, 2015 12:53 PM in response to Hiroto
    Level 1 (14 points)
    iPhone
    Oct 11, 2015 12:53 PM in response to Hiroto

    That one did it, thanks.

  • by Hiroto,

    Hiroto Hiroto Oct 11, 2015 10:46 PM in response to Legofan613
    Level 5 (7,281 points)
    Oct 11, 2015 10:46 PM in response to Legofan613

    You're welcome.

     

    Just in case, here's a stay-open applet implementation of an alarm clock you may explore. This should be far more manageable than the previous primitive skeleton which you'd need to kill to cancel...

     

     

    (*
        Stay open applet script
    *)
    property _wake : missing value -- (date) time set for alarm clock
    property _sleep : true -- control flag
    
    on run
        -- set alarm clock
        if set_alarm_clock((current date) + 60) then
            reopen
        else -- cancelled
            quit
        end if
    end run
    
    on reopen
        -- report current alarm setting
        tell _wake to set s to short date string & " " & time string
        try
            display dialog "Alarm clock is set for " & s giving up after 10
        on error number -128 -- user cancel
            run -- reset alarm clock
        end try
    end reopen
    
    on idle
        -- sleep or wake
        if _sleep then
            set _sleep to false
            set d to _wake - (current date)
            if d > 0 then return d
            return 1 -- fall back
        else
            action()
            quit
        end if
    end idle
    
    on action()
        -- alarm action
        tell application "iTunes" to play
    end action
    
    on set_alarm_clock(t)
        (*
            date t : initial date in dialogue
            return boolean : true if set, false if cancelled
        *)
        set {_wake, _sleep} to {missing value, true}
        repeat
            try
                tell t to set s to short date string & " " & time string
                display dialog "Enter date time when alarm clock is set for" default answer s
                set t to date (result's text returned)
                set d to t - (current date)
                if d > 10 then -- at least 10 seconds ahead
                    set _wake to t
                    exit repeat
                end if
            on error number errn
                if errn = -128 then return false -- cancelled
            end try
        end repeat
        return true
    end set_alarm_clock
    

     

     

     

    Briefly tested under OS X 10.6.8.

     

    Good luck,

    H