Quantcast
Channel: Python – Twilio Cloud Communications Blog
Viewing all 78 articles
Browse latest View live

Digging Through A Treasure Trove of FiveThirtyEight Data in Python!

$
0
0

In 2008, Nate Silver came within one percentage point of perfectly predicting the popular vote results of the Presidential Election. In 2014, Silver’s team at FiveThirtyEight recorded exactly how many clouds Bob Ross painted over the course of his show’s 31 seasons.

FiveThirtyEight is not just a crack team of data-driven journalists. They’re also caretakers of a treasure trove of data readily available for our consumption on GitHub. Using Python, we can easily parse through the data to find nuggets of wisdom on everything from Bob Ross, to political polls, to how to break FIFA.

What You’ll Need

You’ll need Python 2 or 3 for this tutorial. I’m using Python 2.7.

You’ll also need Pandas (not the black and white fluffy bears, but the Python friendly kind)

Employing The Help of Pandas

Python, along with Pandas, is going to do a lot of our heavy lifting. The pandas data analysis library gives us a very easy, intuitive way to sort through our csv data, straight from the command line. Once we get set up, we can name what we’re looking for, and get a ton of information with simple commands.

Examining Mission Critical Data — How Many Bushes Did Bob Ross Paint?

Fire up your terminal and create a file called

FiveThirtyEight.py

Next, let’s get a python environment going. Type the command

python

We need to create an environment fit for pandas. Let’s run the following command:

>>>pip install pandas

Great. We’re ready for Pandas. Let’s invite them in along with

numpy
, a package for easily computing large sets of numbers. We’ll also use the requests library to get the data from FiveThirtyEight’s GitHub where their csv chock full of Bob Ross data lives.

Tragically, we know this csv won’t be changing any time soon. Bob Ross has passed on and won’t be adding to our data set. R.I.P Bob Ross.

But, If you’re working with csvs that are constantly being updated, using requests ensures you current data. Instead of downloading the latest version of a csv and hoping it’s up to date, you can request the data from a recently updated GitHub repo.

Making Requests To FiveThirtyEight’s GitHub Repo

StringIO operates like an open file command and passes the content of our csv file to pandas as a data set.

>>> import pandas as pd
>>> import numpy as np
>>> import requests
>>> from StringIO import StringIO

 
If you’re using Python 3, you’ll want to use BytesIO and run the command
 

>>>from io import BytesIO

 
Great. Now we’re set up to request data from FiveThirtyEight’s GitHub repo. We’ll do that using requests and the .get command. By defining the response variable and the content variable, we can easily call upon the response of our call to the FiveThirtyEight url and the content from that response. StringIO parses the content as a data set pandas can read, and ensures pandas doesn’t mistake the strings in the csv for urls. Once we have that content, we’ll define it as a dataframe that pandas can read using the .read_csv function.

>>>url ='https://raw.githubusercontent.com/fivethirtyeight/data/master/bob-ross/elements-by-episode.csv'
>>>response = requests.get(url)
>>>content = StringIO(response.content)
>>>df = pd.read_csv(content)

 
For the Python 3 folks, run content like so:

>>>content = BytesIO(response.content)

 
Rad! We now have all of our Bob Ross data in Terminal. Let’s see how we can view specific subsets of data. Using the

df.head()
command, pandas will give data from the first five rows of our csv file. In this case, that’s the first five episodes. If we wanted to see the first 10 episodes, we’d just pass in an argument like:
>>>df.head(10)

Now, let’s answer the burning question — how many clouds did Bob Ross paint?  By calling upon the column “CLOUDS” and asking for the sum of that row, pandas will deliver us the answer.

>>>df ["CLOUDS"].sum()


Bob Ross painted 179 happy little clouds


If we wanted to calculate the probability he’ll paint a cloud in any given episode, we could run
>>>df["CLOUDS"].mean().

 
Blam. There’s a 44% likelihood that Bob Ross will paint a cloud. But what if we wanted to see how many times Bob Ross has graced his happy little clouds with a tree friend?

By grouping the two rows “CLOUDS” and “TREES” together and calling the sum, we see how many times he painted trees and clouds together.

>>>df.groupby("TREES")["CLOUDS"].sum()

When you run this, you’ll see that under the 0 column, there are 41 instances where Bob Ross painted clouds with no trees, and there are 138 instances where he painted the two together. When you add 41 to 138, you get 179 — the total number of clouds Bob Ross painted.

More Fun With CSVs and Python Ahoy!

Now that you know how to parse and loop through CSV data, you can answer all sorts of questions straight from the command line.

Resources

If you’re looking for more opportunities to flex your Python skills here are a few resources.

 
If you’ve got any hot data, Bob Ross jokes, or other quips — shoot me a note @kylekellyyahner or kyleky@twilio.com

Digging Through A Treasure Trove of FiveThirtyEight Data in Python!


Shannon Turner Builds A Pet Cam Using Django, Raspberry Pi and Twilio

$
0
0

Thanks to the power of code, your pets are never more than a POST request away. Shannon Turner built a Twilio MMS, Raspberry Pi + Django hack so she can see what her winged companion, a lovely parrot, is up to when she’s out.
 
“Any time I miss my pet, a photo of him playing with his toy is only a text message away,” says Shannon. “I’ve had BudgieCam running for just over a month and I’ve already taken over 200 photos and nearly 100 videos.”

Building BudgieCam

 


When Shannon is on the road, she sends a text to her Twilio-powered number. Twilio gets that requests and fires off a POST request to Shannon’s Django site which triggers her Raspberry Pi (complete with Raspberry Pi Camera) to take a photo. The photo is stored on Shannon’s Pi server. Then Django instructs Twilio to send an MMS with the photo of Shannon’s pretty bird back to Shannon. This all takes place in the span of a few seconds.
 
Shannon usually doesn’t do this. She normally ships civic minded hacks. Hacks that help women learn to code, recommend movies that pass the Bechdel test, or out politicians whose ideals are quite behind the times. “This hack is just for fun,” says Shannon.
 
If you want to engineer a little fun and a whole lot more pet pictures into your life, here’s the code Shannon used to build BudgieCam on GitHub. Take a look at the Twilio integration below, and the MMS docs that will give you a good foothold in tackling project like this.
 

from django.shortcuts import render
from django.views.generic.base import TemplateView

import subprocess
import time

from twilio.rest import TwilioRestClient 

from budgie_settings import BUDGIE_PASSPHRASE, BUDGIE_FILE_PATH, BUDGIE_WEB_PATH, RASPI_IP
from twilio_credentials import ACCOUNT_SID, AUTH_TOKEN

class BudgieCamView(TemplateView):

    def get(self, request, **kwargs):

        """ Response Code 418: I'm a teapot
        """

        template = 'response.html'
        context = {
            'response': '418'
        }
        return render(request, template, context)

    def post(self, request, **kwargs):

        """ Twilio is configured to POST to this URL when a text message is received.
            1. Receive text message
            2. Verify text message and continue if verified
            3. Snap photo (use subprocess module)
            4. Photo needs to be accessible via a URL
            5. Use Twilio API to attach photo to SMS
        """

        text_message = request.POST.get('Body')
        requesting_phone_number = request.POST.get('From')
        budgiecam_phone_number = request.POST.get('To')

        context = {}

        if text_message:
            if BUDGIE_PASSPHRASE in text_message.lower():
                if 'video' in text_message.lower():
                    try:
                        budgie_filename = '{0}.h264'.format(''.join(['{0:02d}'.format(x) for x in time.localtime()[:6]]))
                        # raspivid -o video.h264 -t 10000
                        subprocess.call(['raspivid', '--nopreview', '-t', '30000','-o', '{0}{1}'.format(BUDGIE_FILE_PATH, budgie_filename)])

                        # This would convert the h264 video to mp4 but unfortunately it doesn't run quickly enough on the Raspberry Pi
                        # Maybe later versions of the Pi would be able to handle it, but this one can't.
                        # try:
                        #     print "\t Converting {0} to mp4".format(budgie_filename)
                        #     subprocess.call([
                        #         'ffmpeg',
                        #         '-i',
                        #         '{0}{1}'.format(BUDGIE_FILE_PATH, budgie_filename),
                        #         "{0}{1}.mp4".format(BUDGIE_FILE_PATH, budgie_filename[:-5])
                        #     ])

                        # except Exception:
                        #     print "[ERROR] Failed to convert {0} to mp4".format(budgie_filename)
                        # else:
                        #     subprocess.call([
                        #         'rm',
                        #         '{0}{1}'.format(BUDGIE_FILE_PATH, budgie_filename)
                        #     ])
                        #     budgie_filename = "{0}.mp4".format(budgie_filename[:-5])
                    except Exception, e:
                        print "[ERROR] Call to raspivid failed; could not take video ({0}: {1}{2})".format(e, BUDGIE_FILE_PATH, budgie_filename)
                    else:
                        client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
                        client.messages.create(
                            to=requesting_phone_number,
                            from_=budgiecam_phone_number,
                            body="Video ready here: {0}{1}{2}".format(RASPI_IP, BUDGIE_WEB_PATH, budgie_filename)
                        )
                        context['response'] = '200'
                else:
                    try:
                        budgie_filename = '{0}.jpg'.format(''.join(['{0:02d}'.format(x) for x in time.localtime()[:6]]))
                        subprocess.call(['raspistill', '--nopreview', '-t', '5000', '-o', "{0}{1}".format(BUDGIE_FILE_PATH, budgie_filename)])
                    except Exception, e:
                        print "[ERROR] Call to raspistill failed; could not take photo ({0}: {1}{2})".format(e, BUDGIE_FILE_PATH, budgie_filename)
                        context['response'] = '500'
                    else:
                        client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
                        client.messages.create(
                            to=requesting_phone_number,
                            from_=budgiecam_phone_number,
                            body="{0}".format(budgie_filename),
                            media_url="{0}{1}{2}".format(RASPI_IP, BUDGIE_WEB_PATH, budgie_filename),
                        )
                        context['response'] = '200'
            else:
                context['response'] = '401'
        else:
            context['response'] = '400'

        template = 'response.html'
return render(request, template, context)

Learn more about Shannon and all of the rad hacks she builds right here.

Shannon Turner Builds A Pet Cam Using Django, Raspberry Pi and Twilio

How to Receive and Respond to a Text Message with Python, Flask and Twilio

$
0
0

Here’s all the code you need to receive an SMS message and to send a response using Python, Flask, and Twilio:

from flask import Flask, request
from twilio import twiml


app = Flask(__name__)


@app.route('/sms', methods=['POST'])
def sms():
    number = request.form['From']
    message_body = request.form['Body']

    resp = twiml.Response()
    resp.message('Hello {}, you said: {}'.format(number, message_body))
    return str(resp)

if __name__ == '__main__':
    app.run()

If you’d like to know how that works, check out this short video:

Can you walk me through this step by step?

When someone texts your Twilio number, Twilio makes an HTTP request to your app. Details about that SMS are passed via the request parameters. Twilio expects an HTTP response from your web app in the form of TwiML, which is a set of simple XML tags used to tell Twilio what to do next.

First make sure you set your local environment up and have a directory where the code will live.

Open your terminal and install Flask, the popular micro web framework, which we’ll use to receive Twilio’s request:

pip install flask

Install the Twilio Python library to generate the response TwiML:

pip install twilio

Create a file called app.py, and import the Flask and request objects from the Flask library. Also import the Twilio Python library and initialize a new Flask app:

from flask import Flask, request
from twilio import twiml


app = Flask(__name__)

We need a route to handle a post request on the message endpoint. Use the @app.route decorator to tell our app to call the sms function whenever a POST request is sent to the ‘/sms’ URL on our app:

@app.route('/sms', methods=['POST'])
def sms():

Details about the inbound SMS are passed in the form encoded body of the request. Two useful parameters are the phone number the SMS was sent From and the Body of the message:

def sms():
    number = request.form['From']
    message_body = request.form['Body']

Next we’ll use the Twilio library to create a TwiML <Response> that tells Twilio to reply with a <Message>. This message will echo the phone number and body of the original SMS:

    resp = twiml.Response()
    resp.message('Hello {}, you said: {}'.format(number, message_body))
    return str(resp)

And don’t forget to tell the app to run:

if __name__ == '__main__':
    app.run()

In your terminal, start the server which will listen on port 5000:

python app.py

But how does Twilio see our app?

Our app needs a publicly accessible URL. To avoid having to deploy every time we make a change, we’ll use a nifty tool called ngrok to open a tunnel to our local machine.

Ngrok generates a custom forwarding URL that we will use to tell Twilio where to find our application. Download ngrok and run it in your terminal on port 5000

./ngrok http 5000

Now we just need to point a phone number at our app.

