Published on July 23, 2013

Working at Blackboard Mobile making unique mobile apps is fun, but occasionally it’s interesting to do something completely different at work, just to see what you can come up with. To that end, we recently hosted our first Hackathon, where small teams of co-workers had 24 straight hours to create a project of any theme using resources available inside our outside of the office, and the results would be judged by our peers.

One of the other benefits of working in a growing industry is that we’re expanding our staff almost weekly. Unfortunately, though, that means that the building we’re in is less and less able to handle the increasing capacity. Specifically, the bathrooms are occupied more frequently, resulting in either a return trip to your desk only to try again later, or an awkward wait of unknown duration.

Working with Joe Taylor and Eric Littlejohn, our Hackathon project set out to make the office bathroom availability more visible and accessible through a combination of hardware and software.

The piece of the project that lets this all work is a switch installed inside each door jamb, such that when the locking bolt is engaged, the switch is tripped. That way we, can do anything with resulting data, knowing that when the door is locked, the room is in use. Running wire down through the hollow metal trim was tedious and time consuming, and involved a lot of false starts and fishing around with a straightened coat hanger, but we finally got a run of wire inside each frame.

On each office floor there are two bathrooms side by side, and the pair of switches inside the door jambs are wired to a single Arduino fitted with an Ethernet Shield for network connectivity. The Arduino samples the switches many times per second, providing near-instant feedback.

After debouncing the switch input signal over about 50 milliseconds, the Arduino waits for a definitive change in state — from locked to unlocked, or unlocked to locked — before illuminating LED lights on the wall.

After the light corresponding to the now-occupied bathroom is lit, the Arduino also performs an HTTP POST, sending the event details (floor level, which room, and current occupancy state) to an in-house webserver running Node.js and MongoDB. The webserver records the data and makes it visible on a web page for viewers to check the availability digitally, for those who can’t see the wall mounted lights from their seating position.

If you’d like to employ a project like this, the code we hacked together is available on GitHub, and the wiring is rather straightforward:

  • All components share a common ground
  • LED anodes are wired to room_a_led_pin and room_b_led_pin and brought high when doors are locked, and low when unlocked
  • Switches bring room_a_switch_pin and room_b_switch_pin low when triggered, and the Arduino uses the INPUT_PULLUP pinMode for the unlocked state

Our Hackathon project came in at second place, losing to an as-yet-unannounced software project, but we had a lot of fun staying up and hacking all night!

Published on June 6, 2013

I recently purchased a pair of Nest Learning Thermostats for my new home. Compared to the white brick style Honeywell thermostats that came with the place, the Nest is so much more advanced. It does temperature learning, auto-away, and remote control over Wi-Fi from the web and iOS devices. It also has a color LCD and just generally looks beautiful on the wall in its brushed stainless steel housing.

Installing the Nest is pretty straightforward with a modern forced air heating and cooling system:

  • Remove the old thermostat and mounting plate from the wall
  • Disconnect the wires
  • Patch and paint any holes
  • Install the Nest mounting base and connect the wires
  • Pop the Nest onto the base and configure the software

My initial install went well physically, but not long after, I discovered that the Nest would regularly run out of battery power. I quickly learned that due to how the HVAC circuits are arranged, the Nest can only draw power while the system is running. When the system is not busy heating, cooling, or running the fan, the Nest is left to run under its own battery power. And in sunny California during the springtime, the system doesn’t run often enough to let the Nest keep a charge. Several times per day, I would have to unplug the Nest from its base and charge it over micro USB. Not a great solution.

Reading more about the Nest and HVAC circuitry, I found that there is a solution for situations like this. A “common wire” that provides a path back to the HVAC controller would allow the Nest to draw the power it needs while not running any systems. As luck would have it, my system provided this common wire, but connecting it to the Nest had no battery effect, and the Nest did not detect that the wire was connected.

So, I decided to find out what was at the other end of that common wire. I put up a ladder and ventured into the attic area of my home and scouted around the furnace. On top of it, inside an easily-opened steel enclosure, was the thermostat controller, a ZTech ZTE2S. Double checking the wiring diagram and comparing it with the wires on the left (coming from the Nests), it’s clear that the blue common wire is simply not connected to the controller. In the photo below, you can see that it’s clipped short, close to the jacket covering the bundle of five wires.

