Getting cool CallerIDs with Asterisk and Snom Phones

I recently started fiddling around with Asterisk and Snom VOIP phones, and one of the main features I want my phones to have is cool CallerID handling, which means:

  1. Contacts need to be in sync with my mobile, which syncs with a Zarafa instance.

  2. When the phone rings, I want to see who's calling.

  3. When I type a number (without selecting it from the directory), I want my phone to display the name of the person I'm calling.

  4. I want my phones' directories to be synced without having to worry about it.

So here's what I did.

Syncing contacts

Obviously, none of this is possible without an up-to-date phone directory, and I want the directory to be synced with my mobile phone. Fortunately, I'm not going to edit the directory on my voip phones, so getting a read-only copy of the directory from Zarafa is fine. Unfortunately, the only way I found was building zsync; a Python script that acts like a Zarafa WebApp client, logs into the backend, and queries the directory with a fake AJAX call. It sucks, but it gets the job done, so meh.

CallerID

Anyway, this script also supports telling Asterisk who's calling, so this part is pretty easy:

Set(ENV(ASTERISK_CALLERID_NUM)=${CALLERID(num)});
Set(CALLERID(name)=${SHELL(/usr/local/bin/zsync cachesearch):0:-1});

I wanted to avoid having to escape command line parameters, so I pass the callerid using an environment variable, and the script just spits out whatever Asterisk should send as the Caller ID. So whenever someone calls me, I know who they are.

CalleeID

At work, when I dial an internal number, the phone then displays the name of the person I'm calling — I type 123, and the phone says "123 - John Doe". That way, I get an instant feedback and I know I haven't mistyped the number or anything. I love that feature, so I wanted it.

First, I tried to get Asterisk to set the Remote-Party-ID field in the dialplan. Unfortunately, my phones completely ignored it. So I checked out our work phones' configs, and they use an outgoing action URL. Whenever the phone starts placing a call, it loads that URL. If the remote server returns the correct XML, the phone then displays some information on the screen. So I started hacking a getrpid.php script that tries to find the Caller ID in my phone directory and returns the name. So now, I can type a number and the phone immediately acknowledges I'm calling the right person.

The only catch is that when displaying text, the phone appears to switch to a different mode of operation, and doesn't hang up the call when the receiver is hung up anymore. To fix this, the Snom forums suggest adding a <fetch> tag that triggers the phone to load a different URL which simply returns an <exit /> tag to close the browser:

<?xml version="1.0" encoding="UTF-8"?>
<SnomIPPhoneText>
   <Text>-> Doe, John</Text>
   <fetch mil="5000">http://my-server/getrpid.php?action=exit</fetch>
</SnomIPPhoneText>

And then, when the phone loads the ?action=exit URL five seconds later:

<?xml version="1.0" encoding="UTF-8"?>
<exit />

This way, hanging up works as it should again.

Directory

While I have quite a few numbers memorized, being able to look up others that I don't need regularly would still be a nice thing to have, so the phones needed to be able to display a directory of some kind. Fortunately, Snom phones also support loading a phone directory via an Action URL, and all the keys on the phone can be reconfigured to do arbitrary things. So by extending getrpid.php to also provide a directory, and configuring the directory key on the phone to use that action URL instead of the internal phone directory, I now have a full integration.

Plans

Of course, I still have a couple of ideas.

  • Searching

    Now that I have a directory, being able to easily search it would be awesome. The phones' number keys also have letters printed on them and the phones can send input to action URLs, so I'm now dreaming of a T9-ish way to search the directory. I just need to figure out how to write such an algorithm, and how to switch the phones into an input mode where it sends every single keystroke and displays a result of some kind.

  • Redial

    I'd also like to have a central redial menu. Shouldn't even be too hard, just store the last n numbers dialed somewhere and then do the same thing as for the directory.

  • Missed Calls LED

    It's pretty annoying that when I miss a call, the status LED of all the phones lights up and I need to acknowledge it on every phone manually. I'd like the LED to be turned off on all phones when I delete the message on one of them. But it seems I'll have to disable the LED completely for that though, which is not what I want.