Open the phone number configuration screen in your Twilio console. Scroll down to the “a message comes in” field. You should see something like this:

message-comes-in.png

Punch in the URL for our message route that was generated by ngrok. It should look something like http://your-ngrok-url.ngrok.io/sms.

Click save, then text your number to get a response!

Next steps

To recap, when the text hits Twilio, Twilio makes a request to our app, and our app responds with TwiML that tells Twilio to send a reply message.

If you’d like to learn more about how to use Twilio and Python together, check out:

Feel free to drop me a line if you have any question or just want to show off what you built:

How to Receive and Respond to a Text Message with Python, Flask and Twilio

How to Send an SMS With Python Using Twilio

$
0
0

All you need to send an SMS with Python using Twilio are the following ten lines of code:

import os
from twilio.rest import TwilioRestClient


client = TwilioRestClient(os.environ.get('TWILIO_ACCOUNT_SID'), 
                          os.environ.get('TWILIO_AUTH_TOKEN'))

client.messages.create(from_=os.environ.get('TWILIO_PHONE_NUMBER'),
                      to=os.environ.get('CELL_PHONE_NUMBER'),
                      body='You just sent an SMS from Python using Twilio!')

If you’d like to see this in action, check out this short video:

More of a Textual Learner? Here’s a Walkthrough

The first thing we need for the above code to work is a Twilio account. Sign up for your free trial account here.

We also need an SMS-enabled phone number. You can search for and buy one in the Twilio console.

Sending an SMS using Twilio is as simple as making an HTTP POST request to the /Messages resource in the Twilio API. Twilio makes this super simple by providing a helper library. Install the twilio library from the terminal using pip:

pip install twilio

Next, create a file named sms.py and open it in your favorite text editor. At the top of the file import os and TwilioRestClient from twilio.rest. In the code below we use os to read our Twilio credentials from system environment variables and create a TwilioRestClient using them. If you’re unsure how to store your Twilio credentials in environment variables click here for Windows or here for Mac OS X for more information.

import os
from twilio.rest import TwilioRestClient

client = TwilioRestClient(os.environ.get('TWILIO_ACCOUNT_SID'), 
                          os.environ.get('TWILIO_AUTH_TOKEN'))

Use the client to send an SMS message from your Twilio number to your cell phone. Make sure to replace the phone number placeholders with your Twilio and cell phone numbers:

client.messages.create(from_=os.environ.get('TWILIO_PHONE_NUMBER'),
                       to=os.environ.get('CELL_PHONE_NUMBER'),
                       body='You just sent an SMS from Python using Twilio!')

Head back to the terminal and run the script:

python sms.py

In just a few seconds you should receive your text message!
SMS sent from Python code received on an iPhone

Conclusion

If you’d like to learn more about using Twilio and Python together check out:

What are you building? I’d love to hear about it. You can reach me on Twitter @brentschooley or drop me an email at brent@twilio.com.

How to Send an SMS With Python Using Twilio

Introducing Templates for TwiML Bins

$
0
0

This past May we launched Native TwiML Bins in the Twilio Console. TwiML Bins made it easy for developers to prototype their ideas and even ship simple production use cases without the need to stand up a web server. Since then thousands of developers have been using TwiML Bins to explore the capabilities of TwiML and build simple call forwarding, auto response, and voicemail applications.  However, one consistent piece of feedback that we got from developers was their desire to be able to do more. For instance, SMS forwarding isn’t possible with a static TwiML document. You need to be able to customize the

<Body>
  tag to include both the phone number of the person sending the SMS and the body of the SMS itself.  Developers wanted to be able customize their TwiML at runtime based on the HTTP parameters based into the Bin. We’re excited to share that this is exactly what you can do today with TwiML Bins templates.

Before we dive into templates, let’s review how Twilio processes an incoming phone call.

How Twilio Processes An Incoming Phone Call

When a phone call is placed to a customer’s Twilio number, Twilio looks up the Voice Request URL associated with that phone number. Twilio then makes an HTTP request to that URL passing along the several parameters that provide the app with information about the incoming call. The app then constructs a TwiML document and returns this document in the HTTP response which Twilio then executes for the person on the phone.

TwiML Bins made it possible for a developers to write simple TwiML documents that Twilio hosts and then executes in response to incoming phone calls and SMS messages. Now developers can define a template that includes placeholders for any of the HTTP parameters passed-in by Twilio’s webhook request. This is done by enclosing the name of the HTTP parameter with opening and closing double curly braces (i.e.

{{From}}
 ). With this ability it is now simple to build a TwiML Bin that will forward incoming SMS messages:
<Response>
  <Message to="+12065551212">{{From}}: {{Body}}</Message>
</Response>

In addition to the HTTP parameters that Twilio passes, a developer can also pass their own custom HTTP parameters by simply appending them to the query string in the URL. Here’s an example in Python of placing an outbound call using a TwiML Bin:

client.calls.create(
    url="https://handler.twilio.com/twiml/EHxxx?Dest=%2B12065551212",
    to="+14155551212",
    from_="+15017250604")

The TwiML Bin used above would then reference the value of the

Dest
parameter like so:
<Response> 
  <Dial>{{Dest}}</Dial>
</Response>

It has been great to see developers using TwiML Bins to explore the power of TwiML and to make shipping simple things easy so that they can focus more on building experiences and less on managing web infrastructure. We hope that templates make TwiML Bins even more useful and look forward to seeing what you build.

If you have any any questions about TwiML Bins templates don’t hesitate to reach out to me at @crtr0 on Twitter or carter@twilio.com.

Introducing Templates for TwiML Bins

How to Make and Receive Phone Calls with Python, Bottle and Twilio Voice

$
0
0

Python web applications that combine the Bottle web framework with the Twilio Voice API can easily make and receive phone calls. Our calls will read a snippet of text then play an MP3 file. The call instructions can be modified to provide other useful actions such as gathering input from the number pad or putting all callers together in a conference call.

Our Project Tools

Our Bottle application will need either Python 2 or 3 to be installed. Python 3 is recommended for new applications. We will also need the following tools throughout this walkthrough:

You can snag all the code for this tutorial in the python-twilio-example-apps GitHub repository. Copy and modify the code however you want – it is all open sourced under the MIT license.

Install Dependencies

Before we write our Python code we will create a new virtual environment to isolate our application dependencies. Open your terminal and execute the virtualenv command to create a new virtualenv:

virtualenv bottlephone

Execute the activate script within the virtualenv, which activates this Python installation for the shell we are working in. Be aware that you need to explicitly activate the virtualenv in each terminal window where you want to execute the Bottle application.

source bottlephone/bin/activate

The command prompt will change when the virtualenv is activated. You should see (bottlephone) $. The following screenshot is what my environment looks like after I ran the activate script:

bottlephone-virtualenv.png

Next use the pip command to install the Bottle and Twilio Python packages into your virtualenv.

pip install bottle twilio

Our two required dependencies will be locally installed once the installation script finishes. Time to write some Python code!

Python Coding with Bottle

The Bottle web application will have three endpoints:

  • / – returns a simple message to let us know our Bottle app is running
  • /twiml – responds with TwiML (a set of instructions written in XML) that instructs Twilio what to do with phone calls
  • /dial-phone/<outbound_phone_number>, where “outbound_phone_number” is a phone number in the format ” 12025551234″

With that overview out of the way, we can proceed to writing the code for our initial Bottle application. Create a new file named app.py with the following lines of code:

import os
import bottle
from bottle import route, run, post, Response


app = bottle.default_app()


@route('/')
def index():
    """Returns standard text response to show app is working."""
    return Response("Bottle app up and running!")


if __name__ == '__main__':
    run(host='127.0.0.1', port=5000, debug=False, reloader=True)

Save the file. Make sure your virtualenv is still activated so our code can rely on the Bottle code library. Run the app via the Bottle development server with the following command: 

python app.py

Our development server should boot up successfully:

(bottlephone) matt@ubuntu:~/bottlephone$ python app.py
Bottle v0.12.9 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:5000/
Hit Ctrl-C to quit.

Test out the app by going to localhost:5000 in a web browser. We should get a simple success message that the app is running and responding to requests.

bottle-dev-server.png
Next we need to obtain a phone number that our Bottle app can use to call other phone numbers.

Getting Our Twilio Number

Our basic Bottle web app runs but what we really want to do is make some phone calls.
In your web browser go to the Twilio website and sign up for a free account. You can also sign into your existing Twilio account if you already have one.

console-phone-numbers.png

The Twilio trial account allows you to dial and receive phone calls to your own validated phone number. To dial and receive calls from any phone number then you need to upgrade your account. Trial accounts are great for initial development before your application goes live but upgraded accounts are where the real power of Twilio is revealed.

Once you are signed into your Twilio account, go to the manage phone numbers screen. On this screen you can buy one or more phone numbers or click on an existing phone number in your account to configure it.

number-config-screen.png

There is nothing for us to configure right now on the phone number configuration page but we will come back to it shortly. Now that we have a phone number in hand, let’s add the final bit of code to our Bottle app to get this app working.

Filling in Our Bottle App

We need to add two new routes to our Bottle app so it can dial outbound phone calls. Modify your existing app.py file with the two new functions below, twiml_response and outbound_call:

import os
import bottle
from bottle import route, run, post, Response
from twilio import twiml
from twilio.rest import TwilioRestClient


app = bottle.default_app()
# copy the account SID and auth token from the Twilio Console and paste below
twilio_client = TwilioRestClient('paste account SID here' , 'auth token here')


# input your Twilio number in the second string on the next line
TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', '+12023350173')
NGROK_BASE_URL = os.environ.get('NGROK_BASE_URL', '')


@route('/')
def index():
    """Returns standard text response to show app is working."""
    return Response("Bottle app up and running!")


@post('/twiml')
def twiml_response():
    """Provides TwiML instructions in response to a Twilio POST webhook
    event so that Twilio knows how to handle the outbound phone call
    when someone picks up the phone.
    """
    response = twiml.Response()
    response.say("Hello, this call is from a Bottle web application.")
    response.play("https://api.twilio.com/cowbell.mp3", loop=10)
    return Response(str(response))


@route('/dial-phone/')
def outbound_call(outbound_phone_number):
    """Uses the Twilio Python helper library to send a POST request to
    Twilio telling it to dial an outbound phone call from our
    specific Twilio phone number (that phone number must be owned by our
    Twilio account).
    """
    # the url must match the Ngrok Forwarding URL plus the route defined in
    # the previous function that responds with TwiML instructions
    twilio_client.calls.create(to=outbound_phone_number,
                               from_=TWILIO_NUMBER,
                               url=NGROK_BASE_URL + '/twiml')
    return Response('phone call placed to ' + outbound_phone_number + '!')


if __name__ == '__main__':
    run(host='127.0.0.1', port=5000, debug=False, reloader=True)

Make sure to replace the phone number listed above with your Twilio phone number. Also modify the placeholders for the Twilio credentials to properly instantiate the TwilioRestClient.

There is one issue with our local development environment configuration: Twilio won’t be able to reach that /twiml route. We need to deploy our app to a reachable server or use a localhost tunneling tool like Ngrok. Ngrok provides an external URL that connects to a port running on your machine. Download and install the Ngrok application for your operating system.

Run the following command to make our Bottle app on port 5000 available publicly on the Internet.

./ngrok http 5000

Ngrok will start up and provide us with a Forwarding URL, with both HTTP and HTTPS versions.

The Forwarding URL plus the route will instruct Twilio to handle the phone call when someone answers. Insert the Ngrok forwarding URL into the app.py file where NGROK_BASE_URL is specified:

ngrok-forwarding-url.png

One bit to be aware of when using Ngrok is that your Forwarding URL will change whenever you restart the application, so you’ll need to update your code with the latest Forwarding URL.
To get even more out of Ngrok after finishing your Bottle project, make sure to read this 6 awesome reasons to use Ngrok when testing webhooks post.

Making Calls

Make sure your Bottle development server is still running or re-run it with the python app.py command in a shell where your virtualenv is still activated.

Bring up your application in the web browser. Go to “localhost:5000/dial-phone/my-phone-number”, where “my-phone-number” is a number in the ” 12023350173″ E.164 format. For example, here is what happens when I get the call on my iPhone:

success.png

When we pick up the phone call we also see the /twiml route get called via Ngrok.

post-twiml.png

With only a couple of Bottle routes plus Twilio’s Voice API we were able to make phones ring!

Dialing Our Application

Outbound calls are handy, but what about if someone dials our application’s phone number? We have done all the hard work to make inbound calls possible. We just need to copy our Ngrok forwarding URL plus TwiML endpoint into the phone number configuration screen for the phone number we want to dial.

ngrok-number-config.png

Click “Save” and dial your application’s number. You should get the same message and MP3 played as when you dialed the outbound phone call.

Next Steps

