Hunter Ford Hunter Ford

Use AppleScript to Format Contacts' E-Mail Addresses in All Lowercase

tell application "Address Book"
	-- Go through each record.
	repeat with thePerson in every person
		
		-- A person can have multiple e-mail addresses.
		repeat with account in email of thePerson
			set emailAddress to value of account
			
			-- Use Python to get the lowercase version This is less verbose than doing it all in AppleScript.
			-- Set up to avoid a "privilege violation" error.
			tell current application
				set formatted to do shell script "python -c \"print '" & emailAddress & "'.lower()\""
			end tell
			
			set value of account to formatted
		end repeat
	end repeat
	
	-- Save all Address Book changes.
	save
end tell

Growl Notifications for Apple Mail on Mac OS X

UPDATE: You can grab a beta version of 64-bit Growl 1.2 from the Growl beta site.
GrowlMail is broken on Mac OS X Snow Leopard (10.6). The dev team for Growl has a fix in the works, but I use Prowl and like to have notifications go to my iPhone when I'm not at my computer. So in the meantime, here is my solution.

Screen shot 2009-09-02 at 9.51.22 AM

I was originally inspired by James Higgs.

You first want to create a new AppleScript using AppleScript Editor and save it somewhere logical. I used /Library/Scripts/Mail Scripts/Rule Actions/Growl.scpt Below is the code:

-- Growl Alerts in Mail
-- Hunter Ford [http://www.cupcakewithsprinkles.com]
-- This script arises from the lack of any Growl Support in Mac OS X Snow Leopard (10.6)
-- Code inspired by and adapted from James Higgs [http://blog.jameshiggs.com/2009/08/28/growlmail-on-snow-leopard-a-temporary-fix/] as well as those mentioned.

tell application "GrowlHelperApp"
	-- Make a list of all the notification types
	-- that this script will ever send:
	set the allNotificationsList to {"New Email"}

	-- Make a list of the notifications
	-- that will be enabled by default.
	-- Those not enabled by default can be enabled later
	-- in the 'Applications' tab of the growl prefpane.
	set the enabledNotificationsList to {"New Email"}

	-- Register our script with growl.
	-- You can optionally (as here) set a default icon
	-- for this script's notifications.
	register as application "Mail" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "Mail"
end tell

-- Mail Rule Trigger
--
-- Source: Benjamin S. Waldie [http://www.mactech.com/articles/mactech/Vol.21/21.09/ScriptingMail/index.html]
using terms from application "Mail"
	on perform mail action with messages theSelectedMessages for rule theRule
		repeat with thisMessage in theSelectedMessages
			-- Process the current message

			-- Grab the subject and sender of the message
			set growlSubject to subject of thisMessage
			set growlSender to my ExtractName(sender of thisMessage)

			-- Use the first 100 characters of a message
			set growlMessage to (content of thisMessage)
			set growlLength to (length of growlMessage)

			if growlLength > 100 then
				set growlMessage to (characters 1 through 100 of growlMessage) & "…"
			end if

			set growlMessage to growlSubject & "

" & growlMessage

			-- Send a Notification
			tell application "GrowlHelperApp"
				notify with name "New Email" title growlSender description growlMessage application name "Mail"
			end tell
		end repeat
	end perform mail action with messages
end using terms from

-- *ExtractName*
--
-- gathers the name portion from the "From: " line
--
-- Source: robJ [http://forums.macosxhints.com/archive/index.php/t-19954.html]
to ExtractName(sender_)
	if sender_ begins with "<" then
		return text 2 thru -2 of sender_
	else
		set oldTIDs to text item delimiters
		try
			set text item delimiters to "<"
			set name_ to first text item of sender_
			set text item delimiters to oldTIDs
		on error
			set text item delimiters to oldTIDs
		end try
		return name_
	end if
end ExtractName

Run this first in the AppleScript Editor. As this is what will "register" the notification with Growl. Click the green "play" button that says "Run".

Screen shot 2009-09-01 at 10.46.18 PM

Then you want to create a new rule in mail that will run this script on every message that comes in.

Screen shot 2009-09-01 at 4.45.20 PM

Make sure to select "Don't Apply" that way you don't flood your screen with tons of Growl notifications.

Screen shot 2009-09-01 at 4.53.15 PM

Better Weather Script for Indigo

I find the weather script that comes with Indigo a bit lacking, and at times a little slow. Also, I prefer using the weather feed from Yahoo since it matches up to the weather widget in my dashboard.

You'll first need to get the right parameter for your local weather. Go to Yahoo Weather and type in your city/zip code. Just look at the URL and you should have something like: http://weather.yahoo.com/forecast/USGA0028.html

Grab what comes after 'forecast/' and before '.html' and replace 'USGA0028' in the script below.

property fetchTimeout : 15 -- don't wait for query response for more than 15 seconds...

try
    with timeout of fetchTimeout seconds
        do shell script "curl -s 'http://xml.weather.yahoo.com/forecastrss?p=USGA0028' | grep -E '(<yweather:condition|/\\>)' | sed -e 's/^.*temp=\"//' -e 's/\".*$//'"
        set temperature to result

        do shell script "curl -s 'http://xml.weather.yahoo.com/forecastrss?p=USGA0028' | grep -E '(<yweather:condition|/\\>)' | sed -e 's/^.*text=\"//' -e 's/\".*$//'"
        set conditions to result

        do shell script "curl -s 'http://xml.weather.yahoo.com/forecastrss?p=USGA0028' | grep -E '(<yweather:forecast day=\"|/\\>)' | sed -e 's/^.*high=\"//' -e 's/\".*$//' -e 'q'"
        set high to result

        do shell script "curl -s 'http://xml.weather.yahoo.com/forecastrss?p=USGA0028' | grep -E '(<yweather:forecast day=\"|/\\>)' | sed -e 's/^.*low=\"//' -e 's/\".*$//' -e 'q'"
        set low to result

        tell application "IndigoServer"
            if not (variable "weatherTemperature" exists) then
                make new variable with properties {name:"weatherTemperature", value:temperature}
            else
                if value of variable "weatherTemperature" is not temperature then
                    set value of variable "weatherTemperature" to temperature
                end if
            end if

            if not (variable "weatherConditions" exists) then
                make new variable with properties {name:"weatherConditions", value:conditions}
            else
                if value of variable "weatherConditions" is not conditions then
                    set value of variable "weatherConditions" to conditions
                end if
            end if

            if not (variable "weatherTemperatureHigh" exists) then
                make new variable with properties {name:"weatherTemperatureHigh", value:high}
            else
                if value of variable "weatherTemperatureHigh" is not high then
                    set value of variable "weatherTemperatureHigh" to high
                end if
            end if

            if not (variable "weatherTemperatureLow" exists) then
                make new variable with properties {name:"weatherTemperatureLow", value:low}
            else
                if value of variable "weatherTemperatureLow" is not low then
                    set value of variable "weatherTemperatureLow" to low
                end if
            end if
        end tell
    end timeout
end try

Adjusting the Climate upon Leaving and Restoring Previous Settings upon Return

When you're not at home, you generally don't need to have the A/C running at full blast. One simple solution for this is turn down your A/C when you leave, and turn it back up when you return. Using Indigo and a Insteon compatible thermostat, like the one from Venstar, make this a breeze. My original solution to this worked, but it didn't take into account my overrides of the thermostat. I've added a few variables to Indigo to save the thermostats current state when I leave, and restore it back to that state once I've returned.

For this to work, we're going to need to two triggers (which you may already have setup), and three action groups.

First, we need a trigger to set off the action group to save the settings (you could very well embed the action script into your trigger, but I usually modularize my scripts so that I can perform actions from a remote or from multiple triggers). I have a trigger that is called when I hit the "All Off" button on a KeypadLinc by my front door. I have another trigger that will restore my settings when I return; it is set off by a motion detector by my front door.

You'll need to create a few variables first: climateHeatSetpointPrevious, climateCoolSetpointPrevious, climateHvacModePrevious, climateFanModePrevious, climateHeatSetpointAway, climateCoolSetpointAway, climateHvacModeAway, climateFanModeAway

Now for the action groups:

1. "A/C - Save Current Settings"

if heat setpoint of device "Thermostat" is not value of variable "climateHeatSetpointAway" or cool setpoint of device "Thermostat" is not value of variable "climateCoolSetpointAway" or hvac mode of device "Thermostat" is not value of variable "climateHvacModeAway" or fan mode of device "Thermostat" is not value of variable "climateFanModeAway" then
    set value of variable "climateHeatSetpointPrevious" to heat setpoint of device "Thermostat"
    set value of variable "climateCoolSetpointPrevious" to cool setpoint of device "Thermostat"
    set value of variable "climateHvacModePrevious" to hvac mode of device "Thermostat"
    set value of variable "climateFanModePrevious" to fan mode of device "Thermostat"
end if

*Edit: I added the if statement so that if I hit the 'All Off' button twice by mistake, it wouldn't save my "away" settings as the "previous" settings.

2. "A/C - Set Away Settings"

set heat setpoint of device "Thermostat" to value of variable "climateHeatSetpointAway"
set cool setpoint of device "Thermostat" to value of variable "climateCoolSetpointAway"
set hvac mode of device "Thermostat" to value of variable "climateHvacModeAway"
set fan mode of device "Thermostat" to value of variable "climateFanModeAway"

3. "A/C - Restore Previous Settings"

set heat setpoint of device "Thermostat" to value of variable "climateHeatSetpointPrevious"
set cool setpoint of device "Thermostat" to value of variable "climateCoolSetpointPrevious"
set hvac mode of device "Thermostat" to value of variable "climateHvacModePrevious"
set fan mode of device "Thermostat" to value of variable "climateFanModePrevious"

*Edit: You may have to add some 1 second delays (delay 1) to ensure the signal is received by the thermostat. The Venstar adapter is wireless and therefore more prone to getting error messages like: "send failed (no acknowledgment)".