Ben Dodson

Freelance iOS, Apple Watch, and Apple TV Developer

The AirPlay Alarm Clock: Turning an Apple TV or Airport Express into an Alarm Clock with AppleScript

This article is now outdated and the code no longer works with modern versions of iTunes. Please read my updated article to see how to create an AirPlay alarm clock with iTunes 11 and iTunes 12.

Original article:

I was recently reading through some of my old blog posts when I discovered an article that is still fairly popular about controlling a mac mini via an iPhone. I had an old mac mini lying around and so installed it in my bedroom as a device which basically acted as an iTunes library and alarm clock. Times have changed though and I no longer have a mac mini in my bedroom; I have an Apple TV. With the recent news about iPhone alarm clocks failing to go off (again) and lots of hacking projects with AirPlay to try and stream more than just YouTube videos, I decided to work on something this evening I've been thinking about for a little while; turning my Apple TV into an Alarm Clock. The basic idea is that at a set time in the morning, the Apple TV will wake itself up automatically and start playing a set playlist from my shared iTunes library. The first step would be to get audio playlists working, but the ultimate goal would be to have video alarms as well. Thanks to a bit of AppleScript, I've managed to cook up a basic app to do just that.

So, how does one go about creating an AirPlay Alarm Clock? First of all, you will need a mac that is turned on with a shared iTunes library of content. The "turned on" bit can be automated from System Settings i.e. your machine can be asleep but told to wake up 5 minutes before your alarm is due to go off if you want to save energy. You will also need an AirPlay compatible device - this can be a set of speakers plugged into an Airport Express, one of the new AirPlay compatible iHome speaker systems, or an Apple TV. Please note that video playback will obviously only work on the Apple TV although you will get the audio from the video if you select an audio-only device. Once you've got those, you'll need to make a small tweak to your OS X setup: if you go into System Preferences and then Universal Access, you'll need to enable access for assistive devices - this is so AppleScript can make keypresses on your behalf.

Ok, on to the code:

set AppleTVName to "Bedroom Apple TV"
set PlaylistName to "Alarm"

activate application "iTunes"
delay 0.2

tell application "System Events"
	tell application "iTunes"
		set visible of front browser window to true
                set the view of the front browser window to playlist PlaylistName
	end tell
	delay 0.2

	tell window "iTunes" of application process "iTunes"
		click button 10 of window "iTunes" of application process "iTunes" of application "System Events"
		key code 125 using {command down}
		delay 0.2
		keystroke return

		delay 0.2

		tell window "Multiple Speakers" of application process "iTunes" of application "System Events"
			activate
			click button 2
			tell table 1 of scroll area 1
				activate
				
				repeat with i from 1 to (count of every row)
					set rowcount to count of rows
					if rowcount > 1 then
						tell group 1 of row i
							activate
							if description of checkbox 1 as string = AppleTVName and value of checkbox 1 = 0 then
								set value of checkbox 1 to 1
								delay 0.5
							end if
						end tell
					end if
				end repeat
				
				repeat with i from 1 to (count of every row)
					set rowcount to count of rows
					if rowcount > 1 then
						tell group 1 of row i
							activate
							if description of checkbox 1 as string does not equal AppleTVName and value of checkbox 1 = 1 then
								set value of checkbox 1 to 0
								delay 0.2
							end if
						end tell
					end if
				end repeat
				
			end tell
		end tell
	end tell

	tell window "Multiple Speakers" of application process "iTunes" of application "System Events"
		activate
		click button 3
	end tell
end tell

tell application "iTunes"
	set shuffle of playlist PlaylistName to 1
	play playlist PlaylistName
end tell

I'll explain all of that in a bit more detail shortly, but for those of you that want to get cracking, you can copy and paste that into the AppleScript Editor that comes free with every copy of OS X. You'll want to tweak the first two lines so that the variables match the name of your device and your playlist. Once that is done, you can save the script as an application. To get the alarm to play automagically in the mornings, you can open up iCal and create a new event (it can be recurring if you want a daily alarm). In the "alarm" section, there is a little known entry called "run script" which you can use to run an AppleScript at a specified time relative to the alarm. If you choose the script you saved, then it will automatically run at the allotted time. Simple!

Warning: This script is currently set to shuffle your playlist so that you don't get the same song every morning. However, if you want to playback video, you have to disable the shuffling as iTunes doesn't like playing shuffled video playlists over AirPlay for some reason. To do that, you need to edit the 3rd line from the bottom in the AppleScript to say "set shuffle of playlist PlaylistName to 0".

If you're a geeky sort of person, you'll probably want to know how all of that script works. Here is a quick breakdown of each section:

set AppleTVName to "Bedroom Apple TV"
set PlaylistName to "Alarm"

activate application "iTunes"
delay 0.2

tell application "System Events"
	tell application "iTunes"
		set visible of front browser window to true
                set the view of the front browser window to playlist PlaylistName
	end tell
	delay 0.2

The first step is to setup some variables in order to make it as easy as possible to change later on. The first is the name of your device (as listed in iTunes) and the second is the name of your chosen playlist. The next two lines tell iTunes to activate (basically open it if it's closed, or bring it to the front if it's already open) and then a short delay to make sure everything has caught up. You'll notice the line "delay 0.2" in quite a lot of places in this code. It is there to delay all activity by 0.2 seconds and is required as AppleScript can sometimes run quicker than the buttons it's pressing - by adding the delays every so often, it ensures that you aren't trying to access windows or menus which haven't yet appeared. If the script isn't working for some reason and you have an old machine, try increasing the delay timeouts first of all as these are usually the culprit. The next couple of lines force iTunes to make the main window prominent (in case we have any sub-windows hanging around) and also to display the playlist we want to play prominently. The first version of this script didn't have that and everything generally worked fine so long as the last screen you looked at on iTunes was a music page. I left a TV show list open and found it no longer worked (caused an error with the button handling) so I've added this section to ensure you are always on the correct page.