We can make and receive phone calls from our Bottle web application using our Twilio phone number. Next you could try to add even more features to your app by going through one of these tutorials:

Questions? Contact me via

How to Make and Receive Phone Calls with Python, Bottle and Twilio Voice

First Steps with Python and Bottle

$
0
0

Do you want to build your first web application with Python? Or have you been working with a full-featured web framework such as Django or Pyramid and want to try out a microframework? Take four minutes to watch this video and check off “get started using the Bottle web framework” from your 2016 to-do list:

The Code

You can snag the code in the video via this GitHub Gist or just copy from here into a file named app.py:

import bottle
from bottle import route, run, Response
 
 
app = bottle.default_app()
 
 
@route("/")
def index():
    """Returns standard text response to show app is working."""
    return Response("My Bottle app is up and running!")
 
 
if __name__ == '__main__':
    run(host="127.0.0.1", port=5000, debug=False, reloader=True)

Make sure to pip install bottle from PyPI and then run the following command:

python app.py

That’s it, 15 lines of code to respond to incoming HTTP requests with a simple response!

More Resources

With your quick introduction to Bottle out of the way, here’s where to go next to keep learning:

Questions? Contact me via

First Steps with Python and Bottle

How to Hang Up Currently Active Twilio Phone Calls with Python

$
0
0

In case you found this in an emergency, here is all of the code you need to hang up all currently in progress, ringing or queued phone calls:

from twilio.rest import TwilioRestClient
from twilio.rest.resources import Call


client = TwilioRestClient()

for call in client.calls.iter(status=Call.QUEUED):
    call.hangup()

for call in client.calls.iter(status=Call.RINGING):
    call.hangup()

for call in client.calls.iter(status=Call.IN_PROGRESS):
    call.hangup()

In order for this to work, make sure you grab your Account SID and Auth Token from your Twilio Console and set them as environment variables:

export TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
export TWILIO_AUTH_TOKEN="YOUR_AUTH_TOKEN"

Why would I need to do this?

Sometimes when testing your code to make phone calls with Twilio, you can end up accidentally making too many calls. This situation has happened to me many times. As my friend Brodan said in a similar blog post: “Making too many calls too quickly is dangerous because it can use up a lot of Twilio credit very quickly or get your account suspended due to unintentional spam.”

Let’s take this code and turn it into a shell command that we can run in the terminal whenever too many phone calls are made unintentionally.

Setting up our environment

To separate dependencies from other Python apps running on your machine, we will need a virtual environment. I love using Virtualenvwrapper because it makes working with virtual environments simple.

Install it with the following terminal command:

pip install virtualenvwrapper

Now create a directory to keep all of your virtual environments, and set this as an environment variable for Virtualenvwrapper to use. I created a directory called Envs in my home directory:

export WORKON_HOME=~/Envs
mkdir -p $WORKON_HOME
source /usr/local/bin/virtualenvwrapper.sh

Add that last line to your .bashrc or other shell startup file, to make sure that virtualenvwrapper works every time you need to use it. Otherwise you will have to run it manually for each new terminal session.

With virtualenvwrapper installed, create a virtual environment:

mkvirtualenv kill_calls

And install Twilio inside of that virtual environment:

pip install twilio

Now add this code to a file called kill_calls.py:

from twilio.rest import TwilioRestClient
from twilio.rest.resources import Call


client = TwilioRestClient()

for call in client.calls.iter(status=Call.QUEUED):
    call.hangup()

for call in client.calls.iter(status=Call.RINGING):
    call.hangup()

for call in client.calls.iter(status=Call.IN_PROGRESS):
    call.hangup()

You can run this script when you need to hang up Twilio phone calls. Think of it as your panic button to avoid rickrolling 200 people while they are trying to sleep.

How do I know this works?

We can test this script out by writing some code that will make a bunch of phone calls. For this test you will need a Twilio phone number. You can buy a phone number here.

Create and open a file called make_calls.py and add the following code:

# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import TwilioRestClient

# Instantiate a rest client object
# This grabs Twilio credentials from environment variables
client = TwilioRestClient()

# Make 10 phone calls
for i in range(10):
    call = client.calls.create(url="http://demo.twilio.com/docs/voice.xml",
        to="YOUR_PHONE_NUMBER",
        from_="YOUR_TWILIO_NUMBER")
    print(call.sid)

Now run that code first (don’t forget to replace your phone number and Twilio number) and then the code you wrote to kill all of the calls:

python make_calls.py
python kill_calls.py

You’ll never have to write this code again

Manually running this Python script every time you mistakenly make 500 phone calls to your users would be tedious and waste precious time. We can turn this program into a shell script that you can use at the drop of a hat.

Open your .bashrc, or other shell startup file, again, and add the following line:

alias kill_calls="workon kill_calls; python ~/Path/to/kill_calls.py; deactivate"

Don’t forget to use the correct path to kill_calls.py. This will give you a shell command that you can run any time instead of scrambling to find the right code.

You’ll also want to make sure you have your Twilio authentication credentials set as environment variables permanently by adding the export lines we used before to your .bashrc:

export TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
export TWILIO_AUTH_TOKEN="YOUR_AUTH_TOKEN"

Hopefully, you won’t have any horror stories about accidentally calling your users in the middle of the night while testing code. Feel free to reach out for any questions or to share your own stories:

How to Hang Up Currently Active Twilio Phone Calls with Python


Build Stranger Things Lights with Firebase, Zapier and Twilio

$
0
0

It’s a 2,280 trek from my desk to Indiana, the home state of Stranger Things.

I will forgo any attempt to calculate my commute to the Upside Down. Not only do I have no interest in grappling with the Demogorgon, but any respected physicist will tell you it’s hard to pin down the Upside Down’s coordinates. It could be beneath me at this very moment, or in another universe.

You can safely bring one hallmark of Stranger Things to your home without a cross country roadtrip, or summoning a beast from another dimension. Rajarshi Nigam engineered Stranger Thing’s rope lights – an interdimensional telephone – into existence. Check out his full rundown here.
1w2euhv1zbsizxxlbko72fg

This time they’re not powered by otherworldly forces, but rather by Firebase, Twilio, Zapier, and some hardware tinkering. When you send a text to your Twilio number, your Stranger Things lights will spell out the message you sent. If Will Byers had a cell phone and this hack, his life would be a lot easier.

Read Rajarshi’s full tutorial on Hackster.io.

Build Stranger Things Lights with Firebase, Zapier and Twilio

Getting started with Sanic: the asynchronous, uvloop based web framework for Python 3.5+

$
0
0

uvloop has been making waves in the Python world lately as a blazingly fast drop-in for asyncio’s default event loop. Sanic is a Flask-like, uvloop-based web framework that’s written to go fast. It is also named after the popular Sanic Internet meme, a poorly drawn version of Sonic the Hedgehog.

Sanic is made for Python 3.5 . The framework allows you to take advantage of async/await syntax for defining asynchronous functions. With this, you can write async applications in Python similar to how you would write them in Node.js.

Responding to basic HTTP requests

The “Hello World” example with Sanic looks like this:

from sanic import Sanic
from sanic.response import text


app = Sanic()


@app.route("/")
async def hello(request):
    return text("Hello World!")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Create a new directory for this project, and paste that code into a new file called app.py. In order to run this code, you’ll also want to create a virtual environment (make sure to use Python 3 when creating the environment) and run the following command to install Sanic:

pip install sanic

And run the application:

python app.py

And visit http://localhost:8000 to see “Hello World!” on the page.

“Hello World” is nice, but let’s see what else we can do. In this next example, we’ll switch things up a bit to figure out how to work with query arguments in the request data. Change the code in app.py to the following:

from sanic import Sanic
from sanic.response import text


app = Sanic()


@app.route("/")
async def hello(request):
    # request.args is a dict where each value is an array.
    return text("Hello {}".format(request.args["name"][0]))

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Run the code again and this time visit http://localhost:8000/?name=Sam. Feel free to replace “Sam” with your own name. When you visit the web page, it should be greeting you by name.

Responding to text messages

Next we can use Sanic to do something useful. We’ll write code that uses Twilio to respond to a text message. You’ll need a Twilio account for this, but don’t worry you can sign up for free.

When someone texts your Twilio number, Twilio makes an HTTP request to your app. Details about that SMS are passed via the request parameters. Twilio expects an HTTP response from your web app in the form of TwiML, which is a set of simple XML tags used to tell Twilio what to do next.

Replace the code in app.py again with the following code to quickly respond to a text message:

from sanic import Sanic
from sanic.response import text


app = Sanic()


@app.route("/sms")
async def hello(request):
    # request.form is a dict where each value is an array.
    message_body = request.form["Body"][0]

    # Since we are just responding with a message, we can return a String
    return text("You said: {}".format(message_body))

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

All you need to do is grab a Twilio number or use a phone number that comes with your trial account and configure it to send POST requests to your app whenever you receive a text message.

Our app needs a publicly accessible URL. To avoid having to deploy every time we make a change, we’ll use a nifty tool called ngrok to open a tunnel to our local machine.

Ngrok generates a custom forwarding URL that we will use to tell Twilio where to find our application. Download ngrok and run it in your terminal on port 8000

./ngrok http 8000

Next we need to point a phone number at our app. Open the phone number configuration screen in your Twilio console. Scroll down to the “a message comes in” field. Before entering your URL you should see:

message-comes-in.png

Punch in the URL for our message route that was generated by ngrok. It should look like http://your-ngrok-url.ngrok.io/sms.

Click save, make sure your application is running and text your number to get a response.

Rollin’ around at the speed of sound

That should be all you need to get started building apps with Sanic. You are officially part of the revolution of meme-driven development.

Of course, Sanic is a brand new framework so expect improvements and changes in the near future. You can even contribute to its open source repository and help build it yourself.

Feel free to drop me a line if you have any question or just want to show off what you built:

Getting started with Sanic: the asynchronous, uvloop based web framework for Python 3.5+

Google Spreadsheets and Python

$
0
0

This post is inspired by Patrick McKenzie’s reminder that sometimes you don’t need a database:

In this tutorial, we’ll use Anton Burnashev’s excellent gspread Python package to read, write, and delete data from a Google Spreadsheet with just a few lines of code. 

Google Drive API and Service Accounts

At the risk of being Captain Obvious, you’re going to need a spreadsheet if you want to follow along with this post. If you don’t have one on hand that’s full of juicy data, might I suggest you make a copy of this spreadsheet with contact information for all United States legislators(Side note: Ian Webster uses this data in conjunction with Twilio to make it easy for citizens to call congress).

 

To programmatically access your spreadsheet, you’ll need to create a service account and OAuth2 credentials from the Google API Console. If you’ve been traumatized by OAuth2 development before, don’t worry; service accounts are way easier to use.

Follow along with the steps and GIF below. You’ll be in and out of the console in 60 seconds (much like Nic Cage in your favorite Nic Cage movie).

  1. Go to the Google APIs Console.
  2. Create a new project.
  3. Click Enable API. Search for and enable the Google Drive API.
  4. Create credentials for a Web Server to access Application Data.
  5. Name the service account and grant it a Project Role of Editor.
  6. Download the JSON file.
  7. Copy the JSON file to your code directory and rename it to
    client_secret.json

 

There is one last required step to authorize your app, and it’s easy to miss!

Find the 

client_email
 inside
client_secret.json
. Back in your spreadsheet, click the Share button in the top right, and paste the client email into the People field to give it edit rights. Hit Send.

If you skip this step, you’ll get a

gspread.exceptions.SpreadsheetNotFound
 error when you try to access the spreadsheet from Python.

We’re done with the boring part! Now onto the code.

Read Data from a Spreadsheet with Python

With credentials in place (you did copy them to your code directory, right?) accessing a Google Spreadsheet in Python requires just two packages:

  1. oauth2client – to authorize with the Google Drive API using OAuth 2.0
  2. gspread – to interact with Google Spreadsheets

Install these packages with:

pip install gspread oauth2client

Then paste this code into a new file called

spreadsheet.py
:

import gspread
from oauth2client.service_account import ServiceAccountCredentials


# use creds to create a client to interact with the Google Drive API
scope = ['https://spreadsheets.google.com/feeds']
creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
client = gspread.authorize(creds)

# Find a workbook by name and open the first sheet
# Make sure you use the right name here.
sheet = client.open("Copy of Legislators 2017").sheet1

# Extract and print all of the values
list_of_hashes = sheet.get_all_records()
print(list_of_hashes)

Run

python spreadsheet.py
 and marvel at the glorious, well-formatted data.

 

Insert, Update, and Delete from a Spreadsheet with Python

We’ve just scratched the surface of gspreads’ well documented and comprehensive functionality. 

For instance, we extracted the data into a list of hashes, but you can get a list of lists if you’d prefer:

