Integrating Twilio with @Home with Windows Azure

I started this post about two months ago (right after meeting Jon Gottfried , one of the Twilio evangelists, at Boston Startup Weekend ), but it took yesterday’s announcement to light a fire under me and finish it up!

In case you’re not familiar with @Home with Windows Azure, it’s a project my colleagues Brian Hitney, Peter Laudati and I put together that leverages Windows Azure to contribute to Stanford’s Folding@home medical research project.  We lead you through deploying a simple Windows Azure application to a free 90-day trial or MSDN account, and in turn your code contributes compute cycles to the Stanford project. 

You can monitor your contribution by checking the website you deploy as part of the application we give you, but where’s the fun in that?  Wouldn’t it be cool to get an update each time a Folding@home job completed, and/or be able to request an update on status wherever you happen to be, right from your cell phone? Of course it would! Enter Twilio and its SMS capabilities.

TwilioIn this post, I’ll cover the steps I took to get up and running with a Twilio trial account and the changes I made to the original @home with Windows Azure code to enable features that

  • send an SMS to my cell phone whenever a Folding@home job completes, and
  • allow me to send a text message and get an update on the progress of current folding jobs.

Setting up your Twilio account

This is about as effortless as possible.  Simply click the Get Started button on Twilio’s signup page, enter your name, e-mail and password, and you’re in.  You’ll have a free account at that point, and as mentioned in the announcement yesterday, you’ll get a credit for 1000 texts or inbound minutes when you upgrade from that free account.  You don’t need to do the upgrade now though to get a sense of how it all works.

Once your account is set up, you’ll see your dashboard (below), which includes getting started links, analytics, and most importantly your account credentials and sandbox app.  The sandbox app gives you a telephone number that you can use to both send and receive text and voice messages for development and testing.

Twilio Dashboard

Since you’re using a trial account with a sandbox application there are a few restrictions on usage; these go away when you buy a number and upgrade to a paid account.  Specifically,

  1. You must verify numbers that you own in order to send text messages to them.  Do this via the Verified Number tab under the Numbers menu.  After you enter your number, you’ll see a verification code on the screen and receive a phone call to the number you entered.  Answer that call, enter the verification code, and your number will be now able to send and receive messages. White-list "to" number

  2. Whenever you send a text message from your phone to your Twilio sandbox application, you'll have to preface that message with the Sandbox PIN you see in your dashboard.

    Finding your Sandbox PIN

 

Getting Twilio client libraries

Twilio exposes its SMS and telephony capabilities via REST endpoints and Twilio Markup XML (TwiML), so it follows that you can build a client application using pretty much any programming language or framework that can speak HTTP and XML, like, say C#. 

Dealing with HTTP programmatically is tedious though. Sure you can use HttpWebRequest and handle the request headers, body, status code, etc., but why do that when there’s a Twilio REST API helper NuGet package?

You can locate and install the Twilio package via the Manage NuGet Packages… context menu option on the AtHomeWebRole project, which leads to the dialog below:

NuGet UI panel

or just use the Package Manager Console

Package manager console

This pulls in the Twilio helper libraries (that abstract the HTTP REST calls) as well as their dependencies like Json.NET and RestSharp.

Write some code!

There are two things I want to be able to do:

  1. Have @home notify me via a text message that a folding unit has completed. That means I’ve accrued more points, so I may want to check my current standing amongst all the other folders.
  2. Allow me to send a text to @home to figure out how far along the current work unit is and get other information about how much my deployment has contributed to Stanford’s project.

Sending an SMS message via Twilio

Quite a while ago, I wrote an extensive blog series on the first version of @home with Windows Azure. The recent incarnation is a bit simpler (a single Web Role), but the general workflow is the same – essentially a thread loops continuously in the Web Role invoking Stanford’s command-line Folding@home console client.  The Azure Web Role continually checks if the console client process is complete.  When the process does complete successfully (meaning a work unit is done), the Web Role simply starts up another process and work unit ad infinitum.

During the polling process, the Azure role consults the percentage of completion that’s recorded in a small text file that the Stanford client updates as it is executing, and writes that value to the Azure Table storage account associated with your deployed application (UpdateLocalStatus, line 324 below) and to SQL Azure that’s part of the main @home site (UpdateServerStatus, line 325 below).  If you’re looking at the source code, this all happens in the Launch method of FoldingClient.cs.

  316:  // when work unit completes successfully
  317:  if (exeProcess.ExitCode == 0)
  318:  {
  319:      // make last update for completed role
  320:      FoldingClientStatus status = ReadStatusFile();
  321:   
  322:      if (!status.HasParseError)
  323:      {
  324:          UpdateLocalStatus(status);
  325:          UpdateServerStatus(status);
  326:      }
  327:  }
  328:  else

It’s the IF condition above that detects when a folding unit has completed, so we need to send the SMS right after updating the local and server status.  Here’s the modified code, with the additions (and one change) highlighted.

  316:  // when work unit completes successfully
  317:  if (exeProcess.ExitCode == 0)
  318:  {
  319:      // make last update for completed role
  320:      FoldingClientStatus status = ReadStatusFile();
  321:   
  322:      if (!status.HasParseError)
  323:      {
  324:          WorkUnit workUnit = UpdateLocalStatus(status);
  325:          UpdateServerStatus(status);
         
                TimeSpan duration = workUnit.CompleteTime.Value - workUnit.StartTime;
                String msg = String.Format("WU completed{4}{0}/{1}{4}duration: {2:#0}h {3:00}m",
                                    status.Name, status.Tag, duration.TotalHours, 
                                    duration.Minutes, Environment.NewLine);
                TwilioRestClient client = new TwilioRestClient(
                    "ACcdd159...9a237", "fde24...d14");
                client.SendSmsMessage("415-000-0000", "508-000-0000", msg);
  326:      }
  327:  }
  328:  else

