Category Archives: Productivity

How to create, remove and manage geofence reminders in iOS programmatically with Xcode

I’ve been a fan of geofencing since way back in the days of Where’s Tim. I spoke at the University of Kansas back in 2006 about how exciting it would be to one day have location aware checklists.  Now, with mobile devices running iOS 6, we can take advantage of the reminders API to add and remove location-based items. This saves us from writing a ton of code to manage our own geofencing framework.

I use this feature in Christian Radio Locator to allow users to set alerts when they enter into listening range of a particular station.

To add a reminder, we make sure the device is running iOS 6 or greater, then ask the user for permission to access their reminders. We create a new reminder and set the title and location. Then the distance range of when to alert the user. This will be specific to the situation. For a reminder triggered by Target, you’d want it to be only a 100 meters or so to avoid drive-by triggering. For a “call my wife when I’m getting close to home” situation, the range would be 2000 or 3000 meters. If everything is configured correctly, the API will add the reminder to the system and hand back an eventID, which should be store internally in the application to allow the user to remove the reminder and to avoid entering duplicates.

To remove a reminder, pass in the eventID and tell the API to remove it from the system. There seems to be a five to ten second delay, which makes debugging difficult. We can also query the reminders to display them in our app and to make sure the user hasn’t checked any off from Reminders.app.

Connecting to Event store

Here is the code to get the Event store. The store object will process all the add and remove messages. As the code indicates, the store object is cached locally once is has been successfully retrieved. There is also an unknown delay between requesting the store and the system asking the user for permission. That is why the providedAccess ivar is set via a block.