sheet.get_all_values()

Or you could just pull the data from a single row, column, or cell:

sheet.row_values(1)

sheet.col_values(1)

sheet.cell(1, 1).value

You can write to the spreadsheet by changing a specific cell:

sheet.update_cell(1, 1, "I just wrote to a spreadsheet using Python!")

Or you can insert a row in the spreadsheet:

row = ["I'm","inserting","a","row","into","a,","Spreadsheet","with","Python"]
index = 1
sheet.insert_row(row, index)

You can also delete a row from the spreadsheet:

sheet.delete_row(1)

And find out the total number of rows:

sheet.row_count

Check the gspread API reference for the full details on these functions along with a few dozen others. 

Using Google Spreadsheets with Python opens possibilities like building a Flask app with a spreadsheet as the persistence layer, or importing data from a Google spreadsheet into Jupyter Notebooks and doing analysis in Pandas. But, you’ve probably got even better ideas than that. 

If you build something cool, please let me know. You can find me at gb@twilio.com or @greggyb. And if this post was helpful, please share it with someone else who might dig it. 

Many thanks to Devin and Sam for the reviews, to Google for Sheets, and most of all, to Anton for gspread. 

Google Spreadsheets and Python

Stripe SMS Notifications via Twilio, Heroku, and Python

$
0
0

I recently started a small business using the online platform Storenvy. Storenvy integrates with Stripe, a popular online payments platform. As a small business owner, receiving notifications as soon as orders come in is critical.

Emails are easy to miss, forget about, or overlook, but one thing I never fail to read is a text message. What if it were possible to receive a text message every time my store makes a sale?

Neither Storenvy nor Stripe have SMS notifications built into their platforms, so let’s build a custom SMS notification system using Twilio, Heroku, and Python.

Note: If you’re only interested in the code, it can be found on Github here, along with a “Deploy to Heroku” button.

What You’ll Need

  • git – Git will handle source control and make Heroku deployments easier.
  • Python 3.6 – Heroku’s supported Python runtimes are python-2.7.13 and python-3.6.0. I’ll be using Python 3, although the Python 2 code should be the same.
  • ngrok – ngrok will let us create secure tunnels to our local machine. (See download instructions)
  • A Heroku account. We’ll only be needing the Free tier.
  • A Twilio account. It’s free to sign up and the Free Trial will be sufficient.
  • A Stripe account. Also free, other than transaction fees.
  • (Recommended) virtualenv and virtualenvwrapper – These tools will allow us to create virtual Python environments to avoid cluttering our default environment. You can install these tools by running the following in your terminal (you may need to use sudo):

pip install virtualenv virtualenvwrapper

Getting Started

Here is an outline of what we’ll accomplish:

  • Build a simple app to handle incoming POST requests using Flask and send outgoing text messages with Twilio.
  • Use ngrok to securely tunnel to the Flask app.
  • Configure a webhook on your Stripe account to point to your app.
  • Deploy the app to Heroku and reconfigure the webhook to point the app in the cloud.

If you are are using virtualenvwrapper you should first set up a new Python environment using the following commands:

mkvirtualenv stripe-sms-notifications
workon stripe-sms-notifications

Your terminal prompt will prepend (stripe-sms-notifications) to every line to indicate the virtual environment you are currently in. If at any point you want to leave this virtual environment and return to your default Python environment, you can use the command $ deactivate and use the $ workon stripe-sms-notifications command to re-enter it.

With the environment ready, run the following command to install the Python packages we need:

$ pip install flask twilio

The above command will install Flask, the micro-framework we are using to handle incoming requests, as well as the Twilio Python helper library and all of its dependencies.

Now in the editor of your choice create a new file named app.py. Add the following code:

import os
from flask import Flask, request

app = Flask(__name__)


@app.route("/", methods=['POST'])
def receive_order():
    return '', 200


if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)

At the top of the file we are importing the os module, and two flask modules, Flask and request. The os module is needed to access environment variables, which you can see being used towards the bottom of the file and which we will also need when we import Twilio.

The

app = Flask(__name__)
and
app.run(host='0.0.0.0', port=port)
lines are creating and starting our Flask app, respectively. The most important lines are the ones in the middle.

  • @app.route("/", methods=['POST'])
    represents a rule we are defining for our app’s routing system. Here we are handling POST requests sent to the / route.
  • def receive_order():
    defines the function that will handle requests sent to the route above. It does not take any arguments because we are not handling any URL parameters.
  • return '', 200
    simply returns a 200 response with an empty body.

Save this file and run python app.py in the same directory that app.py is located in. Your terminal should hang and the following line should be displayed:

Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

This means your Flask app was able to start without errors. We can test out our app by making some requests to it. With your app still running, open another, separate terminal and run the following command:

curl localhost:5000

You’ll notice that you receive a 405 Method Not Allowed response. This is fine because we set up our route to only accept POST requests and we sent it a GET request. Use the following command to send a POST request instead:

curl -d '' localhost:5000

It will look like nothing happened because our app returned an empty response body. If you switch back to your other terminal you’ll notice that a POST request was received and a 200 OK response was returned. Our Flask app is ready to go.

Here Comes Twilio

The next step is to import Twilio into our app so that we can send outgoing SMS messages. If you have never worked with Twilio before it might help to first check out their Python Quickstart as we will borrow most of our code from there.

Open up app.py again and add the following lines:

import os
from flask import Flask, request
from twilio.rest import TwilioRestClient

app = Flask(__name__)

# Find these values at https://twilio.com/user/account
account_sid = os.environ['TWILIO_ACCOUNT_SID']
auth_token = os.environ['TWILIO_AUTH_TOKEN']
client = TwilioRestClient(account_sid, auth_token)


@app.route("/", methods=['POST'])
def receive_order():
    message = client.messages.create(
        to=os.environ['PHONE_NUMBER'],
        from_=os.environ['TWILIO_NUMBER'],
        body="Hello, World!")
    return '', 200


if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)

At the top of the file we are importing the TwilioRestClient and building a client object using our Twilio account credentials and phone numbers. Your account sid and auth token can be found in your Twilio console.

I’ve set my credentials as environment variables using the $ export command. If you decide to hard-code your credentials, do not push your source code to a public github repo as it will expose them to the world.

The message = client.messages.create(...) line uses the client object to send an outgoing SMS with the given parameters.

Save the file again, restart the app, run your curl command ($ curl -d '' localhost:5000), and check your phone. You should have received a text message from your Twilio number that says “Hello, World!” If you did not receive a text or your app displays an error, double check that you copy and pasted your Twilio credentials properly.

Handling Stripe Webhooks

The next step is to configure an endpoint in our Stripe account to send data to our application.

If you want to know more about Stripe’s webhooks and how they work, check out their documentation or this blog post. Basically, webhooks allow you to send data to a specific URL whenever events involving your Stripe account occur.

But first we need to make our app publicly accessible so that it can be reached by Stripe. We are going to use ngrok to accomplish this. In a separate terminal run the following command:

ngrok http 5000

Your terminal will transform into a window that looks similar to this:

Copy the first Forwarding URL to your clipboard (http://7dbabaa4.ngrok.io in this case, but yours will be different). This will be the URL we use to configure our Stripe webhook.

Go to your Stripe dashboard and select Webhooks -> Settings (or click here). You should see a menu that looks like this:

Select “+ Add endpoint…” and configure it like this (using the ngrok URL you copied):

We want to be notified whenever we receive a Stripe payment successfully, so the event we are interested in is charge.succeeded. We’re also setting the “Mode” to “Test” so we don’t have to wait for actual payments to come in to test it.

In app.py modify receive_order() to look like this:

@app.route("/", methods=['POST'])
def receive_order():
    event_json = request.get_json()
    amount = event_json['data']['object']['amount'] / 100
    message_body = "Hey! Your shop just received an order for $" + \
        '{:,.2f}'.format(amount) + "."
    message = client.messages.create(
        to=os.environ['PHONE_NUMBER'],
        from_=os.environ['TWILIO_NUMBER'],
        body=message_body)
    return '', 200

Here we are parsing the incoming request object as JSON and extracting Stripe’s amount value from it. We have to divide amount by 100 to convert from cents to dollars. This value gets concatenated to the string message_body, which is then used as the body of our outgoing SMS. Save this file one more time and restart your app.

Testing Our Finished App Locally

All the Python code for our app is now finished and we can test it with Stripe. In your Stripe webhook settings select the “Send test webhook…” button. Use the endpoint we just created to send a charge.succeeded event. You should see the message “Test webhook sent successfully” and receive a text message like in the image below:

Excellent! Now it’s time to deploy our app.

Deploying to Heroku

We are using Heroku in order to avoid the large hassle of renting, configuring, and securing our own server. If you’d like to use your own server, you can skip to the “Wrapping Up” section below.

If you are unfamiliar with the Heroku platform it might be a good idea to at least read through their Getting Started on Heroku with Python guide or check out other Twilio articles that feature Heroku.

However, you’ll find a list of all the commands you’ll need to run below followed by a brief explanation of what the commands are doing.

Make sure you have the Heroku CLI installed and then run the following commands:

echo -n "web: python app.py" > Procfile
pip freeze > requirements.txt
git init
git add app.py requirements.txt Procfile
git commit -m "Initial commit"
heroku create
heroku apps:rename your_project_name
git push heroku master

Replace your_project_name in the command above with whatever you want to name your app. You’ll have to come up with your own name because “stripe-sms-notifications” is already taken by me. Sorry!

The commands above create a Procfile, write our Python dependencies to requirements.txt, initialize and commit all our files to a new Git repo, and create/deploy our app to Heroku.

Once the deployment finishes, run heroku ps:scale web=1 to assign a worker process for your app. (Read more about this step here.)

Heroku Config Vars

Finally, before we can send text messages we need to set a number of config vars for the app. Config vars are Heroku’s equivalent to environment variables. If you previously hard-coded your Twilio credentials you can skip this step.

Run the following commands to set all the necessary config vars, making sure to use your actual Twilio credentials.

heroku config:set TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXX
heroku config:set TWILIO_AUTH_TOKEN=YYYYYYYYYYYYYYYYYY
heroku config:set TWILIO_NUMBER=+15555555555
heroku config:set PHONE_NUMBER=+15555555555

Heroku will take care of restarting the app once the config vars are set.

Testing Our Heroku App

Now that your app is configured and deployed, head back to your Stripe webhook settings and edit the URL of your webhook to point to your Heroku app instead of your ngrok tunnel.

Send another test request using the “Send test webhook…” button as we did earlier. You should receive the same text message as before.

Wrapping Up

Now that your app is working and deployed to Heroku, we need to go back and tell Stripe to use live data instead of the test endpoints we’ve been working with.

We’ll need to create a new endpoint as Stripe will not allow to you edit an endpoint’s Mode after you set it. In your Stripe webhooks select “Add endpoint…”.

As seen below, set the URL to the URL of your Heroku app (remember that yours will be different than mine), set Mode to Live and select the charge.succeeded event.

Note: If you are using your own server instead of Heroku, the URL field should point to your publicly accessible server.

Congratulations! You will now receive an SMS message every time you receive a payment via Stripe. Check your phone for those orders and start makin’ money!

I hope you enjoyed following along with this post. If you run into any issues with your app or you have questions, please reach out to me on Twitter or on Github.

Stripe SMS Notifications via Twilio, Heroku, and Python

Building Python web apps with Flask

$
0
0

When getting started with web development in Python, Flask is a great choice due to its lightweight nature. There is already a solid “Hello World” style quickstart in the Flask docs, so let’s walk through building an application with more functionality.

We are going to build a Flask app using the Twilio REST API that will receive SMS messages containing a song title and respond with a phone call playing a clip of that song from Spotify.

Setting up your environment

Before moving on, make sure to have your environment set up. Getting everything working correctly, especially with respect to virtual environments, can be relatively confusing for developers new to Python.

Run through this guide to make sure you’re good to go before moving on.

Installing dependencies

Now that your environment is set up, you’re going to need to install the libraries needed for this app. We’re going to use:

Navigate to the directory where you want this code to live and run the following command in your terminal with your virtual environment activated to install these dependencies:

pip install requests==2.8.1 twilio==4.8.0 flask==0.10.1

Requesting data from other APIs

Let’s start by writing a module to interact with the Spotify search API, which is just a URL that returns some JSON.

Create a file called spotify.py and enter the following code:

import requests


def get_track_url(song_title):
    spotify_url = 'https://api.spotify.com/v1/search'
    params = {'q': song_title, 'type': 'track'}

    spotify_response = requests.get(spotify_url, params=params).json()
    track_url = spotify_response['tracks']['items'][0]['preview_url']
    return track_url

What we’re doing here is sending a request using the requests module to the URL corresponding to Spotify’s search API, parsing the JSON response, and grabbing the URL associated with the preview of the first track in our search.

Setting up your Twilio account

Before being able to respond to messages, you’ll need a Twilio phone number. You can buy a phone number here.

Your Flask app will need to be visible from the Internet in order for Twilio to send requests to it. We will use ngrok for this, which you’ll need to install if you don’t have it. In your terminal run the following command:

ngrok http 5000

This provides us with a publicly accessible URL to the Flask app. Configure your phone number as seen in this image:

Screen Shot 2016-07-14 at 10.54.53 AM.png
You are now ready to send a text message to your new Twilio number.

Building the Flask app

Now that you have a Twilio number and are able to grab a preview URL from Spotify, which links to an MP3 of a given song, you want to allow users to text a phone number to provide us with a search query.

Let’s create our Flask app. Open a new file called app.py and add the following code:

import spotify

from flask import Flask, request
from twilio import twiml
from twilio.rest import TwilioRestClient
import urllib

# Account SID and Auth Token from www.twilio.com/console
client = TwilioRestClient('TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN')
app = Flask(__name__)


# A route to respond to SMS messages and kick off a phone call.
@app.route('/sms', methods=['POST'])
def inbound_sms():
    response = twiml.Response()
    response.message('Thanks for texting! Searching for your song now.'
                     'Wait to receive a phone call :)')

    # Grab the song title from the body of the text message.
    song_title = urllib.parse.quote(request.form['Body'])

    # Grab the relevant phone numbers.
    from_number = request.form['From']
    to_number = request.form['To']

    # Create a phone call that uses our other route to play a song from Spotify.
    client.calls.create(to=from_number, from_=to_number,
                        url='http://YOUR_NGROK_URL/call?track={}'
                        .format(song_title))

    return str(response)


# A route to handle the logic for phone calls.
@app.route('/call', methods=['POST'])
def outbound_call():
    song_title = request.args.get('track')
    track_url = spotify.get_track_url(song_title)

    response = twiml.Response()
    response.play(track_url)
    return str(response)

app.run(host='0.0.0.0', debug=True)

Make sure to replace “YOUR_NGROK_URL” with your actual Ngrok URL in the code for placing the phone call. If you are using Python 2, you also might have trouble with the song_title = urllib.parse.quote(request.form['Body']) line. Replace it with song_title = urllib.quote(request.form['Body']) and things should work better.

We only need two routes on this app: /sms to handle incoming text messages and to place a call using the Twilio REST Client, and /call to handle the logic of that phone call.

Run your code with the following terminal command:

python app.py

Now text your Twilio number and get a phone call with the song of your choice!

What just happened?

With this app running on port 5000, sitting behind our public ngrok URL, Twilio can see your application. Upon receiving a text message:

  1. Twilio will send a POST request to /sms with the number the message came from, the number it was sent to, and the body of the message.
  2. The inbound_sms function will be called.
  3. A request to the Spotify API will be made, receiving a JSON response that then gets parsed to acquire a “preview URL” to an MP3 file.
  4. A call is made with the Twilio Rest Client, with the track title being sent through URL parameters.
  5. Twilio makes another POST request, this time to the /call route to play the song that the user texted.

Feel free to reach out if you have any questions or comments or just want to show off the cool stuff you’ve built.

Building Python web apps with Flask

Wedding at Scale: How I Used Twilio, Python and Google to Automate My Wedding

$
0
0

September 3, 2016 was just another day for most of the world but to me it will always be memorable as the day that I married my partner.

There are many different aspects to consider while planning a wedding. Food, decor, table fixtures (oh yes these are separate from decor), flowers, accommodation, transportation, entertainment, and location. Whilst there are many unknowns when planning a wedding, I could be sure of one thing. In weddings there are a lot of lists, nested lists, and more lists as far as the eye could see. As I stared at the growing number of items I began to wonder if there was a better way? It all felt so manual and full of inefficiencies. There had to be some aspects that technology could improve.

You may be surprised but inviting people to weddings is expensive (over three hundred and eighty pounds), as you need to send out both ‘Save the date’ cards and a subsequent invite with specifics about the wedding. It is also slow, as you have to send it all via post. It’s time intensive to chase people to see if they received the invite and if they’d like to come to a party with free food and drink – surely an automatic yes? Finally, invites are not environmentally friendly as they are one time use and easily lost or misplaced.

Back to lists. The guest list is split into a few sections:

  1. A list of who you’d liked to come
  2. A list of people who have replied to your R.S.V.P
  3. A list of people who have replied yes
  4. A list of people who have replied yes and selected a food choice

But lists are good. They have predefined requirements and responses which make them a great candidate for automation.

Message In a Bottle

Irrespective of age, I was sure everyone in the wedding list had a mobile phone and that meant it was Twilio time. If you want to skip to the code, you can view the repo on GitHub.

SMS was perfect for my needs. I could configure outbound mass messaging and handle responses quickly and efficiently. While sketching out an MVP and considering a database, I wanted something easy to share and didn’t want to waste time building views. Stumbling upon the gspread python library enabled me to read and write to a google spreadsheet. Whilst not the fastest option, it was certainly flexible enough and provided an easily accessible and readable output.

For the initial R.S.V.P I created a spreadsheet with these columns:

  • Name
  • Telephone_number
  • Confirmation_status
  • Contact detail status
  • Message_count (Amount of messages sent to guest, this comes in handy later)

After the main data entry was completed, I used gspread to iterate through the list and send an SMS to each guest that had a mobile number associated with it:

Sheets.py

import json
import time
import gspread
from oauth2client.client import SignedJwtAssertionCredentials
from twilio.rest import TwilioRestClient

# Message your attendees from a spreadsheet

# add file name for the json created for the spreadsheet
json_key = json.load(open('.json'))
scope = ['https://spreadsheets.google.com/feeds']

credentials = SignedJwtAssertionCredentials(json_key['client_email'],
                                            json_key['private_key'].encode(),
                                            scope)
gc = gspread.authorize(credentials)
wks = gc.open("wedding_guests")  # add your workbook name here
wks_attendees = wks.get_worksheet(0)  # attendees worksheet

ACCOUNT_SID = 'TWILIO_ACCOUNT_SID'
AUTH_TOKEN = 'TWILIO_AUTH_TOKEN'

client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)

# to iterate between guests, amend this based on your total
for num in range(2, 60):
    print "sleeping for 2 seconds"
    time.sleep(2)  # adding a delay to avoid filtering

    guest_number = wks_attendees.acell('B'+str(num)).value
    guest_name = wks_attendees.acell('A'+str(num)).value
    Message_body = u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764" + "\n\n" + u"\u2709" +" Save the date! "+ u"\u2709" +"\n\nLauren Pang and Thomas Curtis are delighted to invite you to our wedding.\n\nSaturday 3rd September 2016. \n\nColville Hall,\nChelmsford Road,\nWhite Roding,\nCM6 1RQ.\n\nThe Ceremony begins at 2pm.\n\nMore details will follow shortly!\n\nPlease text YES if you are saving the date and can join us or text NO if sadly, you won't be able to be with us.\n\n" u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764" + u"\u2B50" + u"\u2764",
    if not guest_number:  # No mobile number skip this guest
        print guest_name + ' telephone number empty not messaging'
        wks_attendees.update_acell('E'+str(num), '0')  # set number to 0

    else:
        print 'Sending message to ' + guest_name
        client.messages.create(
            to="+" + guest_number,  # add the + back to make the number e.164
            from_="",  # your twilio number here
            body=message_body,
        )
        wks_attendees.update_acell('E'+str(num), int(wks_attendees.acell('E'+str(num)).value) + 1)  # increment the message count row
else:                  # else part of the loop
    print 'finished'

As SMS can look a tad plain, I added in some unicode to spice things up. Here is what the message looked like to the lucky invitees:

 

IMG_4729.PNG

 

Next, I used Flask as my web server and set my Twilio Messaging Request URL to point to a /messages url and created simple if statements to parse replies (yes, no):

hello_guest.py

@app.route("/messages", methods=['GET', 'POST'])
def hello_guest():

    if "yes" in body_strip:
        # We have a keeper! Find the attendee and update their confirmation_status
        wks_attendees.update_acell("F"+str(guest_confirmation_cell.row), 'Accepted')  # update the status to accepted for that guest
        resp.message(u"\u2665" + "Thanks for confirming, we'll be in touch!" + u"\u2665")  # respond to the guest with a confirmation!

    elif "no" in from_body.lower():
        # update the confirmation_status row to declined for that guest
        wks_attendees.update_acell("F"+str(guest_confirmation_cell.row), 'Declined')
        # respond to the user confirming the action
        resp.message("Sorry to hear that, we still love you though!")

    else:  # respond with invalid keyword
        resp.message("You sent a different keyword, we need a yes or a no, you sent: "+  
                     from_body)
    return str(resp)

 

IMG_4740.PNG

IMG_4741.PNG

 

The first message was sent 8:37am on the 19th February and the first confirmation was received three minutes later at 8:40am. By 9:38am I had received twenty three confirmations, that’s a 32% acceptance rate! Two days after the initial mass message, we had 58% of guests confirmed! In spite of the clear success, my soon to be wife wasn’t completely sold on my SMS as a wedding invite service (SAAWIS?), so I decided to add some functionality to my app.

Statistics! I could calculate the live attendance list and return it on demand, giving a would be bride instant feedback on how the guest list was shaping up. The code was pretty simple as I had already set up some rudimentary counters in the spreadsheet and so it was just a case of grabbing the contents of these cells and adding them to an SMS:

hello_guest.py

# attendance variables
guest_confirmed = wks_attendees.acell('C70').value
guest_unconfirmed = wks_attendees.acell('C71').value
guest_no_response = wks_attendees.acell('C72').value
guest_acceptance = wks_attendees.acell('C73').value


elif "numbers" in from_body.lower():
    # return statistics (total guests, food choices list)
    resp.message("R.S.V.P update:\n\nTotal Accepted: " + guest_confirmed  
                 "\n\nTotal declined: "   guest_unconfirmed   "\n\nTotal no response: "+  
                 guest_no_response + "\n\nTotal acceptance rate: " + guest_acceptance)

Here is the resultant SMS message:
IMG_4731.PNG

 

Not exactly pretty, but pretty useful.

The fact that Lauren could now keep track of attendance was a stress reliever. From that point forward it was all systems go and SMS was integrated into as many facets of the wedding as possible. Some were obvious, such as sending a notification SMS when the wedding website (powered by Heroku naturally) went live, sharing of gift lists and others I am still proud of today.

Food, Glorious Food

After setting up the R.S.V.P list, the area that is often most delayed is getting guests food choices confirmed You’d be surprised at how hard it is to get people to choose free food. The first step was to send out another SMS telling those guests that had accepted to visit the website and choose their food options via a Google form. Pretty standard stuff however, the form was set to populate the same workbook as attendees. This meant I now had spreadsheets of accepted guests, and those that had filled out the food selection form. Ordinarily I would then have to wait for guests to slowly choose their meals, but my wedding was powered by Twilio and that meant I could chase people with minimum effort.

The data needed to match both spreadsheets on the guest name and update the guests food choice status if there was a match. This required a little extra work but once the code was sorted I could batch run the script on demand and get the latest status of my attendees choice at the end via SMS:

food.py

import json
import time
import gspread
from oauth2client.client import SignedJwtAssertionCredentials
from twilio.rest import TwilioRestClient

# add file name for the json created for the spread sheet
json_key = json.load(open(''))
scope = ['https://spreadsheets.google.com/feeds']

credentials = SignedJwtAssertionCredentials(json_key['client_email'],
                                            json_key['private_key'].encode(),
                                            scope)
gc = gspread.authorize(credentials)
wks = gc.open("")  # add your spreadsheet name here
wks_attendees = wks.get_worksheet(0)  # attendees worksheet
wks_food = wks.get_worksheet(1)  # food responses worksheet

ACCOUNT_SID = 'TWILIO_ACCOUNT_SID'
AUTH_TOKEN = 'TWILIO_AUTH_TOKEN'

client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)

# to iterate between 10 to 60 manual hack to ensure no guests not left out
for num in range(2, 60):
    food_guest_name = wks_food.acell('B'+str(num)).value  # food choice name column

    if food_guest_name:
        attendees_name = wks_attendees.find(val_food_guest_name).value
        attendees_name_row = wks_attendees.find(val_food_guest_name).row
        menu_status = wks_attendees.acell("G"+str(attendees_name_row)).value

        if food_guest_name == attendees_name:
            print
            if menu_status == 'Y':  # data already matched, move on
                print('Skipping')

            else:  # user has supplied their choices, update main spreadsheet
                print ('Food sheet name ' + food_guest_name + 'Attendees sheet name ' + attendees_name)
                # update menu choices row
                wks_attendees.update_acell("G"+str(attendees_name_row), 'Y')
        else:
            print('nothing found, moving on')
            wks_attendees.update_acell('E'+str(num), int(wks.acell('E'+str(num)).value) + 1)  # increment the message count row

    else:
        # send message to the admin that the process has been completed with update stats
        client.messages.create(from_="",  # twilio number here
                               to="",  # admin number here
                               body="Finished processing current meal listnnGuest meals confirmed" + guest_meals_confirmed + "\n\nGuest meals unconfirmed: " + guest_meals_unconfirmed)

