Appreciate the response…I will post my code to determine whether anyone here can improve on it…that said, I do have one question, does anyone here know whether to it is or is not true that an iPhone CANNOT be paired to a MacBook because after 3+ hours of speaking with Apple and finally getting passed to a level 2 support technician I was told that this is not possible [which, personally, I find hard to believe].
As a result of your post and my resulting conclusion that it would likely be best to try to code the script on my own I av it a go and came up with the following:
set EndofTime to false
set IP_address to "192.168.2.11"
repeat while not EndofTime
-- Ping for absence / presence of iPhone [i.e. me] which triggers start/stop of SONOS Music system
set ping to do shell script ("ping -c 2 " & IP_address & "| head -2 | tail -1 |cut -d = -f 4")
-- Set iPhoneDetected to result of ping for absnece / presence of iPhone
if ping contains "ms" then
set iPhoneDetected to true
-- display dialog ("iPhone Detected - " & ping) buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
else if ping contains "timeout" then
set iPhoneDetected to false
-- display dialog "iPhone Not Detected " buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Comemnted out, included for testig purposes only
end if
-- When iPhone absent run script to pause/stop SONOS Music system
if iPhoneDetected is equal to false then
set callSONOSPause to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to pause sonos_complete.scpt" as string
run script callSONOSPause
end if
-- When iPhone present runs script to play / start SONOS Music system
if iPhoneDetected is equal to true then
set callSONOSPlay to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to play sonos at a preset volume_complete.scpt" as string
run script callSONOSPlay
end if
-- When it is the bootom and top of every hour provide the user with the opportunity to exit the script noting this needs to be refined pending the implemenation of the idle handler
if ((the minutes of the (current date) is 0) or (the minutes of the (current date) is 30)) then
display dialog "Do you want to exit/stop the SONOS Music System auto pause/play script?" buttons {"Yes", "No"} default button 2 with icon 1 giving up after 5
set continueResponse to button returned of result
if continueResponse is equal to "Yes" then set EndofTime to true
end if
end repeat
I have two issues for which I would ask for your assistance:
Although I understand the idea behind the idle handler I am unsure how to implement it because i) if I am home I don’t need to ping/test for the absence/presence of my iPhone for say 30 minutes [i.e. I don’t care whether the music continues for 30 minutes after I leave the house] but ii) if I amanita home I need to ping/test for the absence/presence of iPhone say every 30 or 60 seconds to make sure it is on when I actually walk into the door. How do I do this?
I have a logic problem in my code…because i) the ping is continually running and continuously detecting my iPhone and ii) the callSONOSPlay script includes a volume setting control I cannot change the volume of the SONOS because the script is overriding it…as such I need to build in some logic that will not reset the volume until after it next detects the absence of my iPhone [and yes, I can setup a separate script that simply controls the volume]…any suggestions on how best to do this?
a script with an on idle handler looks like this,
it requires to save the code as application with stay open option checked
on run
-- set up variables
end run
on idle
-- do something
return 60 -- call idle again after 60 seconds
end idle
on quit
-- do some cleanup
continue quit
end quit
A huge thank you or pointing me in the right direction…I do however have 3 follow ups with respect to the script that appears below:
At first I had the settings for the variables for firstDetection and IP_Address in the “On Run” section of the code but soon discovered that the settings in the 'On Run" section are not carried over to the “On Idle” section.
a) Is there a to get the variables in the “On Run” section to carry over to the “On Idle” section?
b) Why do the variables in the “On Run” section not automatically carry over to the “On Idle” section?
I am having a problem with the firstDetection variable…I am trying to setup a control variable for efficiency in that I am trying to unnecessary avoid calling the SONOS scripts Pause / Play / Volume unless there is a status change in the iPhone’s detection.
With the “On Run” section’s variables not being carried over to the “On Idle” sections variables I simply cannot figure out a way to do this because i) not setting the value at the top of the “On Idle” section cause the script to fail because the firstDetection has no value and ii) setting the value at the top of the “On Idle” section cause the value to be reset on each successive ping…how do I solve this?
With this being my first attempt at using “On Idle” code please feel free to make any and all suggestions for improvement.
on run
set firstDetection to true -- Set variable to true so the first time the iPhone is detected the SONOS Music System is started
end run
on idle
set IP_address to "192.168.2.11" -- Set iPhone IP address
-- Ping for absence/presence of iPhone [i.e. me] which triggers start/stop of SONOS Music system
set ping to do shell script ("ping -c 2 " & IP_address & "| head -2 | tail -1 |cut -d = -f 4")
-- Set results of ping for absence/presence of iPhone to iPhoneDetected
if ping contains "ms" then
set iPhoneDetected to true
display dialog ("iPhone Detected - " & ping) buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
display dialog ("first Detection - " & firstDetection) default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
else if ping contains "timeout" then
set iPhoneDetected to false
display dialog "iPhone Not Detected " buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
display dialog ("first Detection - " & firstDetection) default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
end if
-- When result of ping for absence/presence of iPhone is absent then run the script to pause/stop SONOS Music system
if ((iPhoneDetected is equal to false) and (firstDetection is equal to false)) then
set callSONOSPause to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to pause sonos_complete.scpt" as string
run script callSONOSPause
set firstDetection to true -- Set varaiable to true so that the next time the iPhone is detected the SONOS Music System is started
end if
-- When result of ping for absence/presence of iPhone is presnet then run the script to play / start SONOS Music system
if ((iPhoneDetected is equal to true) and (firstDetection is equal to true)) then
set firstDetection to false
set callSONOSVolume to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script for a preset volume_complete.scpt" as string
run script callSONOSVolume
set callSONOSPlay to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to play sonos_complete.scpt" as string
run script callSONOSPlay
end if
-- Set the idle time between pings for absence/presence of of the iPhone
set timeControl to time of (current date)
if ((timeControl is greater than 82800) or (timeControl is less than 28800)) then -- No pinging between 8:00 PM and 8:00 AM
if (timeControl is greater than 82800) then set returnTime to ((83699 - timeControl) + 28800) as integer
if (timeControl is less than 28800) then set returnTime to (28800 - timeControl) as integer
return returnTime
else
if iPhoneDetected is equal to false then set returnTime to 60 as integer -- Ping for absence/presence of iPhone every 1 minute when result is absence
if iPhoneDetected is equal to true then set returnTime to 300 as integer --Ping for absence/presence if iPhone every 5 minutes when result is presence
return returnTime
end if
end idle
on quit
display dialog "Do you also want to pause/stop the SONOS Music System?" with title "SONOS Music System Automatic Pause / Play" buttons {"Yes", "No"} default button 2 with icon 1 giving up after 15
set pauseMusic to button returned of result
if (pauseMusic is equal to "Yes") then
set callSONOSPause to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to pause sonos_complete.scpt" as string
run script callSONOSPause
end if
display dialog "Exit/stopping the SONOS Music System pause/play script" with title "SONOS Music System Automatic Pause / Play" buttons {"Okay"} default button 1 with icon 1 giving up after 5
continue quit
end quit
variables in AppleScript are local by default, that means they are valid within the scope of a handler.
Define a variable as global or use a property to extend the scope
property firstDetection : true
The value of a property is set at compile time and is persistent in a script applet even during relaunch
That said, I am running into a problem…I am thinking – perhaps incorrectly – that it would be best to use global variables because that would avoid the need to check / confirm / set the value of firstDetection when quitting as well as be more efficient from a memory management perspective [i.e. I understand that one aspect of a property is that whatever value it has when a script is exited it will have and retain that value when the script is next run unless the script recompiled].
With that I tried to use the following code to define global variables:
on run
global firstDetection
set firstDetection to true -- Set variable to true so the first time the iPhone is detected the SONOS Music System is started
global IP_address
set IP_address to "192.168.2.11"
end run
but I am getting an error message that IP_address is not defined within the “On Idle” portion of the script.
What am I doing wrong as I thought that by defining IP_address as global that it would be available within the “On Idle” portion of the script?
Appreciate that as well noting that I had read that early in the day which is where I got the idea of being better off using global variables rather than properties…what I did not realize / understand was that I needed to declare the variables as global BEFORE the “On Run” section of the script which, thinking about it, now makes perfect sense.
Apologies for being bad / slow student but rest assured I am trying my best.
“Persistence” appliies not only to properties, but to globals and to variables used in the run handler (unless these are explicitly declared local). Like properties, they “belong” to the script in which they occur and their values at the end of each run are saved back into the script file (if it’s a compiled script run in its own right and not just used as a library by some other script).
Variables used in other types of handler are local unless explicitly declared global. Local variables cease to exist as soon as the handler they’re in exits.
Properties of a script can’t be declared within any handler of that script. Their scope is the entire script.
Globals may, like properties, be declared outside any of the script’s handlers, in which case their scope too is the entire script.
Alternatively, globals can be declared inside the handlers where they’re used, in which case, their scope is limited to those handlers.
Variables in the run handler behave as if they’ve been declared global inside that handler. They persist, they “belong” to the script, and they can be accessed from other handlers by declaring them global inside those handlers ” or indeed by placing the word ‘my’ in front of them in those handlers!
It helps to know all this when troubleshooting, but it’s best not to try to be clever with it when writing. For your purposes, Stefan’s suggestion of a simple global declaration at the top of the script is perfect.
As always – as I know I sound like a broken record – thank you for the clear and detailed explanation which is greatly appreciated…I will add it to my list of readings of things to read up among as I would my way through the two texts which I have purchased – Beginning AppleScript and AppleScript: The Definitive Guide – both of which I find to be excellent references.
I feel – though it may appear differently to you – that I am slowly getting better at coding. That said, I have a long way to go but will keep pressing on.
…And for those who i) are either interested in using the script OR ii) interested in providing feedback on ways to improve the script [as I am always looking for better ways of doing things] the working script is as follows:
-- Set global variables. Definitions are defined below
global firstDetection, IP_address
on run
set firstDetection to true -- Set flag to true so that the first time the iPhone is detected the SONOS Music System is started
set IP_address to "192.168.2.11" -- Set the static IP address of the iPhone on the LAN
end run
on idle
-- Ping for absence/presence of iPhone [i.e. me] which triggers start/stop of SONOS Music system
set ping to do shell script ("ping -c 2 " & IP_address & "| head -2 | tail -1 |cut -d = -f 4")
-- Set results of ping for absence/presence of iPhone to iPhoneDetected
if ping contains "ms" then
set iPhoneDetected to true
-- display dialog ("iPhone Detected - " & ping) buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
-- display dialog ("first Detection - " & firstDetection) default button 1 with title "iPhone firstDetection Test" -- Commented out, included for testing purposes only
else if ping contains "timeout" then
set iPhoneDetected to false
-- display dialog "iPhone Not Detected " buttons {"OK"} default button 1 with title "iPhone Detection Test" -- Commented out, included for testing purposes only
-- display dialog ("first Detection - " & firstDetection) default button 1 with title "iPhone firstDetection Test" -- Commented out, included for testing purposes only
end if
-- When result of ping for absence/presence of iPhone is absent then run the script to pause/stop SONOS Music system
if ((iPhoneDetected is equal to false) and (firstDetection is equal to false)) then
set firstDetection to true -- Set flag to true so that the next time the iPhone is present the SONOS Music System is started
set callSONOSPause to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to pause sonos_complete.scpt" as string
run script callSONOSPause
end if
-- When result of ping for absence/presence of iPhone is presnet then run the script to play / start SONOS Music system
if ((iPhoneDetected is equal to true) and (firstDetection is equal to true)) then
set firstDetection to false -- Set flag to false so that the next time the iPhone is present without first being absent nothing happens
set callSONOSVolume to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script for a preset volume_complete.scpt" as string
run script callSONOSVolume
set callSONOSPlay to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to play sonos_complete.scpt" as string
run script callSONOSPlay
end if
-- Set the idle time between pings to test for the absence/presence of the iPhone
set timeControl to time of (current date)
if ((timeControl is greater than 72000) or (timeControl is less than 28800)) then -- No ping to test for iPhone absence/presence between 8:00 PM and 8:00 AM
if (timeControl is greater than 72000) then set returnTime to ((83699 - timeControl) + 28800) as integer
if (timeControl is less than 28800) then set returnTime to (28800 - timeControl) as integer
return returnTime
else
if iPhoneDetected is equal to false then set returnTime to 60 as integer -- Ping for absence/presence of iPhone every 1 minute when iPhone is absent
if iPhoneDetected is equal to true then set returnTime to 300 as integer -- Ping for absence/presence if iPhone every 5 minutes when iPhone is present
return returnTime
end if
end idle
on quit
display dialog "Do you also want to pause/stop the SONOS Music System?" with title "SONOS Music System Automatic Pause / Play" buttons {"Yes", "No"} default button 2 with icon 1 giving up after 15
set pauseMusic to button returned of result
if (pauseMusic is equal to "Yes") then
set callSONOSPause to "/Users/JoelC/Documents/Apple/Scripts/SONOS Pause Play/20141220_script to pause sonos_complete.scpt" as string
run script callSONOSPause
end if
display dialog "Exit/stopping the SONOS Music System pause/play script" with title "SONOS Music System Automatic Pause / Play" buttons {"Okay"} default button 1 with icon 1 giving up after 5
continue quit
end quit
Enjoy!
Joel
PS. I still want to learn how to implement Cocoa’s NSNetServiceBrowser and hope someone will explain it to me.
PS: in Code Exchange I posted a Cocoa application called Bonjour Events (a faceless app like System Events) which provides asynchronous Bonjour networking with AppleScript support