Solution: Find iCal event that triggered script as alert

Posted on
Mon Apr 02, 2012 8:27 pm
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Solution: Find iCal event that triggered script as alert

Solution: An AppleScript method to find out the iCal event that triggered a script as an alert, and how to extract information (start date, end date, notes, etc) from that event. ***Edit: the script relies only on iCal, so it can be used in any scripting application; it does not use any Indigo specific AppleScript terms.

As many are aware, although you can schedule scripts to run with iCal, but iCal does not provide any information about the event that triggered the script, not even if you use Automator to create an iCal alarm workflow; a deficiency that I find infuriating and inexcusable, but one that Apple seems to have no interest in addressing.

The solution that I have implemented searches through events in a specific calendar in iCal (named "Indigo" in this case) to try and find which event occurs closest to the time the script was run. This only works if the event does not trigger the alert before the start time specified in the event. It also assumes that the alert triggers the script to run before any other event takes place in the calendar, or it will return the latter event instead of the one that triggered the script.

This method is also capable of finding repeating events. (If you set an iCal event to repeat, iCal does not actually create those events, it only creates the first event and renders the subsequent time blocks in the calendar view.)

I wrote this script because I don't particularly care for the iCal plugin in Indigo 5.x for the following reasons: controlling Indigo by email is contingent on having functional internet access, which doesn't always happen: router, modem, ISP, mail service, and also hoping that the email comes back within a timely fashion without some weird delivery failure. Second, as the developers clearly state, the email plugin will respond to any email that is formatted for Indigo, and dutifully execute whatever it instructs; sounds dangerous. Finally, I personally think it's silly for a program on computer A to talk to another program on computer A by using computer B (the mail server) as an intermediary.

I have not tested this exhaustively, but so far it has been able to correctly find and extract information from iCal events nestled between other iCal events (subject to the aforementioned constraints). ***Edit: all of the cases I have tested it against are set to dispatch the alert 0 minutes before/after, in the iCal alert settings. If anyone can find cases where it does not work, or how it can be improved, then let us discuss the issues and solutions here to lead to a robust solution to this problem. ***Edit: I would like to keep the core script application-agnostic, but I encourage and welcome any discussion on optimizations or integrating it into other scripts for Indigo (or other applications).

Code: Select all
-- attempt to find the iCal event that triggered the alarm and extract the data

set eventList to {}
set referenceDate to the current date

-- first, construct a list of events that are not after the current time and date (seperately)
tell application "iCal"
   repeat with eventItem in events of calendar "Indigo"
      if the start date of eventItem does not come after referenceDate then
         
         set compareTime to the time of the (start date of eventItem as date)
         if compareTime does not come after the (time of referenceDate) then
            set the end of eventList to eventItem
         end if
      end if
   end repeat
end tell

-- second, find the closest iCal event that occurs at the same time as the alarm was triggered
-- and for whatever reason, I can't get it to work right using repeat with … in …
set bestMatch to item 1 of eventList
repeat with index from 1 to (count eventList)
   tell application "iCal"
      set compareDate to the start date of item index of eventList
      set previousBest to the start date of bestMatch
   end tell
   
   if compareDate comes after previousBest then set bestMatch to item index of eventList
end repeat

-- extract the data from the event
tell application "iCal"
   set eventSummary to the summary of bestMatch
   set eventDescription to the description of bestMatch
   set eventStartDate to the start date of bestMatch
   set eventEndDate to the end date of bestMatch
end tell


In the case of a repeating event, the start and end dates and times will be of the first chronological instance of that event in iCal. To translate them to today's terms, use the following:

Code: Select all
-- translate event dates to today
set startDate to the current date
set the time of startDate to the time of eventStartDate

set endDate to the current date
set the time of endDate to the time of eventEndDate


In addition, I have written an entire script that allows one to control devices, scenes and action groups within Indigo by putting instructions in the 'notes' section of the iCal event. It will also turn those devices and scenes off at the end of the event duration. I am still testing and tweaking it, but I will post it in a new thread when it is satisfactory.
Last edited by moscomedve on Mon Apr 02, 2012 9:23 pm, edited 2 times in total.

Posted on
Mon Apr 02, 2012 8:34 pm
jay (support) offline
Site Admin
User avatar
Posts: 18246
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Find iCal event that triggered script as alert

Check out the iCal Alarm Processor plugin - it does much of what your script does with less work - it just goes about it a different way.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Mon Apr 02, 2012 8:59 pm
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Re: Find iCal event that triggered script as alert

jay wrote:
Check out the iCal Alarm Processor plugin - it does much of what your script does with less work - it just goes about it a different way.


I did look into that before I investigated using a scripted solution. I have two reasons for making and using the script, one is that I wanted an Indigo-agnostic solution so that I (or anyone interested) can use it in other situations (e.g. Embedded scripts in Automator, etc), and second, and also for the aforementioned reason that I don't like the idea (from a practical and security standpoint) of using the included iCal alarm processor plugin.