Now that there was a confirmed list of guests and a growing list of food choices, it made sense to make those stats public via the main application. All that was needed was grab the contents of the relevant cells and reply with an SMS:

Hello_guest.py

# respond with the current food totals and the meal choices
elif "food" in body_strip.strip():

    resp.message("Guest meals decided:" + guest_meals_confirmed + 
                 "\nGuest meals undecided: " + guest_meals_unconfirmed +
                 "\n\nMenu breakdown:\n\n" + starter_option_1 +": " +
                 starter_option_1_amount + "\n" + starter_option_2 +": " +
                 starter_option_2_amount + "\n" + starter_option_3 +": " +
                 starter_option_3_amount + "\n" + main_option_1 +": " +
                 main_option_1_amount + "\n" + main_option_2 +": " + main_option_2_amount +
                 "\n" + main_option_3 +": " + main_option_3_amount + "\n" +
                 dessert_option_1 + ": " + dessert_option_1_amount + "\n" + dessert_option_2
                 + ": " + dessert_option_2_amount)

 

IMG_4733.PNG

 

This was very handy in keeping the wedding caterers informed of our progress and provided actionable data on who had not made their selection. Chasing guests was another candidate for automation. Simply iterate through the list of attendees and find the naughty guests that had not chosen a meal option and send them a message!

Chase.py

for num in range(2, 72):  # manual hack to ensure no guests not left out
    print "sleeping for 3 seconds"

    time.sleep(3)  # adding a delay to avoid carrier filtering
    wedding_guest_number = wks_attendees.acell('B'+str(num)).value  # grab attendee tel number
    wedding_guest_name = wks_attendees.acell('A'+str(num)).value  # grab attendee name
    menu_guest = wks_attendees.acell('G'+str(num)).value

    if not wedding_guest_number:
        print wedding_guest_name+' telephone number empty not messaging'  # output to console that we are not messaging this guest due to lack of telephone number
        wks_attendees.update_acell('H'+str(num), '1')  # increment the message count row for the individual user

    else:
        if menu_guest == "N":  # guest has not chosen food! CHASE THEM!
            print 'Sending message to '+wedding_guest_name
            client.messages.create(
                to="+" + wedding_guest_number,
                from_="",  # your Twilio number here
                body="If you have received this message, you have not chosen your food options for Tom & Lauren's Wedding!\n\nYou can pick your choices via the website, no paper or postage required!\n\nhttp://www.yourwebsitehere.com/food"
            )
            wks_attendees.update_acell('H'+str(num), int(wks_attendees.acell('H'+str(num)).value) + 1)  # increment the message count row for the individual user
else:                  # else part of the loop
    print 'finished'

 

IMG_4735.PNG

 

The big day approached faster than we could imagine. The only thing left to do was send a final SMS to remind guests of the basic details and to arm themselves with an umbrella to ward off the typically rainy British summer time:

 

IMG_4742.PNG

In Summary

Weddings are never simple affairs and it can feel like a lot of aspects are outside of your control. Automating certainly made my life easier by providing a direct channel with our guests and a myriad of different ways I could track, nudge and poke them into responding. It helped us become proactive over a notoriously time consuming aspect of the wedding, freeing us to focus on other important areas of the big day.

Building scalable solutions to complex problems is never easy, even in its final form my application was fragile at times. I had planned to build out a more complete solution with data visualizations on progress, voice integration and less reliance on CLI scripts but time got the better of me. Overall I’m happy with how it worked out. No communication system is perfect. You need to implement the channel that best fits your audience, be it SMS, Voice, Chat, Video, or semaphore.

If you want to talk about wedding automation, I’m @seektom on Twitter.

Wedding at Scale: How I Used Twilio, Python and Google to Automate My Wedding

Next Generation Python Helper Library Release

$
0
0

Today, we are excited to announce the general availability of our next-generation Python helper library.

The approach

The Python library offers new functionality and takes advantage of modern Python language features. We’ve rebuilt it from the ground up based on the developer feedback we received from you.

This release is the latest addition to the next-generation SDK family. We recently released new versions of PHP, Java, and .NET/C#. To learn more about our novel approach to make the helper libraries more consistent, enable faster iteration, and improve the libraries by having a shared foundation across languages, check out our blog post that introduced the next generation Twilio Helper Libraries.

The next language that we will release is Node, but first things first, let’s take a deeper look at the new features of the Python library first.

What’s new

  • Python version support: Works with version 2.7 and up, including Python 3.x versions.
  • Simplified import: There’s only 1 object you need to import.
  • Accessing resources: The new library makes Twilio API subdomains (Lookups, Conversations, Monitor, etc.) first-class citizens. You can now also pin your interactions to the Twilio API to specific versions of that API.
  • Listing resources: There are now 2 ways to get a list of resources – list and stream.
    • list returns an Array that contains the Instances of resources.
    • stream returns a generator that efficiently pages the list of resources for you.
  • Paging: Both list and stream automatically handle paging for you!
  • Proper types: Resources now serialize/deserialize appropriate types
  • Configurable HTTP client: You can now plug your own HTTP client into the Twilio client!

How to get started

The are several great resources to help you to get started with the new library:

  • The Getting Started Guide that covers installation and how to send your first message.
  • Our guides and tutorials provide code samples for several use cases.
  • The auto-generated library docs are a helpful reference documentation.
  • The Migration Guide is a great resource, especially if you are familiar with the previous generation. It covers some of the new features and highlights the differences.

 

The new libraries come in two lines based on our Versioning Strategy:

  • The ’mainline’ that contains our GA products and is the most stable release
  • ‘edge’ which includes new features that are in Developer Preview or Beta.

Deprecation

New functionality will only be added to the new library (Python Helper Library 6.x). The old library (5.x) will be officially supported until 7/3/2017. After that day, Twilio will stop providing bug fixes and Support might ask you to upgrade before debugging issues. Learn how to migrate your existing application.

Next-gen Release Candidates

With the latest release of the Python, we are approaching the home stretch of updating all supported languages libraries.

We’d love your get your feedback on our other release candidates. They are available on Github now and we are interested in your issue tickets and pull requests.

  • Node.js is the next language to get released.
  • Followed by Ruby.

 

We can’t wait to see what you build!

Next Generation Python Helper Library Release


Developer Digest: Automating Wedding Stress Away in Python

$
0
0

Old things are new again, just new in a different way. That old NES you used to play Super Mario Bros on…? Well Andrew Reitano’s newly-hacked NES lets strangers turn any level into a water level with one text. This issue of the Developer Digest celebrates the developers making the old new and novel, from fax machines, to wedding invitations, to that trusty old password you still use.

 

The Digest

A Bunch of Awesome People (Like You) Are Coming to SIGNAL

You’ll learn why the founder of ngrok is hyped about grpc. You’ll share your projects. You’ll learn to wield new Twilio tools. You’ll hone your craft. There’s a session, a track, a speaker, a space for you at SIGNAL. Grab your ticket now, and use the code DEVDIGEST20 to get 20% off your ticket.

os.remove(Stressful_Wedding_Planning.txt)
Thomas automated away the stresses of planning his wedding using Python. Instead of mailing save the date invitations, he fired off an HTTP request to Twilio. How many guests are having the sirloin entree? The answer is one command away. Read how Thomas did it.

Twilio Programmable Fax— No Foolin’

Two things: Yes, it’s real. Yes, it is also 2017. Fax is now programmable. As proof you can send ASCII Art in Node, or check out the docs, or read how your pizza orders might be powered by fax.

Seriously, It’s Real. Tomasz Already Made Fax Serverless

With a quickness, Thomasz shows you how to use Auth0 Webtasks to send faxes sans server. He even shows you how to expose this as a Slack command. Get /faxing.

Build Passwordless Auth with Elixr and Phoenix
QWERTY1234 is not a solid password. Entering in your email, mother’s maiden name, and zipcode is not a solid user experience. Made by Many shows you how to build passwordless authentication using a few simple APIs.

Docker + Rails Made Simple
Remember the name Guillaume Montard. He put together Dockrails, a simple CLI to generate and run a rails environment using Docker. Get a refresher now.

.NET From The Computer to the Cloud with Docker & now.sh
Yep, it’s a double dose of Docker goodness. Dominik Kundel wants you to share that .NET Core app with the world. Learn how to get that bad boy online in this tutorial.

 

Who Picked Up That Call? Was It You, Answering Machine?

Calls work best when they reach their intended recipient (who normally isn’t an answering machine). You can use the newly released Answering Machine Detection feature for Twilio Voice. Learn how to use it now.
 

Closing Thoughts

Let that nostalgia sink in for a bit. Just chase it with some creativity. In a little while, those old programming haunts of yours could spark a new project or a new hack. When that spark hits, let us know.

Developer Digest: Automating Wedding Stress Away in Python

Texting robots on Mars using Python, Flask, NASA APIs and Twilio MMS

$
0
0

NASA has a bunch of awesome APIs which give you programmatic access to the wonders of space. I think the Mars Rover Photos API in particular is really amazing as you can use it to see what kind of pictures the Mars Curiosity rover has been taking.

Let’s build an app using the Mars Rover API with Twilio MMS, Python and Flask to make it so that we can text a phone number and receive pictures from Mars.

Setting up your environment

Before moving on, make sure to have your environment setup. Getting everything working correctly, especially with respect to virtual environments is important for isolating your dependencies if you have multiple projects running on the same machine.

You can also run through this guide to make sure you’re good to go before moving on.

Installing dependencies

Now that your environment is set up, you’re going to need to install the libraries needed for this app. We’re going to use:

Navigate to the directory where you want this code to live and run the following command in your terminal with your virtual environment activated to install these dependencies:

pip install requests==2.13.0 twilio==6.0.0 flask==0.12.1

Requesting data from other APIs

Let’s start by writing a module to interact with the Mars Rover API, which is a URL that returns some JSON.

Create a file called mars.py and enter the following code:

import requests
from random import choice

rover_url = 'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos'

def get_mars_photo_url(sol, api_key='DEMO_KEY'):
    params = { 'sol': sol, 'api_key': api_key }
    response = requests.get(rover_url, params)
    response_dictionary = response.json()
    photos = response_dictionary['photos']

    return choice(photos)['img_src']

What we’re doing here is sending a request using the requests module to the URL corresponding to Mars Rover’s API, parsing the JSON response, and grabbing the URL associated with a random image for whatever Martian Solar day we provide.

Setting up your Twilio account

Before being able to respond to messages, you’ll need a Twilio phone number. You can buy a phone number here.

Your Flask app will need to be visible from the Internet in order for Twilio to send requests to it. We will use ngrok for this, which you’ll need to install if you don’t have it. In your terminal run the following command:

ngrok http 5000

This provides us with a publicly accessible URL to the Flask app. Configure your phone number as seen in this image:
       
Screen Shot 2016-07-14 at 10.54.53 AM.png
You are now ready to send a text message to your new Twilio number.

Building the Flask app

Now that you have a Twilio number and are able to grab a URL corresponding to an image taken on Mars, you want to allow users to text a phone number to view these images.

Let’s create our Flask app. Open a new file called app.py and add the following code:

import os

from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse, Message

from mars import get_mars_photo_url


app = Flask(__name__)


