Idle handler function is not running at the exact specified interval - applescript

The script uses idle handler that runs every 5 minutes and alerts me to perform the task. But the script always runs late by 10-40 seconds. I am not sure why that is happening.
global numberOfBeeps, beepcycle
on idle
if beepcycle is greater than 0 then
say "Update 5 minute data and watchlist " using "Serena"
set beepcycle to beepcycle - 1
else
say "Update 30 minute data and watchlist" using "Kate"
set beepcycle to 5
end if
return 300
end idle
on run
set beepcycle to 6
end run

The if statement in your script adds this 10-40 seconds to the on idle handler. So, you should correct the return time of on idle handler some way. For example, you can do something like this:
global numberOfBeeps, beepcycle
on idle
set currentDate to (get current date)
if beepcycle is greater than 0 then
say "Update 5 minute data and watchlist " using "Serena"
set beepcycle to beepcycle - 1
else
say "Update 30 minute data and watchlist" using "Kate"
set beepcycle to 5
end if
set timeElapsed to (get current date) - currentDate
return (300 - timeElapsed)
end idle
on run
set beepcycle to 6
end run

Related

VBS popup doesn't appear at a specific time using a loop

I have a VBS file with the following code:
dtsnow = Now()
hours = Right("00" & Hour(dtsnow), 2)
minutes = Right("00" & Minute(dtsnow), 2)
Do
If hours > 10 And minutes > 30 Then
CreateObject("Wscript.Shell").Popup "ok", 0, "Window title"
End If
WScript.sleep 2000 'every 2 seconds
Loop
If I run the file for example at 11:31, the popup is apperaed every 2 seconds, as expected. But if I run the file e.g. at 11:30 i.e. then clock minutes are not more than 30 and then wait a few minutes, the popup doesn't appear when clock minutes are more than 30 while the loop checks the time every 2 seconds.
Why?

AppleScript Progress Bar with Reboot Button

I've recently been tasked with working on a project to switch antivirus software in the environment as we are changing to a new vendor. Naturally, this kind of effort will require a reboot on our endpoints once the old A/V software has been removed.
What I'm trying to do is create a reboot notification prompt for our Mac customers (since many are high up on the food chain) to let them know what we are doing.
This prompt will let them know they have 3 hours to reboot their Macs to complete the removal of the software if they are logged in. If they do not reboot within 3 hours, their workstation will automatically reboot.
Applescript has a great workflow that allows me to effectively communicate with our users, but I would like to change the Stop button to a reboot, so that our customers can reboot their Macs on demand.
I will work in logic later on to automatically reboot if they are not logged in.
I modified one of the scripts that I, "borrowed," from here
https://macscripter.net/viewtopic.php?id=46572
-- Progress Bar - Reboot Timer
progress_timer("03:00:00", "Reboot Timer") -- call the progress timer with an HMS time and timer label
return result
------------------------------------------
-- subroutines in alphabetical order --
------------------------------------------
-- getTimeConversion converts a time in HMS format (hh:mm:ss) to a time in seconds
on getTimeConversion(HMS_Time)
set HMSlist to the words of HMS_Time -- get {hh, mm, ss} from HMS time (p. 158 Rosenthal)
set theHours to item 1 of HMSlist
set theMinutes to item 2 of HMSlist
set theSeconds to item 3 of HMSlist
return round (theHours * (60 ^ 2) + theMinutes * 60 + theSeconds)
end getTimeConversion
-- progress_timer displays the elapsed time in a progress bar. For information on progress bars see: https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/DisplayProgress.html
on progress_timer(HMS_Time, timerLabel)
set theTimeSec to getTimeConversion(HMS_Time) -- convert the HMS format to seconds
set progress total steps to theTimeSec
set progress completed steps to 0
set startTime to (current date)
repeat with i from 0 to theTimeSec -- begin at i = 0 to start the timer at 00:00:00
set HMS_SoFar to TimetoText(i) -- convert the seconds so far to HMS format for display
set HMS_ToGo to TimetoText(theTimeSec - i) -- convert the seconds to go to HMS format for display
set progress completed steps to 0
set progress description to "
Your IT Department needs to make changes to your Mac.
Your workstation must be rebooted in order for these changes to take effect.
Your workstation will reboot in " & HMS_ToGo
set progress additional description to ¬
""
--"Time Elapsed: " & HMS_SoFar & return & ¬
--"Counting Down: " & HMS_ToGo
set progress completed steps to i
set elapsedTime to (current date) - startTime -- get actual elapsed time for adjusting delay
set lagAdjust to elapsedTime - i -- compute lag adjustment
delay 1 - lagAdjust -- delay 1 second minus any cumulative lag that needs removing
end repeat
--set HMS_Elapsed to TimetoText(elapsedTime) -- convert elapsedTime back to HMS format for display
set dialogText to null
--set dialogText to "Elapsed Time: " & return & ¬
-- "Nominal = " & HMS_Time & return & ¬
-- "Actual = " & HMS_Elapsed
tell me to activate
--display dialog dialogText with title timerLabel & " Timer"
return dialogText
end progress_timer
-- TimetoText converts a time in seconds to a time in HMS format (hh:mm:ss)
on TimetoText(theTime)
-- parameters - TheTime [integer]: the time in seconds
-- returns [text]: the time in the format hh:mm:ss
-- Nigel Garvey points out this script is only valid for parameter values up to 86399 seconds (23:59:59) and offers a solution for longer times here: https://macscripter.net/viewtopic.php?pid=134656#p134656
if (class of theTime) as text is "integer" then
set TimeString to 1000000 + 10000 * (theTime mod days div hours) -- hours
set TimeString to TimeString + 100 * (theTime mod hours div minutes) -- minutes
set TimeString to (TimeString + (theTime mod minutes)) as text -- seconds
tell TimeString to set theTime to (text -6 thru -5) & ":" & (text -4 thru -3) & ":" & (text -2 thru -1)
end if
return theTime
end TimetoText
Here's a screenshot of the resulting output.

