Building a ~Bat Signal~ Family Hotline

Build a Family Hotline with the Nexmo Voice API!

Published November 20, 2018 by Mark Smith

Any company I ever phone always has one of those automated answering systems that ask me questions before I get to speak to a real person, and because I’m a bit weird, I’ve always thought “why can’t I have one of those?”

My daughter started secondary school a few months ago, and the form they sent us to fill in only had one slot for a contact phone number. What happens if we give them my details and I’m unavailable? Lucky for me, I work for Nexmo, and know how to set up a phone number capable of forwarding calls to either one of us – or both! Nexmo to the rescue!

What We’re Going to Build

  1. The school is given a Nexmo number as a contact number.
  2. If they call the number, an automated message gives them the following options:
    1. List the parents’ names, with a digit to press to be forwarded to each parent.
    2. If the caller does nothing, forward to the first parent in the list.
    3. Press ‘*’ if there is an emergency. This will set up a conference call and dial in both parents.

I had another couple of requirements:

  1. Be simple, and practically free to host and run.
  2. No database to manage, for added simplicity.

How We’re Going to Build It

I’ve chosen a couple of technologies I’m most familiar with – Python 3.6 and Flask. I’ve chosen Python 3.6 because that was the release that came with f-strings and they’re great! I’m also using pipenv to manage my Python dependencies.

This combination allows us to build a great home IVR (Interactive Voice Response) system in just over 100 lines of code!

Let’s Go!

First let’s set up our development environment.

Because Nexmo needs to call the server you’re going to write, and your laptop is sitting behind a nice, secure firewall, you’ll probably want to use ngrok for local development – let me recommend my colleague Aaron’s excellent blog post about using ngrok.

You’ll probably want to install pipenv globally, and from then on we’ll use it to manage our project’s virtual environment:

Now let’s install the dependencies we’ll need for this project, and activate our virtual environment. Run these commands in your new project’s directory – I’ve called mine hotline:

Now let’s start writing our Flask server.

Open up a file called hotline.py, and type the following:

Now, in separate terminal windows you’ll want to run the following at the same time:

When you run ngrok, it prints out the generated domain name it will forward through to your server. It will look something like this: https://abcde1234.ngrok.io -> localhost:5000. So now you can test your Flask app at https://abcde1234.ngrok.io/incoming (replace abcde1234 with whatever was printed on your terminal).

You should see something like this:

First NCCO test

Make a Phone Call to Your Server

Now you need to configure a Nexmo Virtual Number to call your server when someone calls your number. So now you need 3 things:

  1. A Nexmo account
  2. A configured Voice application
  3. A configured Nexmo Virtual Number.

Create a Nexmo Account

Sign up for an account on the Nexmo website.

Install the Nexmo CLI

Follow the installation instructions in the Nexmo CLI README.
This is generally a really useful tool for configuring your Nexmo account.

Create a Voice Application

You’ll want to save that ID that’s printed out after Application created:. You’ll need it in the next step.

Buy a Number and Link it to Your Voice App

This step is where the command-line interface really comes into its own – the following is just 3 commands:

Okay!

Now you can test all that by calling the phone number you just bought. You should hear Amy read out the message “Welcome to the Brockman family hotline.” If you hear a message saying the number was not recognised, or things don’t work out, open the ngrok debug page at http://127.0.0.1:4040/ in your browser so you can see what requests came in and whether the server responded correctly.

Responding to INPUT

Let’s change the message and add an input action to our menu NCCO so that the caller can select the person they wish to speak to:

Don’t call it just yet! We’re not quite ready … but, let me explain what this does:

I added this to the talk action:

This means that the caller can press a number on their phone while the talk action is still reading them the message. It will automatically activate the following input action. I also added the following action:

This input action tells Nexmo to call the family_selection function we’ve also just added. Flask’s url_for function provides the URL for the given function name.

A Neat Use of partial

url_for by default generates a relative URL. Relative URLs aren’t supported by Nexmo Voice — so, I’ve added the following to the top of the file:

This use of partial sets the url_for function to something more useful – it’s a copy of Flask’s url_for function, but with the default value of the _external parameter set to True. (I forgot to set this parameter so many times before I fixed it with this!)

Once you’ve added that to your file and ensured your server has reloaded, it’s time to call your number again. It should read you the message, allow you to pick a number on your phone, and then read you out that number with one subtracted from it. If you wait for a few seconds, it should then tell you that you selected zero.

Why am I subtracting 1 from the number they entered? It’s so we can select a person from a list! If the test above went well, let’s put our people in a list and make this menu a bit more dynamic.

Forwarding Calls