@app.route('/sms', methods=['POST'])
def inbound_sms():
    message_body = request.form['Body']
    resp = MessagingResponse()

    if message_body.isdigit():
        response_message = 'Taken {} Martian solar days into the journey.' 
                           .format(message_body)
        photo_url = get_mars_photo_url(message_body)

        msg = Message().body(response_message).media(photo_url)
        resp.append(msg)
    else:
        msg = Message().body('Text a number of solar days into the rover's journey.')
        resp.append(msg)

    return str(resp)


if __name__ == '__main__':
    app.run()

We only need one route on this app: /sms to handle incoming text messages.

Run your code with the following terminal command:

python app.py

Now text your Twilio number to literally communicate with a robot on Mars!

What just happened?

With this app running on port 5000, sitting behind our public ngrok URL, Twilio can see your application. Upon receiving a text message:

  1. Twilio will send a POST request to /sms.
  2. The inbound_sms function will be called.
  3. A request to the Mars Rover API will be made, receiving a JSON response that then gets parsed to acquire an “img_src” URL to a photo from Mars.
  4. Your /sms route responds to Twilio’s request telling Twilio to send a message back with the picture we retrieved from the Mars Rover API.

Feel free to reach out if you have any questions or comments or just want to show off the cool stuff you’ve built.

Texting robots on Mars using Python, Flask, NASA APIs and Twilio MMS

How to Send SMS Text Messages with AWS Lambda and Python 3.6

$
0
0

Amazon Web Services (AWS) Lambda is a usage-based service that can run arbitrary Python 3.6 code in response to developer-defined events. For example, if a new JPEG file is uploaded to AWS S3 then AWS Lambda can execute Python code to respond to resize the image on S3.

Let’s learn how to use AWS Lambda with a manual test event trigger to send outbound text messages via a Python Lambda function that calls the Twilio SMS REST API.

Getting Started with AWS Lambda

Sign up for a new Amazon Web Services account, which provides a free tier for new users, or sign into your existing AWS account.

After you sign up go to the main Console page that looks like the following screen.

Search for lambda in the dashboard text box.
As shown in the screenshot, use the search box with the text “lambda” to find Lambda on the list of services. Click on Lambda to get to the main AWS Lambda page.
Click the “Create a Lambda function” button. The “Select Blueprint” page will appear.
The Select Blueprint Lambda screen.
Click on the “Blank Function” option to advanced to the “Configure triggers” page. A trigger fires and runs the Lambda function when a developer-defined event happens. I found it confusing at first that the trigger is optional and you don’t actually need to configure a trigger to move to the next step. In our case we’ll test the Lambda function manually after we’ve set it up so click the “Next” button to move on.
Configure Lambda trigger screen.
The “Configure function” screen appears next where we can write some code.
The Lambda configuration screen.

Preparing the Lambda Function

Enter a “sendsms” as the name of the Lambda function and “Send an SMS text message to a phone.” for the description field. In the Runtime drop-down, select Python 3.6 for the programming language.
python-3-6.jpg
Below the Runtime drop-down there is a large text box for code, pre-populated with a stub lambda_handler function. The “Code entry type” drop-down can be changed to upload a ZIP file but for our short function we will stick to the “Edit code inline” option. Replace the default function in the text box and paste in the following code.

import base64
import json
import os
import urllib
from urllib import request, parse


TWILIO_SMS_URL = "https://api.twilio.com/2010-04-01/Accounts/{}/Messages.json"
TWILIO_ACCOUNT_SID = os.environ.get("TWILIO_ACCOUNT_SID")
TWILIO_AUTH_TOKEN = os.environ.get("TWILIO_AUTH_TOKEN")


def lambda_handler(event, context):
    to_number = event['To']
    from_number = event['From']
    body = event['Body']

    if not TWILIO_ACCOUNT_SID:
        return "Unable to access Twilio Account SID."
    elif not TWILIO_AUTH_TOKEN:
        return "Unable to access Twilio Auth Token."
    elif not to_number:
        return "The function needs a 'To' number in the format +12023351493"
    elif not from_number:
        return "The function needs a 'From' number in the format +19732644156"
    elif not body:
        return "The function needs a 'Body' message to send."

    # insert Twilio Account SID into the REST API URL
    populated_url = TWILIO_SMS_URL.format(TWILIO_ACCOUNT_SID)
    post_params = {"To": to_number, "From": from_number, "Body": body}

    # encode the parameters for Python's urllib
    data = parse.urlencode(post_params).encode()
    req = request.Request(populated_url)

    # add authentication header to request based on Account SID + Auth Token
    authentication = "{}:{}".format(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
    base64string = base64.b64encode(authentication.encode('utf-8'))
    req.add_header("Authorization", "Basic %s" % base64string.decode('ascii'))

    try:
        # perform HTTP POST request
        with request.urlopen(req, data) as f:
            print("Twilio returned {}".format(str(f.read().decode('utf-8'))))
    except Exception as e:
        # something went wrong!
        return e

    return "SMS sent successfully!"

The above code defines the lambda_handler function, which AWS invokes to execute your code. The Python code expects two environment variables that are read by the os module with the os.environ.get function.

Within the lambda_handler function we check that all values have been set properly, otherwise we exit with a readable error message. If the appropriate values are in place we populate the URL with the user’s Twilio Account SID as specified in the API reference documentation. We then use Python 3’s urllib standard library functions to perform an API request to Twilio. If Twilio returns the expected HTTP 201 response there will not be an exception so we return from the function with the “SMS sent successfully!” value.

Below the code input area there is a section to set environment variable key-value pairs. Enter two environment variable keys named TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN.
env_vars.jpg
Head to the Try Twilio page and sign up for a free Twilio account so that we can grab Twilio credentials for populating the environment variable values.
try-twilio.jpg
After signing up, you’ll get to the main Twilio Console where you can grab your Account SID and Auth Token. Copy the values and paste them into the environment variable values on the AWS Lambda configuration page.

console-values.png 

The Python 3.6 code and the environment variables are now in place. We just need to handle a few more AWS-specific settings before we can test the Lambda function. Scroll past the environment variables to the “Lambda function handler and role” section, which contains a few more required function configuration items.

Keep the default handler set to lambda_function.lambda_handler. Select “Create a new Role from template(s)” from the drop-down then for the “Role name” field enter “dynamodb_access”. Under “Policy templates” select the “Simple Microservice permissions”.
The “Simple Microservice permissions” allows our Lambda to access AWS DynamoDB. We will not use DynamoDB in this tutorial but the service is commonly used either as permanent or temporary storage for Lambda functions.
For the final configuration, keep the default handler, create a new role from a template for Simple Microservice permissions and save it with a unique name.
Our code and configuration is in place so click the “Next” button at the bottom right corner of the page.

Testing the Lambda Function

The next screen is to review the settings you just configured. Glance through the name, environment variables and other fields to make sure you didn’t typo anything.
review-screen.png
Scroll down press “Create function”.
review-function.png
A success message will appear on the next page below the “Test” button.
function-created.png
Click the “Test” button to execute the Lambda. Lambda will prompt us for some data to simulate an event that would kick off our function. Select the “Hello World” sample event template, which contains some default key that we will replace. Modify the template so you have the following input test event keys:

  • "To": "recipient phone number" – the number in the format “+12023351493” that you want to send a text message to. If you have a trial Twilio account this should be your verified phone number. If your Twilio account is upgraded then this can be any phone number.
  • "From": "twilio phone number" – the number in the format “+19732644156” that you own on Twilio, which will be used to send the outbound SMS
  • "Body": "Hello from AWS Lambda and Twilio!" – the message you want to send from the Twilio number to the recipient phone number

input-test-event.jpg
After entering your test event values, click the “Save and test” button at the bottom of the modal. Scroll down to the “Execution result” section where we can see our output.
sent-successfully.jpg
We can see the return value of the Lambda function and in just a moment our phone should light up with the received message like this:

success-python-3-6-aws-lambda.jpg
Awesome, our AWS Lambda function is working and we can modify it for whatever alert SMS notifications we need to send.

Next Steps

You just configured and ran some serverless infrastructure to call the Twilio API via the serverless AWS Lambda platform. There is a lot more you can do with Python and AWS Lambda. Check out the following tutorials for more code projects:

Questions? Drop a comment down below or contact me via

How to Send SMS Text Messages with AWS Lambda and Python 3.6

Leaving A Message For A Rockstar with Python and Twilio

$
0
0

You know when you’re selling out stadiums and want to connect with your fans one-on-one but can’t exactly give out your personal phone number? Yeah, common problem — for Zac Brown & his band.
Zac Brown Band has about 1.67 million Twitter followers. The ZBB squad wanted to reach out to every fan before dropping their new record (which came out today). Dialing up 1.67 million people is tricky, so the ZBB team let the fans come to them.

Now, all of them can call up Zac Brown Band’s Twilio number and leave a message relaying their favorite memory, song, or moment from an album.

Here’s an initial prototype of the app I built for Zac’s management crew to get ideas flowing. The entire app runs on about 60 lines of Python.

The goal is to do the following things in order:

  • Greet the caller with a friendly message
  • Allow them to record a message
  • Tell Twilio when they’re done recording a message and bid them adieu.

In this prototype, we set a max length of 30 seconds to ensure the team can get through everyone’s messages easily, and to ward off any would-be-butt-dial voicemails.

Here’s all the code you need to make it happen.

 

from flask import Flask, request
from twilio.twiml.voice_response import VoiceResponse, Gather


app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def welcome():
    """
    Twilio voice webhook for incoming calls.
    Respond with a welcome message and ask them to press 1
    to record a message for the band.
    """
    # Start our TwiML response
    resp = VoiceResponse()

    # <Say> a welcome message
    resp.say("Welcome to the band's line")
    resp.say("Press 1 to record a message for the band")

    # <Gather> a response from the caller
    resp.gather(numDigits=1, action='/start-recording')

    return str(resp)

@app.route('/start-recording', methods=['GET', 'POST'])
def start_recording():
    """Processes the caller's <Gather> input from the welcome view"""
    # Start our TwiML response
    resp = VoiceResponse()

    # If the caller pressed one, start the recording
    if 'Digits' in request.values and request.values['Digits'] == '1':
        resp.say('Awesome. Leave a message after the tone.')
        resp.record(max_length="30", action="/end-call")

    # Otherwise, say we didn't understand the caller and ask them to try again
    else:
        resp.say("Sorry, I didn't understand that.")
        resp.say("Press 1 to record a message for the band")
        resp.gather(numDigits=1, action='/start-recording')

    return str(resp)

@app.route('/end-call', methods=['GET', 'POST'])
def end_call():
    """Thanks a caller for their recording and hangs up"""
    # Start our TwiML response
    resp = VoiceResponse()

    # <Say> thanks to the caller
    # (Add your signoff as you see fit)
    resp.say("Thanks for your message. The band will be stoked.")
    resp.hangup()

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)

If you’ve got any ideas for what you can build in Python, keep me posted – kylekellyyahner.

Leaving A Message For A Rockstar with Python and Twilio

Birth Announcements for the Busy Father using Python, Flask and Twilio

$
0
0

One day during my wife’s first pregnancy, it dawned on me that a lot of people would be interested to know when the baby was born. I began counting all the family members and friends who would want some notification about the baby’s arrival and realized I’d be making more phone calls than I would prefer. Sure, I could shove everyone into one big group text message, but then I run the risk of missing someone who might care while also subjecting myself to a seemingly endless cacophony of notification beeps.

To solve our endless beeping problem, we need a way to allow others to quickly learn about the birth of the child while notifying anyone who might care. We accomplish this using Python, Flask, and Twilio. With Twilio we can text or call anyone we like without the burden of doing so ourselves: all it takes is around 150 lines of Python.

What We’re Building

We want to take a list of phone numbers and have them each receive a call with a message of our choosing. WeI could guess at what numbers should be in that list, but it would be better if we did not have to manually enter numbers into a database. Since the purpose of this is to notify people about the birth of a child, it can not happen at a set time, so the application also needs to have a way to be triggered at a time of our choosing.

The application allows users to call a phone number and register their numbers to receive a call. When a specific text message is sent to that number, it uses Twilio to call each number in the list and read off a hard-coded message to the person, notifying him or her of the birth. This is functional and simple and will solve the problem for us nicely. A well-placed social media post containing the phone number for the application will then allow you to gather the phone numbers of everyone who might care about your child’s birth.

The Code

The project is written in Python and uses Flask. If you would like to skip the explanation you can see everything in its home on Github.

A SQLite database is sufficient for data storage. Flask-SQLAlchemy is a great extension that I highly recommend, but it is overkill for such a simple project, so let’s use Python’s built-in sqlite3 module instead.

Your Dev Environment

Flask is a micro web framework, and as such we do not need too much to get an application up and running. Let’s set up our project.

It is good practice when developing Python projects to use a virtual environment. Using your Python version of choice (preferably 3), install virtualenv if you haven’t already via pip (pip install virtualenv), then run virtualenv .venv in your project directory. Activate your virtual environment with source .venv/bin/activate on Linux or .venvScriptsactivate on Windows.

Next you need to install your dependencies in your virtual environment. This project will make use of the flask, twilio, and requests libraries. Install them via pip: pip install flask twilio requests. If you would like to use the exact versions of each library that I did, you can use my requirements.txt file). Save it to disk then run pip install -r requirements.txt. It should be noted that I used twilio version 5.6.0, which uses the TwilioRestClient you see in the code, rather than more recent versions (6+) using Client.

Your next step is purchasing a phone number from Twilio and retrieving your SID and auth token. After you have done that, we need an easy way to supply this data to our Flask app. Create a configuration file called config.py in the root of your project directory with the following information.

