Hi All,
Apologies if this is super neophyte question. Total newbie with Applescript and still learning.
I’d like to create an Applescript that will send ECP commands to Roku box(es) on the local network - and do so at specified durations (set as delays) so for example:
The sequence (including the ECP commands) would go something like:
I am able to manually execute the curl -d command lines directly from the Terminal, and they function as expected, I am just not sure how to do this from AppleScript - so that the process is automated.
Any insight or suggestions would be sincerely appreciated.
Works perfectly. It was the “escaping” the quotes that was hanging me up - could not think of the word to even refer to the quotes within quotes! Preceding with a backslash does the trick.
And delay works perfectly following each do shell script.
Question - is there a way to keep the AppleScript “persistent” - meaning, in the case that one of the curl line fails (as a result of no device at the specified IP for example) the script will ignore the error and keep running to the next line?
I noticed during some testing, test I had mistakenly entered the wrong IP, and when the script got to that line, the script stopped and showed me the error. Useful while debugging, but in practice for my implementation, I’d like to gave the script continue to the next line without regard for whether or not the present curl command succeeds. Does this make sense, and is there a way to implement this to make the AppleScript itself resilient or persistent (sorry if my wording is poor, not sure how else to describe what I am trying to accomplish.)
try
-- any errors from code here will be ignored
-- after an error script continues with statement after 'end try'
end try
You should put each curl command in its own try block
When you expect other errors that can be dealt with in whatever manner you can add an on error clause:
try
-- any errors from code here will be dealt with in the 'on error' part
on error errorMessage number errorNumber
-- add code here to deal with specified errors
end try
Wow, thank you. You all are amazing. This makes perfect sense. Thank you. I will get to work on implementing Try now.
Is there a way to also have the script write a simple Log file to the desktop, with a time/date stamp for each time the script runs the sequence of curl commands? And it would merely append to the same txt file?
Using the above Try logic, how could I differentiate in the output to the log.txt whether the curl command was successful?
Thank you very much for all of your input and support!
this script writes a log in failure case into the default log folder ~/Library/Logs.
You can change the name in the first line to the file name you want.
The log can be watched in Console.app
A log entry contains the time stamp, the path and the error reason
property logFileName : "myLog.txt"
property logFile : ""
set logFile to ((path to library folder from user domain as text) & "Logs:" & logFileName)
repeat
delayAndCurl(300, "keypress/home")
delayAndCurl(10, "launch/42088")
delayAndCurl(15, "keypress/right")
delayAndCurl(5, "keypress/select")
end repeat
on delayAndCurl(theDelay, thePath)
delay theDelay
try
do shell script "curl -d [url=http://192.168.0.x:8060/]http://192.168.0.x:8060/"[/url] & thePath
on error errorMessage
writeToLog(thePath & " failed: " & errorMessage)
end try
end delayAndCurl
on writeToLog(theMessage)
tell (current date) to set timestamp to short date string & space & time string & ": "
try
set fileReference to open for access file logFile with write permission
set logFileEof to get eof of the fileReference
write timestamp & theMessage & return to fileReference starting at eof as «class utf8»
close access fileReference
on error
try
close access file logFile
end try
end try
end writeToLog
Beautiful! Thank you. So a question on structure if I would like to implement these commands across a series of devices at different IP addresses. (192.168.0.x, 192.168.1.x, 192.168.2.x, 192.168.3.x and so on)
Would it be better to place each one in it’s own TRY subroutine (is that the right word) or can they somehow be sequenced in the same TRY block? Or perhaps even place the IP addresses (URLs) in a variable? What I am trying to accomplish is to know which IP fails and on which CURL command.
if blocks of the IP addresses are consecutive like in your example I’d prefer this way
on delayAndCurl(theDelay, thePath)
repeat with i from 0 to 3
delay theDelay
try
do shell script "curl -d http://192.168. " & i & ".x:8060/" & thePath
on error errorMessage
writeToLog(thePath & " failed: " & errorMessage)
end try
end repeat
end delayAndCurl
Ok, indeed makes sense. However, the subnets are consecutive, but the actual IP addresses of the devices are not and sometimes new devices are added in a given subnet, so they may be:
and so on. Roku ECP has the ability to do “auto-discover” on a subnet to poll the IP of any Roku devices it finds, but that is getting way over my head at this stage. For now, I have allowed the respective DHCP server to assign the address to the Roku box when it brought online and then I go in a reserve that IP on the DHCP server (since there is no other way to assign a static IP on the Roku box itself.)
How would I create a table or input source of IPs in the script that can be either
a) manually adjusted or
b) read from an external txt file as an IP list? and if read from said list, to be read each time it runs the loop?
Manual input is ok, since I don’t think the IP list would change that often - as new devices may only be introduced once a week.
create a plain text file and save the addresses one per line
.
set logFile to ((path to library folder from user domain as text) & "Logs:" & logFileName)
repeat
set ipAddresses to paragraphs of (read file "MacHD:path:to:file.txt") -- change to proper path
repeat with anAddress in ipAddresses
delayAndCurl(300, "keypress/home", anAddress)
delayAndCurl(10, "launch/42088", anAddress)
delayAndCurl(15, "keypress/right", anAddress)
delayAndCurl(5, "keypress/select", anAddress)
end repeat
end repeat
on delayAndCurl(theDelay, thePath, ipAddress)
delay theDelay
try
do shell script "curl -d http://" & ipAddress & ":8060/" & thePath
on error errorMessage
writeToLog(thePath & " failed: " & errorMessage)
end try
end delayAndCurl
.
Quick question if I may - so I understand the logic:
Based on the following, does this
wait 300 seconds and then execute the CURL command for a single IP - then go through the four commands (CURL) then repeat with the next IP?
OR
does this wait 300 seconds and execute that CURL command for all of the IPs in the list of IPs before proceeding to the next delayAndCurl?
repeat
set ipAddresses to paragraphs of (read file "MacHD:path:to:file.txt") -- change to proper path
repeat with anAddress in ipAddresses
delayAndCurl(300, "keypress/home", anAddress)
delayAndCurl(10, "launch/42088", anAddress)
delayAndCurl(15, "keypress/right", anAddress)
delayAndCurl(5, "keypress/select", anAddress)
end repeat
end repeat
The reason I am asking is to understand how to establish the timing(s) - ideally, it would wait 300 seconds, and then execute that “keypress/home” for each and every IP in the IP list, then proceed to the next delayAndCurl (10,
Sorry for my confusion, just want to see if I am understanding what is happening.
How would I structure it so that it would process all IPs for that command following the single delay value? The difference in timings becomes very large if it waits 300 seconds for one IP first command. Ideally, for timings, it would merely wait 300 seconds, then execute the CURL command for all IPs in the list, then proceed to the next delay/command. Such that the total delay is always about 300 seconds at the start whether 1 or 10 Roku devices.
try this, it waits 5 minutes before going through the address list and one second before each keypress/home address
repeat
set ipAddresses to paragraphs of (read file "MacHD:path:to:file.txt") -- change to proper path
delay 300
repeat with anAddress in ipAddresses
delayAndCurl(1, "keypress/home", anAddress)
delayAndCurl(10, "launch/42088", anAddress)
delayAndCurl(15, "keypress/right", anAddress)
delayAndCurl(5, "keypress/select", anAddress)
end repeat
end repeat
Ok, I see. So there is still the cumulative effect of executing each command in sequence for each IP, but this could be manageable for a list of perhaps ten (10) devices - would total somewhere close to 5 minutes to work it’s way through the list.
How would you structure it so that it executes them more together with less delay between commands if we needed the devices to be triggered at about the same time(s)?
Sort of like this logic/flow:
repeat
delay 300
do shell script "curl -d [url=http://192.168.0.x:8060/keypress/home]http://192.168.0.x:8060/keypress/home"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/keypress/home]http://192.168.2.x:8060/keypress/home"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/keypress/home]http://192.168.2.x:8060/keypress/home"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/keypress/home]http://192.168.2.x:8060/keypress/home"[/url]
do shell script "curl -d [url=http://192.168.3.x:8060/keypress/home]http://192.168.3.x:8060/keypress/home"[/url]
do shell script "curl -d [url=http://192.168.3.x:8060/keypress/home]http://192.168.3.x:8060/keypress/home"[/url]
delay 10
do shell script "curl -d [url=http://192.168.0.x:8060/launch/42088]http://192.168.0.x:8060/launch/42088"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/launch/42088]http://192.168.2.x:8060/launch/42088"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/launch/42088]http://192.168.2.x:8060/launch/42088"[/url]
do shell script "curl -d [url=http://192.168.2.x:8060/launch/42088]http://192.168.2.x:8060/launch/42088"[/url]
do shell script "curl -d [url=http://192.168.3.x:8060/launch/42088]http://192.168.3.x:8060/launch/42088"[/url]
do shell script "curl -d [url=http://192.168.3.x:8060//launch/42088]http://192.168.3.x:8060//launch/42088"[/url]