The first thing we really need is a better way of configuring our “parents”. It’s nice to have a list of the people we will want to forward calls to. For the moment, let’s define their details in the Python file. Please don’t do this with real phone numbers and commit to a public repository!

In the code above, I’m using the amazing attrs library to define a simple class, Endpoint, for holding a person’s name and phone number. I’m then creating a list of Endpoints for the people we may want to forward calls to.

Now I add a simple utility function for generating talk actions. It will make the code more readable and means that by default we’ll be using the Amy voice. You can get a list of all the voices Nexmo supports here

And now I’ve factored out the code for generating the main menu message:

You see that *endpoint_options in the last line of the code above? Did you know you can do this in Python 3 to expand a list into another list? In this case, the result is that we end up with a list of strings that we can join together with spaces.

You can now replace the talk action in the incoming method with the following call to the talk function:

And finally, you can modify the family_selection function so that it will actually forward the call to a phone number:

The code above looks quite a lot more complicated than it did before, but that’s because we’re now doing some error checking and telling the caller if they pressed a key we didn’t expect. If the user presses 1 or 2, they’ll be read a message saying that they’re being connected, and then they will be connected to the endpoint’s number.

Okay, so what have we done so far?

  • The school can call my number and they’re read a list of people they can connect to.
  • If they press 1 or 2 they’ll be connected to that person. (Incidentally, neither side of the phone call can see each other’s phone number, so this is a great way to anonymise calls!)
  • If the caller waits they’ll be connected to the first endpoint in the configured list.

We could stop here if we want, but I had a third requirement: In case of an emergency, the caller could hit star, and it would call both of us and dial us all into a conference call.

Adding a Conference Call Option

A conference call is created with a conversation action, and it ends (by default) when there are no more people on the call. The only thing we need to connect a person to a conference call is the name that we gave the conference call with the first conversation action.

Initialise a Client Object

We’re going to need a Nexmo Client object to create outbound calls to the parents, so it’s lucky we installed the Nexmo Python library at the start of this tutorial, right? Put the following lines near the top of your file. If you want to, you can paste your application_id and private_key values directly into the file, but I think it’s better to load them from environment variables instead. It’s too easy to commit them to a public repository, and anyone who has them can spend your Nexmo balance!

Tell the User They Can Press ‘*’

Before we do that, add the message "If this is an emergency, please press star." to the string returned by our make_answer_message function. I added it just after the message item in the list.

Create a Conference Call

Now let’s create our conference call. Take a deep breath; it’s a reasonably big block of code.

We’ll need a new HTTP endpoint, called conference_ncco, which will provide NCCO actions for each of the parents being dialled into the conference call.

I’ve abstracted out all the code for dialling out to the parents and generating NCCO actions for the caller into a function called create_conference_call.

I’m pasting the two functions together so you can see how the conference_id parameter, which is generated in create_conference_call is embedded in the URL path to the conference_ncco endpoint so that it knows the name of the conference call to embed in the conversation NCCO action.

Handle a Star Input

Now, we just need to modify family_selection so it knows what to do with a * dtmf code, by putting this near the top of the function:

Test It!

Call your Nexmo number, and follow each of the instructions in the main menu to check that they work! If it’s all working, then it’s time to deploy it!

Deploy It!

If you check out the Git repository for this project
you’ll see that I’ve made some minor changes to it, including loading all configuration from environment
variables, and adding a Procfile. This should mean that it’s relatively straightforward to deploy to Heroku – but I’ll leave that as an exercise for you! Don’t forget to update your Nexmo Application’s configuration to point at the new Heroku URL instead of the ngrok URL you’ve been using for development.

Once it’s deployed, it’s time to talk to your child’s school and ask them to update your contact details!

What Did We Do?

We built a whole IVR system to allow the school to contact us! It can forward calls to individual numbers, or connect everyone in one conference call!

Further Credit

Some more things I considered doing with this server include:

  • Forwarding SMS messages sent to the number to both parents.
  • Sending text messages to inform a parent if they missed a call from the school.
  • Creating a ‘race’ call that would call both parents and the first one to answer takes the call. The second call would be cut and be sent an SMS saying the other parent had handled it.
  • If no parent picks up, allowing the school to record a message, which would then be available for both parents to pick up.
  • Integration with a family Slack, with alerts for incoming phone calls, forwarding of SMS messages to the Slack, and even posting of recorded messages to be played within the Slack!

As you can see, there is lots of potential once you get started. I hope you had fun following this tutorial. I’m @judy2k on Twitter – follow me, or ask me questions about this tutorial!

Leave a Reply

Your email address will not be published.