- (EKEventStore*) getEventStore{

    if (eventStore) {

        return eventStore;

    }

    

    EKEventStore *store = [[EKEventStore alloc] init];

    __block BOOL providedAccess = YES;

    BOOL atLeastIOS6 = [[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0;

    if (!atLeastIOS6) {

        providedStoreAccess = NO;

        return nil;

    }

    [store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {

        providedAccess = granted;

    }];

    [self setProvidedStoreAccess:providedAccess];

    [self setEventStore:store];

    return store;

}

Adding location-based reminder to store

Now that we have the store, we can add a location-based reminder that will use the built-in geofencing. This will also display the outlined GPS symbol on the users Status Bar so they know they have a location-based reminder. Note that we are storing the eventID in NSUserDefaults so we can retrieve the details about it later.

- (BOOL) addReminder{

    //make sure there is a store to get to

    EKEventStore *store = [self getEventStore];

    if (!store) {

        return NO;

    }

    

    //make sure the user provided access to the store

    if (!providedStoreAccess) {

        return NO;

    }

    EKReminder *reminder = [EKReminder reminderWithEventStore:store];

    [reminder setTitle:[NSString stringWithFormat:@"Listen to %@ (%@)",station.ownedBy,station.frequency]];

    [reminder setNotes:[NSString stringWithFormat:@"%@ %i mile range",station.city, (int)[station.range doubleValue]]];

    //create the geofence alarm

    EKAlarm *enterAlarm = [[EKAlarm alloc] init];

    [enterAlarm setProximity:EKAlarmProximityEnter];

    EKStructuredLocation *enterLocation = [EKStructuredLocation locationWithTitle:[NSString stringWithFormat:@"%@ (%@)",station.ownedBy,station.frequency]];

    CLLocationDegrees lat = [station.lat doubleValue];

    CLLocationDegrees lng = [station.lng doubleValue];

    CLLocation *radioLocation = [[CLLocationalloc] initWithLatitude:lat longitude:lng];

    [enterLocation setGeoLocation:radioLocation];

    //convert our range from miles to meters then set the radius

    //the alarm will go off when the user enters this radius

    [enterLocation setRadius:[station.range doubleValue] * 1609];

    [enterAlarm setStructuredLocation:enterLocation];

    [reminder addAlarm:enterAlarm];

    [reminder setCalendar:[store defaultCalendarForNewReminders]];

 

    NSError *err;

    [store saveReminder:reminder commit:YES error:&err];

    [self setEventId:reminder.calendarItemIdentifier];

    

    //store the event id so we can track if the user

    //has a geofence reminder for this station

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSDictionary *reminders = [defaults objectForKey:@"reminders"];

    NSMutableArray *latlng = [NSMutableArray arrayWithArray:reminders.allKeys];

    NSMutableArray *itemIds = [NSMutableArray arrayWithArray:reminders.allValues];

    

    [latlng addObject:[NSString stringWithFormat:@"%@%@",station.lat,station.lng]];

    [itemIds addObject:eventId];

    

    NSDictionary *newReminders = [NSDictionary dictionaryWithObjects:itemIds forKeys:latlng];

    [defaults setObject:newReminders forKey:@"reminders"];

    [defaults synchronize];

    

    return YES;

}

Removing reminders

If the user wishes to remove or check off the event, they can do so in reminders.app, or we can do it programatically.

- (BOOL) removeReminder {

    if (eventId.length == 0) {

        return NO;

    }

    EKEventStore *store = [self getEventStore];

    if (!store) {

        return NO;

    }

    if (!providedStoreAccess) {

        return NO;

    }

    

    EKReminder *reminder = (EKReminder *)[store calendarItemWithIdentifier:eventId];

 

    NSError *err;

    [store removeReminder:reminder commit:YES error:&err];

    

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSDictionary *reminders = [defaults objectForKey:@"reminders"];

    NSMutableArray *latlng = [NSMutableArray arrayWithArray:reminders.allKeys];

    NSMutableArray *itemIds = [NSMutableArray arrayWithArray:reminders.allValues];

    

    [latlng removeObject:[NSString stringWithFormat:@"%@%@",station.lat,station.lng]];

    [itemIds removeObject:eventId];

    

    NSDictionary *newReminders = [NSDictionary dictionaryWithObjects:itemIds forKeys:latlng];

    [defaults setObject:newReminders forKey:@"reminders"];

    [defaults synchronize];

    

    [self setEventId:@""];

    returnYES;

    

}

Staying in sync with Reminders.app

We want to be able to display to the user the reminders that our app has set for them. We also need to make sure that we stay in sync with the Event store in case the user checked off or deleted a reminder that our app created.

- (void) setReminderCellDisplay{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    

    NSDictionary *reminders = [defaults objectForKey:@"reminders"];

    

    //check if the user has any stored reminders to display to them

    if (reminders.count == 0) {

        return;

    }

    

    EKEventStore *store = [self getEventStore];

    if (!store) {

        return;

    }

    if (!providedStoreAccess) {

        return;

    }

    NSMutableArray *remindersToRemove = [[NSMutableArray alloc] init];

    for (NSString *key in reminders) {

        //making sure that no events have been removed outside of this application

        //if so, we are going to remove it from the collection and not mark the reminder cell

        BOOL skip = NO;

        NSString *eventIdFromReminders = [reminders valueForKey:key];

        EKReminder *reminder = (EKReminder *)[store calendarItemWithIdentifier:eventIdFromReminders];

        if (!reminder || reminder.completed) {

            [remindersToRemove addObject:eventIdFromReminders];

            skip = YES;

            NSLog(@”Need to remove:%@”,eventIdFromReminders);

        }

        //this station does have a reminder associated with it

        if ([[NSString stringWithFormat:@"%@%@",station.lat,station.lng] isEqualToString:key] && !skip) {

            [reminderCell setAccessoryType:UITableViewCellAccessoryCheckmark];

            [self setEventId:eventIdFromReminders];

        }

    }

    //nothing to remove…carry on

    if (remindersToRemove.count == 0) {

        return;

    }

    

    NSMutableArray *latlng = [NSMutableArray arrayWithArray:reminders.allKeys];

    NSMutableArray *itemIds = [NSMutableArray arrayWithArray:reminders.allValues];

    

    //we have a reminder that we need to get rid of

    for (NSString *eventIdToRemove in remindersToRemove) {

        NSUInteger index = [itemIds indexOfObject:eventIdToRemove];

        [latlng removeObjectAtIndex:index];

        [itemIds removeObjectAtIndex:index];

        NSLog(@”Removed:%@”,eventIdToRemove);

    }

    

    NSDictionary *newReminders = [NSDictionary dictionaryWithObjects:itemIds forKeys:latlng];

    [defaults setObject:newReminders forKey:@"reminders"];

    [defaults synchronize];

}

Summary

This blog post showed how to create and manage location-based reminders for iPhones and iPads. Geofencing is a powerful tool that we can use to make our lives more productive…or to make sure we don’t miss any of our favorite radio stations.

Prevent clamshell laptop from sleeping when using AirPlay on Mountain Lion

We cut our cable several years ago and have watched most of our TV on Hulu by connecting a laptop to our TV using an HDMI cable. This has always worked fine, but it was a pain to connect the cables and quite often the sound didn’t work.

I was excited to hear that the new version of Mac OS X (Mountain Lion) would have native support for AirPlay mirroring to our AppleTV. I’ve used apps like AirFlick before, but it never worked with Hulu. I finally had a chance to use the AirPlay mirroring to watch a show last night and was disappointed to find that I couldn’t close the lid to my laptop without it going to sleep.

No physical cable

Previously, I was using an HDMI cable and the TV was essentially a second display. The laptop was smart enough to know that when I closed my lid, it should use the TV as the primary display and not go to sleep. With the lack of a physical cable plugged it, it didn’t know to stay awake.

I could have change my power settings to never go to sleep, but usually when I close the lid, I want it to sleep. I don’t want to have to remember to change my settings before and after I use AirPlay.

NoSleep Extension

NoSleepHelper

Enter the NoSleep Extension by Pavel Prokofiev. It lives in the menu bar and simply prevents my laptop from going to sleep when I close the lid. Clicking the icon toggles the functionality and right-clicking offers a preference pane where it is possible to target the no sleep behavior to only battery or power adaptor environments.

NoSleep 2

This is a great utility that does one simple thing and does it well. Now I can watch my shows and not worry about burning up my display by leaving the laptop open. Kudos to the developer of this app.

Editing Folder Action Scripts

Scanner folder evernote 

I have a Folder Action Script set up where when if I scan a file to a specific folder, it uploads it to Evernote. I have it go to a queue notebook called tofile. This way, when something important comes in, I can scan it to Evernote and shred or recycle the actual document. Additional, the watched folder is in my Dropbox, so I can add files to that folder from my phone or a different computer. The next time I get online with my laptop, Dropbox will download that file, then my action script will kick in and upload it to Evernote.

Anytime I need to make a change to this script, I can never remember where it is or how to edit it. Hopefully by posting instructions here, I’ll remember next time.

Accessing the file:

In Finder, select “Go to Folder” from the “Go” menu and type:

/Library/Scripts/Folder Action Scripts/

To edit the script:

  1. Drag the file to your desktop.
  2. Edit file and save changes.
  3. Drag the file back to the Folder Action Scripts folder. You’ll have to authenticate the operation.

There is no need to reassign the script back to the folder. It just works.

Image source: Markus Malzner

CC emails are not worthy of being pushed

I’m on a quest to be more productive. The best way to allow more productivity is to eliminate distractions and focus on what is important by ignoring that which is not. Push email is the best worst thing to happen in technology in the last few years. I love that I can be immediately available to the people that need (and warrant) my attention right now, but don’t like having my entire thought process hijacked by the ding of a new email.

Most of these new emails are not important. They are automatic notifications that I’ve set up that I can deal with at a later time, or they are a never-ending email thread that I was unlucky enough to be cc’ed on. We’ve all been on an email thread that went on way too long and had way too many participants. They never stop and they never get anything done. So I decided to not push emails that I was cc’ed on to my phone. Essentially, if I was cc’ed on it, it is for my information only and doesn’t require my immediate attention.

Here is how I set it up using Google Apps for domain:

Create a label called “no push” and enable IMAP so we can easily get to it from a mail client.

Create a filter that will sift out mail cc’ed to me and apply the “no push” label. The syntax is “cc:me”

20120503-212334.jpg

I still want to be able to cc emails in my inbox, just not have them sent to my phone. So I added the label to one of my inboxes.

20120503-212522.jpg

I’ve been using this system for almost two months and it has really cut down on how often my phone is buzzing with new emails.

Of course, many things can be filtered to be put the “no push” label. Bank statements, facebook notifications, anything that will provide an immediate distraction, but still needs to be looked at later.

Using ifttt to put stuff in the right boxes

I’ve been using ifttt lately to keep my digital life organized. We have places at home for our physical stuff, yet we let our inbox handle our to-do items, project management, reminders, notebooks and vault. It’s like one big digital junk drawer.

In my pursuit of focusing on what is important by ignoring that which is not, I’ve been using a combination of ifttt, Evernote and Readability to automatically help triage my Gmail and Google Reader.

Google Reader management

I follow a lot of blogs. Part of my job is making sure I’m up on the latest trends in technology so I know which direction EnGraph needs to be heading as a company. I follow lots of .NET, WPF, transit and mobile blogs and honestly, a lot of it is regurgitation. I scan the posts and star the ones that look interesting enough to read later. This is where ifttt comes in.

As soon as I star it, it gets placed in my Readability queue and it is there on my iOS device when I have a moment to dedicate to it.  I don’t have to remember to go back to Google Reader and look at my starred items.

Now, let’s say a particular article is really good and I want to spend more time on it, or write a post about it. I can star the article in Readability and ifttt will kick in again.

Ifttt will take that article, download an excerpt of  the text and place it along with the URL into an Evernote notebook I have called good articles. Now I will always have that article and it will show up in my Evernote searches.

To triage Google Reader on the go, I use FeeddlerRSS on my iOS devices.

Additionally, I have a ifttt task set up to grab anything I favorite on twitter and dump into readability.

As a bonus, there are excellent Chrome Extensions for Evernote and Readability.

Personal finances

After battling with Money and Quicken for years, I’ve finally settled on Mint (for now) to manage our personal finances. I’ve set up a tag called reconciled that I label on every transaction that I’ve physically verified. This way I can do a “-tag:reconciled” search and see all the transactions that I need to still look at to make sure they are accurate and properly categorized.

Using the Mint iOS app helps enter transactions on the go, but my wallet still was stuffed full of receipts and my inbox was overflowing with bill pay and money transfer notifications.

The battle for me is pulling out my wallet, getting all the receipts out, flattening them out, logging into the site and starting the reconciliation process. By the time I was actually doing work I had invested a significant amount of time. With two small kids and a third on the way, along with running a small business, I invariably am going to run into an interruption. So then I’d have to put my receipts back in my wallet and start the process again later.

I set up a notebook in Evernote call rec. What I do now is take a receipt out of my wallet, take a picture of it with my phone and email it to my Evernote email address with a @rec tag. If I get interrupted, no big deal, I recycle the receipts I’ve logged and move on with my life. When I have a spare moment, I open my Evernote on one of my devices, and Mint on a different one, reconcile the receipt, then delete the note containing the receipt from my notebook. Again, no big deal if I get interrupted. In fact, the two processes of entering and reconciling are now decoupled and they are independent from each other.

To prevent my Gmail from turning into its own separate personal finance queue, I set up an ifttt rule that pushes any new emails that I have labeled as money and sends it to my rec notebook.

I can also forward emails from my wife directly to my rec notebook.

Other fun recipes

Post any picture I take on instagram to this blog.


The answer is, “because I can”.

Check out more fun recipes.

For me, if I put something in it’s correct place, I’m more likely to give it the attention it deserves. Ifttt helps me put my digital stuff in the right boxes.

Focus on what is important by ignoring that which is not

Last month, I attended Nebraska Code Camp and listened to an incredible talk by Scott. It had to do with eliminating distractions and focusing on the current task at hand. It was everything that I knew to be true and had always tried to maintain, but couldn’t ever execute just right. Scott gave some great concrete examples during his talk that I’ve hit the ground running with. I’ll bullet them with the intention of linking to future posts of how I’ve been implementing them.

Last month, Scott spoke at WebStock and the talk was filmed and released. I’ve already scheduled a yearly meeting at EnGraph to watch this with the crew.