PHRASE = 'itshappening'             # the secret phrase to POST to kick off notifications
NUMBER = '+13338675309'             # your twilio phone number
PORT = 1234                         # the port your app will run on
URL = 'http://yoursite.com'         # the callback url for phone calls
SID = 'yourtwiliosid'               # your twilio sid
AUTHTOKEN = 'yourtwilioauthtoken'   # your twilio auth token

Flask apps run on port 5000 by default, but you can change that to whatever value you want in the above config file under PORT. The PHRASE is essentially a password used to start the notification process, so you’ll want to set this to something that malicious family members would not be able to guess. For phone calls to work, your TwiML needs to specify a callback URL for Twilio to route requests to. If you are hosting the service on a server with a domain name, then use that here. In my case I just use the public IP address of my Digital Ocean droplet where the app is running (http://192.168.1.1 as an example for how it should look).

The Flask App

Our application is small and simple, so all files can go in the root directory with config.py. If you really wanted, you could put all of the code we will write into the same file, but some logical separation should still exist to maintain sanity.

We started this logical separation with config.py, and can continue it with utility functionality. Create a utils.py file for holding our functions for interacting with the database and any other simple functionality we may need:

import os
import sqlite3


DB_NAME = 'numbers.db'
SCHEMA = 'create table numbers (id integer primary key autoincrement not null,number text not null,text integer not null)'


def init_db():
    exists = os.path.exists(DB_NAME)
    with sqlite3.connect(DB_NAME) as conn:
        if not exists:
            conn.executescript(SCHEMA)
            conn.commit()


def insert_to_db(number: str, text: bool):
    with sqlite3.connect(DB_NAME) as conn:
        cursor = conn.cursor()
        cursor.execute('SELECT id FROM numbers WHERE number = ?', (number,))
        data = cursor.fetchone()
        if not data:
            text = 1 if text else 0
            cursor.execute('INSERT INTO numbers (number, text) values (?,?)', (number, text))
            conn.commit()


def get_all_numbers():
    with sqlite3.connect(DB_NAME) as conn:
        cursor = conn.cursor()
        cursor.execute('SELECT number, text FROM numbers')
        numbers = cursor.fetchall()
        return numbers


def make_recordings_directory():
    if not os.path.exists('recordings'):
        os.mkdir('recordings')

Three of the four functions are database related: one for creating the database if it does not exist init_db(), another for adding a user’s information insert_to_db(), and another for getting all of the users from the database get_all_numbers(). The fourth function make_recordings_directory() creates a directory for us to store recordings, a feature we will cover later. If you have a basic understanding of SQL then the database functionality should make sense to you. If not, just trust me that it works, or read up on it if trust is not your strong suit.

Now we can begin making our application. For this post, I assume you have a basic knowledge of Flask. Create a file called run.py (or app.py if you prefer) and add the following code.

import twilio.twiml
from twilio.rest import TwilioRestClient
from flask import Flask
from flask import request
from flask import redirect
from flask import url_for
import requests

import utils


app = Flask(__name__)
app.config.from_pyfile('config.py')
utils.init_db()
utils.make_recordings_directory()
MESSAGE = ''


@app.route('/')
def index():
    return 'go away'

This code initializes your Flask app, configures it, initializes your database, and creates a dummy index route. You do not need the dummy route, but I included it to yell at all the bots that scan my droplet regularly.

Our first feature to address is allowing users to register a phone number. We will need an initial endpoint for entering a number, another for confirming the number that was entered, another for handling the confirmation digits (redirect to the start if failed, otherwise redirect to the next step), another for asking whether the user wants a phone call or a text message, and finally an endpoint for saving the user’s information. Each endpoint makes heavy use of twilio.twiml.Response, which is our way of telling Twilio what we want to happen, and the gather() method of that class.

The following is the entry point for when users first call our number. We want to greet the caller, then prompt the caller for a phone number to register. We accomplish this using Response.gather() to collect digits and to tell Twilio which endpoint to visit next. Each endpoint needs to return valid TwiML to interact with Twilio, and calling str() on the Response() object provides that for us.

@app.route('/api/register', methods=['GET', 'POST'])
def register():
    resp = twilio.twiml.Response()
    resp.say('Welcome to the Labor Notifier.', voice='female')
    # Aren’t context managers the best?
    with resp.gather(numDigits=10, action=url_for('confirm'), method='POST') as g:
        g.say('To register to receive a phone call once the baby is born, please enter your '\
              'phone number. Enter the 3 digit area code, followed by the 7 digit number', voice='female')
    return str(resp)

The next endpoint is where Twilio is redirected to after collecting the 10 digit phone number from the caller. Its purpose is to have the user confirm she entered the correct number. You could skip this step if you trust your users to always type correctly, but I don’t put a lot of trust in the shaky hands of older generations, let alone my own hands.  We use the gather() method again to have the caller confirm if the number she entered is correct, and to redirect to another route for checking the result of this call. It is important to note that the “action” specified in the gather() call includes passing the digits entered at the first step between endpoints. The application is stateless at this point so we need to remember the original phone number entered before we save it to a database.

@app.route('/api/confirm', methods=['GET', 'POST'])
def confirm():
    resp = twilio.twiml.Response()
    digits = request.values.get('Digits', None)
    # space the digits so they are recited properly
    digits_spaced = ' '.join(ch for ch in digits)
    with resp.gather(numDigits=1, action=url_for('confirm_route', number=digits), method='GET') as g:
        g.say('You entered the number ' + digits_spaced + '. If this is correct, press 1. Otherwise, press 2.')
    return str(resp)

In the following endpoint, if the caller pressed 1 then we can proceed and pass along the phone number entered at the first step. If the caller entered anything other than 1 then we send her back to the confirm() endpoint.

@app.route('/api/confirm_route')
def confirm_route():
    resp = twilio.twiml.Response()
    digit = request.args.get('Digits', None)
    if digit == '1':
        number = request.args.get('number', None)
        resp.redirect(url=url_for('text_or_call', number=number), method='GET')
        return str(resp)
    else:
        resp.redirect(url=url_for('register'))
        return str(resp)

At this point the caller has entered her phone number and confirmed that it is correct. Now we need to ask her if she wants a phone call or a text message when it comes time to send out the notification. We still are not to the point of saving the number to the database yet, so we have to continue passing the number between endpoints.

@app.route('/api/text_or_call')
def text_or_call():
    resp = twilio.twiml.Response()
    number = request.args.get('number', None)
    with resp.gather(numDigits=1, action=url_for('save_number', number=number), method='GET') as g:
        g.say('If you would like to receive a text message, press 1. If you would like to receive a' \
              ' phone call, press 2.')
    return str(resp)

Now we can finally save this number to the database. The ‘Digits’ request argument contains a number corresponding to whether the caller wants a call or a text.  We still have access to the original number because of our due diligence in passing it between each endpoint in the “number” parameter. This time, we need to know for certain if the caller wants a text or a call, so we redirect the caller back to the prior endpoint if the entered digit is not 1 or 2. Then we call our insert_to_db() method from utils.py and end the call.

@app.route('/api/save_number')
def save_number():
    resp = twilio.twiml.Response()
    digit = request.args.get('Digits', None)
    number = request.args.get('number', None)
    text = None
    if digit == '1':
        text = True
    elif digit == '2':
        text = False
    else:
        resp.say(digit+' is not a valid choice.')
        resp.redirect(url_for('text_or_call', number=number), method='GET')
        return str(resp)
    number_spaced = ' '.join(ch for ch in number)
    number = '+1' + number
    utils.insert_to_db(number, text)
    resp.say('Thank you. You will receive a notification at that number once the baby is born.', voice='female')
    resp.say('Goodbye.', voice='female')
    resp.hangup()
    return str(resp)

Those five endpoints accomplish the stated needs. One gotcha is preserving the user’s entered phone number across requests. We can pass it around in a number parameter to each endpoint. This process starts in the /api/confirm endpoint with action=url_for('confirm_route', number=digits). Another is making the nice robot lady properly repeat the number back to the caller for confirmation. If you simply put 8675309 into the TwiML, she will dutifully say “eight million, six hundred and seventy five thousand, three hundred and nine” instead of “eight six seven five three zero nine”. Put spaces between the digits and use that instead (digits_spaced = ' '.join(ch for ch in digits)). Also note that SQLite does not support Booleans. Instead, we use zero or one to indicate false or true (you might have already noticed this in utils.insert_to_db()).

Next, we need to handle notifying the users. The app needs to check received text messages for the PHRASE we set in our config file and iterate through our users, sending texts or making phone calls. Users receiving text messages do not need any other special endpoints as we do not expect responses back from them, but for phone calls we need to have an endpoint for handling the redirect from Twilio.

This is our endpoint for handling text messages sent to our number. If a user sends a text that does not start with our secret phrase then we ignore the text rather than sending something back. This saves you some money, although you still incur a cost for the received message. We retrieve all of our users from the database then use their preference for text vs call to either send a text message using client.messages.create() or make a phone call using client.calls.create(). The text message containing the secret phrase will also include the message to send out to your users. This code expects it to look like “secretphrase Here is my message to send”. Because users getting phone calls are handled in a different endpoint, we use the global MESSAGE to preserve the specified message.

@app.route('/notify', methods=['GET', 'POST'])
def notify():
    global MESSAGE
    if request.form['Body'].startswith(app.config['PHRASE']):
        MESSAGE = request.form['Body'].replace(app.config['PHRASE'], '')
        client = TwilioRestClient(app.config['SID'], app.config['AUTHTOKEN'])
        numbers = utils.get_all_numbers()
        for number in numbers:
            if number[1] == 0:
                client.calls.create(to=number[0], from_=app.config['NUMBER'],
                                    url=app.config['URL']+'/api/notify')
            else:
                client.messages.create(to=number[0], from_=app.config['NUMBER'],
                                       body=MESSAGE)
        resp = twilio.twiml.Response()
        resp.message('Finished notifying all {} numbers'.format(len(numbers)))
        return str(resp)
    return ''

This final route handles users receiving a phone call. It simply says our specified message, then ends the call.

@app.route('/api/notify', methods=['GET', 'POST'])
def notify_number():
    resp = twilio.twiml.Response()
    resp.say(MESSAGE, voice='female')
    resp.say('Thank you. Goodbye.', voice='female')
    resp.hangup()
    return str(resp)

Notice the dreaded global keyword in there? It’s an abomination that will be removed in a future iteration to be replaced with parameter passing similar to what was used with the user’s phone number in the registration process. When we text the app our special phrase, we put a space after the phrase then enter our desired message to be passed on to the users. That phrase can be immediately used in that endpoint for users receiving text messages, but it needs to be passed along to the endpoint for handling phone calls in order for those users to hear it. We create a TwilioRestClient using our SID and auth token and use that to send messages and make calls.

One feature that I added was the ability for users receiving a phone call to leave a message for my wife and I. It certainly is not necessary, but it was a nice experimentation with the voice recording feature that Twilio offers. We will not cover it here, but you can see it in run.py over on Github.

Finish your application with app.run(host='0.0.0.0', port=app.config['PORT']) and your code is done! This will run your Flask app in a way that allows it to listen for incoming connections on your specified port with all your server’s available IPv4 interfaces.

The final step is supplying Twilio with your endpoints for handling phone calls and text messages. Open the Twilio console and add http://yourip:1234/api/register for phone calls and http://yourip:1234/notify for messaging to your purchased phone number.

Run the App

Running your application is as simple as python run.py. Assuming you run this on some server under your control, you will likely be connected in remotely. Because of this, if you disconnect from your remote session then your application will not stay running. I solve this problem by using a terminal emulator called tmux and running my application in there: the tmux session stays running even after I disconnect. If your server goes down then so does your application, so a more robust solution is ideal, but that is outside the scope of this post. I’ve had the same droplet running on Digital Ocean for 3 years with no downtime, so this has yet to become a real concern.

970 (1).png

Wrapping it Up

Congratulations! You just saved yourself the headache of calling every one of your relatives when your baby arrives. The application is lightweight, allows for custom messages, and pushes the problem of being notified onto others. You might have to help Grandma through the registration process, but in the end a simple text message allows you to trade a symphony of beeps for a solo (or duet, or trio) of crying.

Because this app was originally written as a small side project, it is lacking in some features that may make it more friendly.

  • Allow for registering via text
  • Add an admin interface for you to easily manage the db
  • Get rid of the nasty global variable
  • Make the bot voice configurable

Using Twilio for this has allowed my wife and I to enjoy some time with our new baby at the hospital while also satisfying the masses who want to know all about it. Automation simplifies and improves our lives so we can focus on what truly matters, and services like Twilio allow for that.

If you have questions about the app or ideas for improvement, file a ticket on Github.

Birth Announcements for the Busy Father using Python, Flask and Twilio

Viewing all 78 articles
Browse latest View live