Hopefully someday Apple will allow events to be sent as input to scripts, or have some command that can return the event that called the alert directly. Every time they release a software update involving iCal I send them feedback asking specifically for that, because I also find that it severely impairs what can be done with Automator. Until then, this script seems to function well in a way that can be included in Indigo (other application specific) scripts without having any of those application specific terms, or having to rely on email and fickle internet service.

Posted on
Mon Apr 02, 2012 9:10 pm
jay (support) offline
Site Admin
User avatar
Posts: 18246
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Solution: Find iCal event that triggered script as alert

I've given up on an alarm plugin API similar to what they have for Address Book - I think that was the only hope for having event data communicated outside of iCal.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Mon Apr 02, 2012 9:27 pm
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Re: Solution: Find iCal event that triggered script as alert

jay wrote:
I've given up on an alarm plugin API similar to what they have for Address Book - I think that was the only hope for having event data communicated outside of iCal.


I'm still in awe that even Automator isn't given any information about the triggering event, even when using the iCal Alarm template, which effectively does nothing different than the regular workflow, other than when you save it, Automator attaches it to a new event in a new calendar, without letting you choose. Oh well, I'll get down off my soap box now.

Posted on
Tue Apr 03, 2012 2:46 am
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Re: Solution: Find iCal event that triggered script as alert

Possible improvement:

I just woke up and realized that alarms within the iCal event have their own trigger dates and offset times. Perhaps rather than looking for the iCal event that is closest to the time the alarm was triggered, the script should try and match the alarm within the events to cross-reference it. It might also relieve the issue of strictly having to set the alarm time to 0 minutes after the event...

Sorry if this seems incoherent, but wanted to write it down before I forget in the morning.

Posted on
Tue Apr 03, 2012 4:28 am
DomoPat offline
User avatar
Posts: 210
Joined: Jul 17, 2010
Location: Toulouse, France

Re: Solution: Find iCal event that triggered script as alert

To avoid all these difficulties with iCal, I use iCalBuddy http://hasseg.org/icalBuddy. It's a very small command line program which returns the data from the database of iCal in a simple text format. It deals very well with the recurring events, this is why I found it. It made my scripts much more simple !

Posted on
Tue Apr 03, 2012 11:06 am
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Re: Solution: Find iCal event that triggered script as alert

DomoPat wrote:
To avoid all these difficulties with iCal, I use iCalBuddy http://hasseg.org/icalBuddy. It's a very small command line program which returns the data from the database of iCal in a simple text format. It deals very well with the recurring events, this is why I found it. It made my scripts much more simple !


Thanks, I'll take a look at that.

Posted on
Thu Jan 03, 2013 3:35 pm
moscomedve offline
Posts: 34
Joined: Apr 02, 2012

Re: Solution: Find iCal event that triggered script as alert

After finally getting back to this problem, I've decided to abandon a pure AppleScript solution. There are just too many caveats and exceptions that cause AppleScript to not find/match the correct events. Also, as of Mountain Lion, the sandboxing rules have apparently crippled Calendar's ability to run scripts as alarms, but it can still launch automator workflows (when saved as applications or iCal alarms); a script can simply be embedded into automator. iCalBuddy does a very nice job of tracking down iCal events. Here is an example of how to use iCalBuddy in AppleScript and extract the data from an event in a calendar called "Indigo" into a record object:

Code: Select all
set eventString to (do shell script "/usr/local/bin/iCalBuddy -nc -npn -iep title,notes,datetime -b '' -ps .§. -nnr '¶' -ic Indigo eventsNow")

set eventData to {eventName:"", notes:{}, startDate:"", endDate:""}

-- convert the string to a list, separated by '§'
set AppleScript's text item delimiters to "§"
set eventList to every text item of eventString

set eventData's eventName to eventList's first item

-- convert the time stamps to a list, separated by ' - ' and save them
set AppleScript's text item delimiters to " - "
set dateList to every text item of eventList's last item
set eventData's startDate to (date (dateList's first item))
set eventData's endDate to (date (dateList's second item))

-- convert the notes to a list, separated by '¶'
set AppleScript's text item delimiters to "¶"
set eventData's notes to every text item of (eventList's second item)


The above example uses § (option-6) so separate the different data fields, and ¶ (option-7) to split each line of the notes section into a separate list item (rather than the default \n with four spaces). This was simply a formatting/parsing convenience. This solution only returns events that have a duration of at least one minute and do not extend to or past midnight. It does not handle overlapping events either, but a more complex script could be written to handle this (iCalBuddy has options for returning events of different date ranges). I may provide an example later, but I hope this provides a starting point for anyone interested in extracting iCal information.

A more complete (but complex) script could be written to extract the location, url and uid of the event by omitting the -npn option and parsing through each field.

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 4 guests