tell window "iTunes" of application process "iTunes"
	click button 10 of window "iTunes" of application process "iTunes" of application "System Events"
	key code 125 using {command down}
	delay 0.2
	keystroke return

This section controls the little AirPlay button in the bottom right hand corner of iTunes. You can usually target buttons with their names rather than their index position but the AirPlay button is a special case as it has a different name depending on which device you have selected. I have 4 different AirPlay devices in my house so rather than writing a big if statement to check for each name and then press accordingly, I instead target the button by it's numerical index. You can find out the index of UI elements by using the fantastic UI Browser tool - it's a little bit pricey but worth the money if you are planning on doing a lot of AppleScripting. Once we've told iTunes to click on the button, we use key code 125 (which means the down key) in conjunction with the command button to jump down the entire context list to the "Multiple Speakers..." option. Originally, I wanted to read the list of devices, iterate through them, and then select the one we wanted but I had a lot of problems getting AppleScript to correctly read the context menu so went for this slightly more longwinded approach instead. Once the "Multiple Speakers..." option is selected, we hit return to make it open the window.

tell window "Multiple Speakers" of application process "iTunes" of application "System Events"
	activate
	click button 2
	tell table 1 of scroll area 1
		activate

This section is now specifically targeting the "Multiple Speakers" window which we just opened. The activate command allows us to start interacting with it, and by using UI Browser, we find that button 2 is the maximum volume setting. I decided to set this manually here (rather than using the existing volume) just in case I had it set really quiet (or muted) for any reason. This ensures that the music will always come through at it's maximum volume. The next section lets us select the table listing which shows each device that we are about to iterate through.

repeat with i from 1 to (count of every row)
	set rowcount to count of rows
	if rowcount > 1 then
		tell group 1 of row i
			activate
			if description of checkbox 1 as string = AppleTVName and value of checkbox 1 = 0 then
				set value of checkbox 1 to 1
				delay 0.5
			end if
		end tell
	end if
end repeat

repeat with i from 1 to (count of every row)
	set rowcount to count of rows
	if rowcount > 1 then
		tell group 1 of row i
			activate
			if description of checkbox 1 as string does not equal AppleTVName and value of checkbox 1 = 1 then
				set value of checkbox 1 to 0
				delay 0.2
			end if
		end tell
	end if
end repeat

I'm a big fan of the DRY (don't repeat yourself) principle of coding so you may wonder why there are two loops here which are essentially the same. The first goes through the list and turns the checkbox on for the device we want to play our alarm through. The second goes through the same list again, but turns off any devices that aren't our chosen alarm device. My first thought was to do one loop that went through and turned the checkbox on if the device was correct or off it wasn't. The problem with that approach is that you can't turn off the Computer audio until you've selected another device. Therefore, you have to go through once to turn on the chosen device and then through again to turn the others (if they were enabled) off. A little tedious but this is a bit hacky anyway! I've updated the delay in the first loop from 0.2 to 0.5 as I found that a 0.2 delay would occasionally not be enough time for an AirPlay speaker to be selected before the next loop comes in and turns of the Computer. This led to an alert in the script (thus pausing everything not leading to playback) which is obviously not ideal in an alarm clock...

tell window "Multiple Speakers" of application process "iTunes" of application "System Events"
	activate
	click button 3
end tell

Just for the sake of tidiness, this tell will close the "Multiple Speakers" window we opened.

tell application "iTunes"
	set shuffle of playlist PlaylistName to 1
	play playlist PlaylistName
end tell

This final section tells iTunes to shuffle our playlist (remember to turn the shuffle off — set shuffle of playlist PlaylistName to 0 — if you are going to send video via AirPlay) and then play it.

And there you have it! A small piece of AppleScript to enable audio and video alarms over AirPlay. If you have any comments or suggestions, please get in touch.

Update [11th Jan 2011]: I've amended two sections of the code. Firstly, I've added a line near the top which ensures that the playlist you want to play is selected and displayed as the main view. Previous versions worked perfectly when I tested them as I was in the "Music" section of iTunes but if you are in a video section (e.g. left on a TV show page) then there would be an error as it couldn't find the AirPlay button (as the index was different). The second change is a delay in the looping section has been increased from 0.2 to 0.5 as occasionally it took slightly longer than 0.2 seconds to select an AirPlay speaker. This caused a problem as the script would alert causing everything to pause. Both lines have been amended in the code at the top of the page and in the analysis afterwards.

Update [25th Oct 2011]: The button codes have changed in iTunes 10.4 and 10.5 so I've updated the above script so it will continue to work. The key part was changing click button 8 of window "iTunes" of application process to click button 10 of window "iTunes" of application process. Thanks to Thomas Engbjerg for letting me know it was broken!

Update [25th Jan 2012]: I've added this code to GitHub for easier managing. If something should break in the future (looking at you iTunes 10.6) then a fix will be put up there.

Update [15th Mar 2012]: iTunes 10.6 did break as expected - needed to add a delay 0.2 before the call to speak with the "Multiple Speakers" window due to some newly introduced lag. Updated here and on GitHub.

Update [12th May 2016]: This article is now outdated and the code no longer works with modern versions of iTunes. Please read my updated article to see how to create an AirPlay alarm clock with iTunes 11 and iTunes 12.

Thoughts on the Verizon iPhone 4 » « The CoverSutra Saga