Reconnecting the wire was a matter of disconnecting the wires that were connected, snipping them all to the same length, and stripping a little plastic off the end so that all five can be connected to the HVAC controller.

A few hours after leaving the Nest installed with the common wire attached and the HVAC controller all closed up, its battery has fully charged and the features work great.

Published on January 7, 2012

Widerbug

Good news Widerbug users!

The dedicated Firebug team has just added the widescreen option that Widerbug enables into the core of Firebug 1.9.0, making Widerbug obsolete. You may uninstall Widerbug and go back to using regular Firebug and be able to change the layout using the option seen below.

Firebug widescreen support

This is welcome news to all Widerbug users, I imagine. It’s been difficult to keep up with Firefox’s new fast-track release schedule, as well as continually adapting to the Firebug internal changes. Now you can enjoy widescreen support, with Firebug in one of several locations, without sacrificing new critical updates and feature improvements.

Published on June 20, 2011

Mac OS X is an increasingly popular platform for web developers, client-side and server-side alike. For doing intensive PHP development on OS X, you can use a full-blown IDE like Zend Studio or PhpStorm, but I like my toolkit to be much more lightweight. I prefer to code in TextMate, execute SQL queries in Querious, run code in Safari, and perform technical tasks in Terminal. Absent from this agile team, though, is a true PHP debugger, leaving you with only rudimentary calls like printf and var_dump for debugging. Worse still, you have to change your code just to debug it. We can do better. Recently, I discovered an excellent tool that filled the need for a lightweight PHP debugger. MacGDBp communicates with PHP using the Xdebug PHP extension, and offers variable inspection, stepping controls, breakpoints, and a call stack, all in a native Cocoa app — no bloated Java IDEs required:

MacGDBp debugging a Zend Framework application

What is Nginx?

Nginx is a web server similar to Apache, in that it’s capable of serving web content over HTTP and HTTPS to visitors. While Apache is far and away the most common web server — currently serving up about 64% of all websites on the internet — it’s also about a decade older than Nginx. Being newer, Nginx doesn’t have all the baggage that Apache has accumulated over that time, and it’s only gaining in usage, particularly on high-traffic sites. In addition, Nginx’s config file format is much saner and less verbose than Apache’s, simplifying setup. The only speed bump I’ve run into with Nginx is a lack of .htaccess support, requiring your URL rewrites to be done in your site’s configuration file, as opposed to read at runtime. It’s a different approach, but it helps you centralize your configurations instead of spreading them throughout your project. This way, environment-related details are kept in the web server environment, and the application code base is all about the application.

What is PHP-FPM?

PHP-FPM was originally a standalone source code patch that added independent process management to PHP, but is now included as part of the PHP project. When Apache handles web requests, its PHP module gets loaded even if it’s not needed, wasting time and memory. By contrast, under PHP-FPM, processes are launched as demand increases (up to limits we’ll set), increasing speed and reducing memory usage. With the setup detailed below, you’ll be able to run PHP with Nginx and debug server-side code with the simplicity of a Mac application. A build of MySQL 5.5 is also included, but you could, of course, substitute your preferred database if desired.

Install Xcode

Many of the following steps depend on a compiler and other programs that are included with Apple’s Xcode developer tools. A version of Xcode is included on your Mac OS X Install DVD, and a more recent version is available on the Mac App Store. Registered Mac and iOS developers can download a copy through the Apple Developer site. Any version that’s compatible with your Mac OS X version should suffice. For this tutorial, I’m running Mac OS X 10.6.7 and Xcode 4.0.2. The default install of Xcode should provide everything you need to complete this step.

Install X11

Some of the libraries we’ll use aren’t part of a default OS X install, but are provided by Apple in their optional X11 distribution. Insert your Mac OS X Install DVD or USB drive and open the “Optional Installs” folder and run the “Optional Installs.mpkg” package. When you get to the customization screen, open the Applications disclosure triangle, and check off X11 before performing the install.

Install Homebrew

