I’m trying to get to run two idle loops at different intervals. The following illustrative code works to some extent but there is a noticeable lag between loops.
Is there a better way for this without the lag between loops? Maybe using a different approach alltogether?
property Delay1 : 1
property Delay2 : 10
on idle
set i to 0
repeat until i is greater than (Delay2 - Delay1)
-- do something, for example
beep
set i to i + Delay1
delay Delay1
end repeat
-- do something else, for example
say "Beep"
return
end idle
I want to monitor motion with AMStracker at short intervals (less than a second) and monitor the SSID at long intervals (about a minute). If motion is detected an alarm sound will go off and if the SSID changes the script will log off. As the user can set which to monitor I need to set loops for both. The current lag between loops is around 15-20 seconds and is too long since during this period motion cannot be detected.
I found a working way but unfortunately it’s not using the on idle call:
property Delay1 : 1
property Delay2 : 10
repeat
set i to 0
repeat until i is greater than (Delay2 - Delay1)
beep
delay Delay1
set i to i + Delay1
if i is Delay2 then
say "beep"
end if
end repeat
end repeat
This script isn’t using an idle as it’s intended. An “on idle” handler expects a “return n” statement where n is the number of seconds to the next cycle measured from that point (meaning that the total cycle time is the run time + idle setting). To run at two different rates that are an integer multiple of each other should be accomplished with a count of the short cycle time.
set c to 0
on idle
set c to c + 1
-- do your short cycle thing
if c is 10 then
-- do the long cycle thing
set c to 0
end if
return 1
end idle
I see Adam’s beaten me to the post, but to complement what he’s written:
An ‘idle’ handler is used in a stay-open script applet. If it doesn’t return a value at the end (as in your first script), or if it returns 0 or something that can’t be interpreted as a positive number, the system calls it every 30 seconds. That’s why you were getting the delay between the loops. The handler needs to return a value which tells the system how many seconds to wait before calling it again.
property Delay1 : 1
property Delay2 : 10
global i
set i to 0
on idle
-- do something, for example
beep
set i to i + Delay1
if (i ≥ Delay2) then
-- do something else, for example
say "Beep"
set i to 0
end if
return Delay1
end idle
Returning a value every time, as above, resets the idle interval each time and the next call is made Delay1 seconds after the handler finishes. A slightly different approach would be to set the idle interval on the first idle only. After that, it would remain unchanged and the system would poll the handler regularly every Delay1 seconds (instead of Delay1 seconds after the handler finishes).
property Delay1 : 1
property Delay2 : 10
global i, firstRun
set i to 0
set firstRun to true
on idle
-- do something, for example
beep
set i to i + Delay1
if (i ≥ Delay2) then
-- do something else, for example
say "Beep"
set i to 0
end if
if (firstRun) then
set firstRun to false
return Delay1
end if
end idle
If the handler’s still doing something when it’s called again, the call simply goes unheeded.
In the scripts above, Delay2 is based on Delay1 rather than the actual interval that takes place, so it may get out slightly. It sounds as if that might not matter very much for your purposes. For greater precision, it would be better to have two stay-open applets, each with its own idle interval.