In Line 324, you’ll note a modification was made to UpdateLocalStatus to return information about the work unit for use later in this method.  That change required modifying the return type of that method from void to WorkUnit, and returning the instance of the work unit class that was previously only used as a local variable in that method.

Most of the code added is to craft the SMS text!  Sending the SMS requires only two lines of code – one to instantiate the Twilio client proxy, passing in your Twilio account SID and authentication token, and the other to send the message from the sandbox account number to the cell phone number that you explicitly verified earlier. 

Here’s how it all maps out; of course, you wouldn’t hardcode values like this, and probably instead use custom service configuration settings you’d define in ServiceDefinition.csdef and ServiceConfiguration.cscfg.

Twilio API parameter sources

Mock up of received text messageNow as each Folding@home client invocation completes, I get a text message to my phone that looks something like you see to the right.  The “Sent from the Twilio Sandbox Number” prefix is another ‘feature’ of the trial account; when you upgrade to a paid account, that goes away.

By the way, you don’t actually have to deploy this to Azure either. In fact, to get the various screen shots for this post, I’ve been using the Windows Azure emulator and the mock folding client we provide with @home with Windows Azure.

Receiving an SMS Message in Twilio

What we just implemented was a pushed message, triggered by the completion of a work unit.  Folding@home units can take a number of hours to complete though, and what if you want to know right now how far along a job is?   Now instead of the application initiating the SMS, you want the end-user to do so from his or her phone and have the @home application respond.

Sending a text is easy enough, just send it to the Sandbox number (prefaced by the Sandbox PIN for the trial accounts), but of course you need something on the other end to interpret the text and act on it.  That’s where the two URLs on the Dashboard come in.  Those URLS are endpoints to REST services that respond to SMS or voice messages originating from a validated sender.  The default services simply display/play a welcome message, so we’ll need to do something a bit more sophisticated, something that takes the user’s SMS message as input and sends a reply SMS containing the relevant @home stats.

There are a number of different ways we could write such a service, with the new ASP.NET Web API perhaps at the top of the list.  Rather that get sidetracked by yet another new and cool technology though, I’m going to keep it simple (albeit a bit kludgy) and just add a simple ASP.NET ASPX page to AtHomeWebRole (which is essentially an ASP.NET Web Forms application).  The page, SMSStatus.aspx, doesn’t have any markup, just a Page_Load method:

    1:  protected void Page_Load(object sender, EventArgs e)
    2:  {
    3:      String command = Request["Body"].Trim();
    4:      String outgoingMsg = String.Empty;
    5:   
    6:      switch (command)
    7:      {
    8:          case "current":
    9:              outgoingMsg = "<current status goes here>";
   10:              break;
   11:          case "total":
   12:              outgoingMsg = “<total contribution to date>";
   13:              break;
   14:          default:
   15:              outgoingMsg = String.Format("invalid request: {0}", command);
   16:              break;
   17:      }
   18:   
   19:      Response.Write(String.Format(@"<?xml version=""1.0"" encoding=""UTF-8""?>
   20:          <Response>    
   21:          <Sms>{0}</Sms>
   22:          </Response>
   23:          ", Server.HtmlEncode(outgoingMsg)));
   24:  }

This code will process two messages sent via SMS from a user.  When the word “current” is texted (prefaced by the Sandbox PIN for a trial account), a response will be sent consisting of the message seen on Line 9.  Likewise, when the word “total” is texted, the user will receive a reply message shown on Line 12. 

Of course, these are all hardcoded strings for illustration; in my actual deployment, I’m calling a method to process each message and pulling information from Windows Azure Storage to provide the current percentage complete of a work unit, total number of folding jobs running, number complete, etc. – processing similar to what occurs to build the Status.aspx page that’s part of the same @home with Windows Azure project.  Obviously, you can do whatever processing you want, just as long as you wrap up your response in TwiML as you see on Line 19ff.

The last step here is to indicate that this ASPX page should be the desired target to be executed whenever a text is sent to the Sandbox number.   That association is made in the Twilio Dashboard, by specifying the location of SMSStatus.aspx as the SMS URL.  Of course, at this point you can’t test this (easily) within the local Windows Azure emulator, because https://localhost won’t be resolvable, I deployed my updated @home at Windows Azure solution to https://twiliotest.cloudapp.net, and so the complete SMS URL is:

https://twiliotest.cloudapp.net/SMSStatus.aspx

Specifying SMS URL endpoint

Now I can start texting my application!

Mockup of Twilio SMS conversation on Windows Phone

Wrap Up

I hope the article provided some useful insight into how easy it is to incorporate Twilio into a Windows Azure application.  I didn’t touch on the voice aspects, but the process would be quite similar, and you could dial in from a landline (if you can find one) and get your @home with Windows Azure stats. 

Twilio also has an offering called Twilio Connect which makes building and pricing SaaS applications that much easier.  Instead of you having to provision a number and metering the billing among your clients, Twilio Connect enables your application to tap into your customers’ existing Twilio accounts via OAuth, so you don’t have to figure out how to split up your one big end-of-the-month bill across all of the clients that used your SaaS application.

Give it a shot, and if you have questions or issues getting it set up, let me know.

@home with Windows Azure is great (and meaningful) project to get started with Windows Azure – and now Twilio as well!