Homebrew is a package manager for Mac OS X, similar to yum for Linux. It’s a faster, lower-overhead alternative to other OS X package managers like MacPorts and Fink. We’ll be using it to install a few dependencies. To get things rolling, open a Terminal window, and run:

ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

Create a Place to Work

We’ll need some easily-accessible place to download source code and build it, so a SourceCache folder in the your Home folder is as good a place as any.

mkdir ~/SourceCache

Download and Build Nginx

Building and installing Nginx is fairly straightforward. We’ll download the code from the Nginx site, unpack it, install a single dependency using Homebrew, configure, compile, and install:

cd ~/SourceCache
curl -O http://nginx.org/download/nginx-1.0.4.tar.gz
tar -xzf nginx-1.0.4.tar.gz
cd nginx-1.0.4
brew install pcre
./configure --prefix=/usr/local/nginx --pid-path=/usr/local/nginx/var/run/nginx.pid --with-http_ssl_module
make
sudo make install

Nginx is now installed and ready to run. With the creation of a small file, you can even set Nginx to run at startup. Mac OS X uses launchd to run scripts at the appropriate time, so we’ll create a simple launchd plist to start Nginx at boot. I’ll be using TextMate’s built-in mate command to edit files here, but you can use vi, nano, or any other text editor that floats your boat.

sudo mate /Library/LaunchDaemons/org.nginx.nginx.plist

Then paste in this plist content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>org.nginx.nginx</string>
    <key>LaunchOnlyOnce</key>
    <true/>
    <key>NetworkState</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/nginx/sbin/nginx</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>Nginx web server</string>
    <key>StandardErrorPath</key>
    <string>/var/log/system.log</string>
</dict>
</plist>

Edit Nginx Config Files for PHP

Nginx is now ready to run on its own, but it still needs to be told where to look for your sites on disk, and how to handle

.php files once we install PHP. We can create some config files now so that they work after the PHP install is complete. This first config file is a basic Nginx config file. You’ll want to replace “collin” towards the top of the file with your own OS X short username (which you can see by running whoami), so that Nginx runs as your user. Or, if you prefer, you can add a new user and group dedicated for Nginx. Since this is just a local development setup and not a production web server, I didn’t bother going that route.

sudo mate /usr/local/nginx/conf/nginx.conf

Here is the content for the config file:

user collin staff;
worker_processes 2;

events {
    worker_connections 1024;
}