trying to write an apple script that chimes every hour

I'm trying to write this script that chimes on every hour. I saved it as an application and selected the checkbox run after completion but it doesn't work. My code looks like this:
global chime
set chime to (path to resource "chime.mp3")
on idle
set currenthour to hours of (current date)
if currenthour = 0 then
set currenthour to 12
end if
if currenthour > 12 then
set currenthour to currenthour - 12
end if
set currentminute to minutes of (current date)
set currentsecond to seconds of (current date)
set currenttime to {currentminute, currentsecond} as text
if currenttime is "" then
repeat currenthour times
do shell script "afplay " & (quoted form of POSIX path of chime)
end repeat
end if
return 1
end idle
In a script app, the number you return from the on idle handler tells the system how long to sleep the app before the next idle invocation. You can use this set up a (loosely) accurate timer.
global chime, firstRun
on run
-- I'm not sure if this is necessary, but I always use explicit run handlers in script apps.
set chime to (path to resource "chime.mp3")
set firstRun to true
end run
on idle
set {currenthour, currentminute, currentsecond} to {hours, minutes, seconds} of (current date)
-- don't chime when the script app is activated
if not firstRun then
-- quick mathy way to retrieve the number of chimes.
set chimeCount to (currenthour + 11) mod 12 + 1
repeat chimeCount times
do shell script "afplay " & (quoted form of POSIX path of chime)
end repeat
else
set firstRun to true
end if
-- calculate the number of seconds until the next hour mark and tell app to sleep until then
return 60 * (60 - currentminute) + 60 - currentsecond
end idle

Problems with variables working outside idle loops in apple script

I have a problem with variables not working outside an idle. What should I do to make it work? My code looks like this:
set currentdate to current date
set currentminute to currentdate's minutes
on idle
display dialog currentminute
if idle_time < 0 then set idle_time to days - (time of (current date))
return idle_time
end idle
on idle is not a loop, it's a handler having its own scope.
Mark currentminute as global or declare it as property for example. Both ways makes the variable available in handlers on lower levels.
property currentminute : 0
set currentdate to current date
set currentminute to currentdate's minutes
on idle
display dialog currentminute
if idle_time < 0 then set idle_time to days - (time of (current date))
return idle_time
end idle

Perform a loop for a certain time interval or while condition is met

I am trying to have a check fire off every second for 30 seconds. I haven't found a clear way to do this with Ruby yet. Trying something like this currently:
until counter == 30
sleep 1
if condition
do something
break
else
counter +=1
end
Problem with something like that is it has to use sleep, which stops the thread in its tracks for a full second. Is there another way to achieve something similar to the above without the use of sleep? Is there a way to have something cycle though on a time based interval?
You can approximate what you're looking for with something along these lines:
now = Time.now
counter = 1
loop do
if Time.now < now + counter
next
else
puts "counting another second ..."
end
counter += 1
break if counter > 30
end
You could do something simple like..
max_runtime = 10.seconds.from_now
puts 'whatever' until Time.now > max_runtime
you can try this it allows for interval controls
counter == 30
interval = 5 # Check every 5 seconds
interval_timer = 1 # must start at 1
now = Time.now
while Time.now - now < counter
if interval_timer % interval == 0 #Every 5 attempts the activity will process
if condition
stuff
end
end
process_timer = process_timer + 1
end
This will happen under a guaranteed 30 seconds the interval can be set to any value 1 or greater. Some things process via milliseconds this will give you an option that will save you cycles on processing. Works well in graphics processing.

Resources