Scripts to Send an SMS Text Message When You’re Idle on Adium (for Mac OS X)

2012, May 10  —  ...

I work in an industry, technology, where we're basically working around the clock. Even "after hours" I'm checking work email and monitoring the team chat room. Every so often, I miss out on the fact that somebody is trying to reach me in the chat room. Either the sound on my computer is muted, not loud enough, or I'm just out of the house. To solve this problem I decided that it would be great if I could receive an SMS text message whenever somebody tries to reach me via chat after my computer has been idle for 15 minutes.

I started down the path of writing an AppleScript (since this is already built into Adium) to make this work but quickly became frustrated by this approach when I discovered that the sender nor the message were accessible in the AppleScripts. I eventually found a blog post announcing an Adium Xtra, called Pipe Events, which, when triggered, will run a shell script with the message as STDIN and the sender as the first argument. It's a decent plugin but has a pretty frustrating bug, if you script has an output to STDOUT or the shell, the script will stop running at that point with a broken pipe. So make sure your scripts are silent.

Setup

You'll need a few things to get started.
  1. An account on If This Then That, a great tool to glue together different API driven sites on the internet using very elementary scripts.
  2. Use this recipe on If This Then That:  Send email to ifttt with #adium in the subject and receive SMS text message.
  3. Next you'll need the mail gem. I use rvm but if you do not, then ignore the first line.
$ rvm use 1.9.2-p180
$ gem install mail

The Script to Run the Script

I decided to run my script using ruby but since I'm using rvm, I ran into some issues trying to get /usr/bin/ruby working with the gems required to make this work. Therefore, the first step was to write a bash script to invoke rvm. Using the rvm docs on scripting as a guide, I created this script to invoke my ruby script.
#!/bin/bash
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
  # First try to load from a user install
  source "$HOME/.rvm/scripts/rvm"
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
  # Then try to load from a root install
  source "/usr/local/rvm/scripts/rvm"
else
  logger "ERROR: An RVM installation was not found." 1>&2
fi

# Uncomment this log the output of this command to system.log
# The output should be: "rvm is a function"
# logger `type rvm | head -1`

# Suppress output or else the Adium Xtra, Pipe Events will break
rvm use 1.9.2-p180 > /dev/null

# Run ruby script
ruby ~/bin/adium_alert.rb $1 < /dev/stdin

The Ruby Script

The following script will retrieve the ide time of the system and send an email, via gmail, to ifttt to trigger the SMS text message. In the script below I also log all messages to a log file regardless of the idle time.  To get the idle time, I used the method described in this Mac OS X Hints article. The only thing I don't like about this script is that it has to contain my email password. I would eventually like to change it to use Google OAuth for IMAP/SMTP.
require 'rubygems'
require 'mail'

time = Time.now
#idle_time = `ioreg -c IOHIDSystem | perl -ane 'if (/Idle/) {$idle=(pop @F)/1000000000; print $idle,"";last}'`

# Get the system idle time
idle_time = `ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/!{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'`.to_f / 1000000000

# Format the message
msg = "#{time.strftime('%y-%m-%d %H:%M:%S')}: from #{ARGV[0]} - #{STDIN.read.strip} (idle: #{idle_time})"

# Log the message to a file
File.open("#{ENV['HOME']}/adium.log", "a+") do |f|
  f.puts msg
end

# If idle time is greater than 15 miuntes, send an email
if idle_time.to_i >= 15*60
  begin
    Mail.defaults do
      delivery_method :smtp, {
        :address => 'smtp.gmail.com',
        :port => '587',
        :user_name => 'gmail_user_name',
        :password => 'gmail_password',
        :authentication => :plain,
        :enable_starttls_auto => true
      }
    end
    Mail.deliver do
      to "trigger@ifttt.com"
      from "email_address_expected_by_ifttt@example.com"
      subject "#adium"
      body msg
    end
  rescue Exception => e
    # Log errors
    File.open("#{ENV['HOME']}/adium.log", "a+") do |f|
      f.puts "#{e.message}: #{e.backtrace}"
    end
  end
end