http {
    include mime.types;

    default_type text/plain;
    server_tokens off;

    sendfile on;
    tcp_nopush on;
    keepalive_timeout 10;

    gzip on;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types text/plain text/css text/javascript application/json application/x-javascript text/xml application/xml application/xml+rss;

    index index.html index.php;
    include sites-enabled/*.link;
}

After we install PHP, Nginx will need to know how to interact with it. Unlike running PHP as an Apache module, PHP-FPM runs its own separate set of processes, and Nginx has no idea they exist unless you tell it about them. Nginx communicates over the FastCGI protocol, with the master process listening on a local port so it can handle PHP requests from Nginx. Now we’ll create an Nginx config file that holds all the details about PHP-FPM. Note that, at the bottom of this config file, we instruct FastCGI to listen on port 9001 instead of the default port 9000. This will come into play later when we setup the debugging tools.

sudo mate /usr/local/nginx/conf/php.conf

fastcgi_intercept_errors on;

location ~ \.php$
{
    fastcgi_split_path_info ^(.+\.php)(/.+)$;

    fastcgi_param PATH_INFO         $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED   $document_root$fastcgi_path_info;
    fastcgi_param QUERY_STRING      $query_string;
    fastcgi_param REQUEST_METHOD    $request_method;
    fastcgi_param CONTENT_TYPE      $content_type;
    fastcgi_param CONTENT_LENGTH    $content_length;
    fastcgi_param SCRIPT_NAME       $fastcgi_script_name;
    fastcgi_param SCRIPT_FILENAME   $document_root$fastcgi_script_name;
    fastcgi_param REQUEST_URI       $request_uri;
    fastcgi_param DOCUMENT_URI      $document_uri;
    fastcgi_param DOCUMENT_ROOT     $document_root;
    fastcgi_param SERVER_PROTOCOL   $server_protocol;
    fastcgi_param GATEWAY_INTERFACE CGI/1.1;
    fastcgi_param SERVER_SOFTWARE   nginx;
    fastcgi_param REMOTE_ADDR       $remote_addr;
    fastcgi_param REMOTE_PORT       $remote_port;
    fastcgi_param SERVER_ADDR       $server_addr;
    fastcgi_param SERVER_PORT       $server_port;
    fastcgi_param SERVER_NAME       $server_name;

    fastcgi_read_timeout 600; # Set fairly high for debugging

    fastcgi_pass  127.0.0.1:9001; # Non-default port
    fastcgi_index index.php;
}

Nginx is now configured to talk to PHP, but only when we include this particular config file in a particular site’s config file.

Configure Local Sites

At the bottom of the main Nginx config file, we called

include sites-enabled/*.link. We’ll now create sites-available and sites-enabled folders to hold config files for each site you develop locally. sites-available will hold all available site config files, and sites-enabled will contain only symbolic links to the config files of enabled sites, allowing you to turn local sites on and off just by linking or unlinking their config files and restarting Nginx.

sudo mkdir /usr/local/nginx/conf/sites-available
sudo mkdir /usr/local/nginx/conf/sites-enabled

With those two folders available, we’ll set up an example site that will make use of the PHP config file above. Again, you’ll want to replace “collin” with your own username so Nginx looks in the correct folder for website content.

sudo mate /usr/local/nginx/conf/sites-available/example.conf

server
{
    listen 80;
    server_name example.local;
    root /Users/collin/Sites/example/public;

    access_log /Users/collin/Sites/example/logs/access_log.txt;
    error_log /Users/collin/Sites/example/logs/error_log.txt;

    location /
    {
        index index.php;
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    include php.conf;
}

Now we can enable the site by symlinking the config file from the sites-available folder into the sites-enabled folder:

sudo ln -s /usr/local/nginx/conf/sites-available/example.conf /usr/local/nginx/conf/sites-enabled/example.link

While we’re configuring this site, we should also create the actual folder structure on disk. The

public folder will be where Nginx considers the web-accessible root to be when visited in a web browser, and logs will be where Nginx (and possibly your web application) puts log files.

mkdir -p ~/Sites/example/public
mkdir -p ~/Sites/example/logs

Finally, we need to make sure that visiting

example.local in a browser actually routes to your computer (if you were to visit it right now, more than likely nothing would happen):

sudo mate /etc/hosts

Add the following line to the

end of the file:

127.0.0.1 example.local

And with that, we’ve configured a local website for Nginx.

Install MySQL With Homebrew, installing MySQL is the easiest of all the installs we’ll perform. This build of MySQL via Homebrew includes a launchd script, which we’ll copy into the LaunchDaemons folder just like we did with Nginx.

brew install mysql
unset TMPDIR
mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp
sudo cp /usr/local/Cellar/mysql/5.5.10/com.mysql.mysqld.plist /Library/LaunchDaemons/

Install PHP Dependencies

Unlike Nginx and MySQL, PHP requires quite a few other software packages depending on how you build it. We’ll install some common ones before proceeding with with PHP build and install.

brew install libjpeg mcrypt

cd ~/SourceCache
curl -O http://download.icu-project.org/files/icu4c/4.6.1/icu4c-4_6_1-src.tgz
tar -xzf icu4c-4_6_1-src.tgz
cd icu
sh source/configure --prefix=/usr/local
gnumake
sudo make install

cd /usr/local
curl -O ftp://ftp.cac.washington.edu/mail/imap.tar.Z
tar -xzf imap.tar.Z
cd imap-2007e
make osx
mkdir include
ln -s c-client include
mkdir lib
cd lib
ln -s ../c-client/c-client.a libc-client.a
rm /usr/local/imap.tar.Z

Download and Build PHP with PHP-FPM

cd ~/SourceCache
curl -O http://us2.php.net/distributions/php-5.3.6.tar.gz
tar -xzf php-5.3.6.tar.gz
cd php-5.3.6

This next configure line is escaped with backslashes and should be run as one giant, single command:

./configure --prefix=/usr/local/php \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--sysconfdir=/private/etc \
--enable-cli \
--with-config-file-path=/usr/local/php/etc \
--with-libxml-dir=/usr \
--enable-xml \
--with-openssl=/usr \
--with-kerberos=/usr \
--with-zlib=/usr \
--enable-bcmath \
--with-bz2=/usr \
--enable-calendar \
--with-curl=/usr \
--enable-exif \
--enable-ftp \
--with-gd \
--with-jpeg-dir=/usr/local/Cellar/jpeg/8c/lib \
--with-png-dir=/usr/X11 \
--enable-gd-native-ttf \
--with-imap=/usr/local/imap-2007e \
--with-imap-ssl \
--with-ldap=/usr \
--with-ldap-sasl=/usr \
--enable-magic-quotes \
--enable-mbstring \
--enable-mbregex \
--enable-json \
--with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-mysql-sock=/tmp/mysql.sock \
--with-iodbc=/usr \
--enable-shmop \
--with-snmp=/usr \
--enable-soap \
--enable-sockets \
--with-sqlite \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-wddx \
--enable-fpm \
--with-mhash \
--with-mcrypt \
--with-xmlrpc \
--enable-xmlwriter \
--enable-xmlreader \
--with-iconv-dir=/usr \
--with-xsl=/usr \
--enable-zend-multibyte \
--enable-zip \
--with-pcre-regex=/usr \
--with-pdo-sqlite \
--enable-pdo \
--with-pdo-mysql \
--enable-dba \
--with-freetype-dir=/usr/X11 \
--enable-dom \
--enable-gd-native-ttf \
--enable-posix \
--enable-fileinfo

After PHP is done configuring, it’s time to build it. This will take some time, so you might consider going and making a sandwich.

make

Once compiled, PHP can be installed, and default/example config files can be copied to their actual destinations:

sudo make install
sudo cp /private/etc/php-fpm.conf.default /private/etc/php-fpm.conf
sudo mkdir /usr/local/php/etc
sudo cp /private/etc/php.ini.default /usr/local/php/etc/php.ini

Like Nginx and MySQL, PHP-FPM won’t start up on its own, so we’ll again make use of a launchd plist:

sudo mate /Library/LaunchDaemons/net.php.php-fpm.plist

Here is the content for the PHP-FPM launchd plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>net.php.php-fpm</string>
    <key>LaunchOnlyOnce</key>
    <true/>
    <key>NetworkState</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/php/sbin/php-fpm</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>PHP FastCGI Process Manager</string>
    <key>StandardErrorPath</key>
    <string>/var/log/system.log</string>
</dict>
</plist>

Edit PHP-FPM Config File

We’ve configured Nginx to communicate with PHP on port 9001, so now we need to configure PHP-FPM to listen for Nginx’s call. At the same time, there are a few other options that can be configured such as the number of PHP-FPM processes to run simultaneously.

sudo mate /private/etc/php-fpm.conf

Here is the content for a basic PHP-FPM config file that, among other things, tells PHP-FPM to listen on port 9001. Again, my username is in the config file, so you’ll want to replace that with your own.

[global]
pid = /usr/local/php/var/run/php-fpm.pid
daemonize = yes

[www]
listen = 127.0.0.1:9001
user = collin
group = staff
pm = dynamic
pm.max_children = 10
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

With the config file saved, PHP-FPM is ready to run several worker processes at startup.

Download and Build Xdebug

The real key to the PHP debugging puzzle is the Xdebug extension, which is delightfully easy to build:

cd ~/SourceCache
curl -O http://www.xdebug.org/files/xdebug-2.1.1.tgz
tar -xzf xdebug-2.1.1.tgz
cd xdebug-2.1.1
/usr/local/php/bin/phpize
/usr/local/php/bin/php-config
./configure --enable-xdebug
make
sudo make install

After installing Xdebug, we need to inform PHP that the extension is available and set a few basic options. We can do this by editing the

php.ini file we copied earlier, which contains a myriad of settings for PHP’s operation.

sudo mate /usr/local/php/etc/php.ini

Add the following to the end of the file:

zend_extension=/usr/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so
xdebug.remote_enable=1
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.remote_autostart=1

Start Everything Up

One by one, start up each of the services we’ve installed:

sudo launchctl load -F /Library/LaunchDaemons/com.mysql.mysqld.plist
sudo launchctl load -F /Library/LaunchDaemons/net.php.php-fpm.plist
sudo launchctl load -F /Library/LaunchDaemons/org.nginx.nginx.plist

Write a PHP Script

Just to make sure everything works, create a simple PHP script:

mate ~/Sites/example/public/index.php

<?php

$animals = array('dog', 'cat', 'rabbit');
foreach ($animals as $animal)
{
    print "&lt;p&gt;Hello, $animal&lt;/p&gt;";
}

Visit http://example.local in a browser to see the result. It’s not Facebook or Twitter yet, but it’s enough to step into with a debugger.

Install an Xdebug Browser Extension

By default, Xdebug does not automatically debug PHP requests. It needs to be triggered by a GET or POST parameter of

XDEBUG_SESSION_START, or a cookie of the same name, but there is an even easier way. Install an Xdebug extension for Safari, Firefox, or Chrome to automatically set the Xdebug cookie when you need to debug code.

Launch MacGDBp

Now that we have all the tools installed, a PHP debug extension ready, and a browser extension to trigger it all, it’s time to debug that awesome script. Launch MacGDBp, and note that it has a main debug window, a Breakpoints window, and a variable inspector. Take a peek at the Preferences for MacGDBp, and you’ll note that you can choose to break on the first line of PHP (or wait until a breakpoint is hit). I like to uncheck that checkbox because some applications have a fair bit of setup code that needs to be skipped each time. You’ll also find that the default Xdebug port is set to 9000. Earlier, we configured PHP-FPM to listen on port 9001, and this is why we made that change — both tools default to running on port 9000. And just like in Ghostbusters, it’s best not to cross the streams. It would be bad.

In MacGDBp’s Breakpoints window, hit the little “+” button in the lower-left to add a new breakpoint, and navigate to the index.php we created above. Once added, you’ll see the source code for that script in the upper half of the window. Click on a line number to add a breakpoint. With the breakpoint set, flip back to your browser and toggle Xdebug using the installed extension, and reload the page. You’ll see your browser appear to hang while loading, as if the page is taking a while to load. Under the hood, Xdebug has actually paused PHP’s script execution and started a debug session, ready for you to see what’s going on. Behind the browser window, MacDBGp should have hit the breakpoint, ready to inspect variables or step through code: This works for everything from the simplest scripts like we did here, up through complex web apps with deep frameworks. Just set a breakpoint, start the code, and step through to see where the execution deviates from your expectations.

Published on June 13, 2011

As a longtime Mac user, I’ve had an account on file with Apple dating back to when iTools was available. Only recently has the Apple ID become much more important as a personal identifier. Back then, Apple IDs were mostly a means for me to identify myself to Apple. Now, people find me using my Apple ID for FaceTime, iMessage, Game Center, and more.

Not so long ago, I decided that I wasn’t happy with this Apple ID and created a new one to do everything with. It was, however, long enough ago that Apple IDs weren’t yet required to be in the form of an email address. So, this new one was just a new name.

More recently, I decided that I should switch my new Apple ID to be in the form of an email address like they now encourage, and verify the matching email address with it. Only, the Apple ID management system would not let me do this, reporting that:

Email address is already verified for another Apple ID

I didn’t recall verifying this email address with any other Apple ID. Even using the “Forgot my Apple ID” tool, which searches for Apple IDs given an email address, produced no Apple IDs that had a record of that email address. Even my old Apple ID didn’t list this email address as one of its verified emails.

As it turns out — and this is after trying many different things including contacting Apple ID Support — MobileMe requires a backup email address in the event you forget your MobileMe password. The email address I wanted to verify with my new Apple ID was set as my MobileMe backup email address for my old Apple ID. This counts as a verify, even though it’s not listed as a verified email address on the Apple ID site for my MobileMe account.

Simply setting up a new email account with my provider dedicated to MobileMe — one I’ll probably never check unless I need to — and using that as my MobileMe backup email address freed up the desired email address I wanted to associate with my new Apple ID.

Hopefully this will help someone who may be running into the same issue. Figuring all this out was wildly confusing at times, and even more difficult to explain to Apple ID Support, which is probably why we never got the issue resolved until now!