Receive SMS Messages with A LinkIt ONE using Programmable Wireless, AWS IoT and Lambda
Time to read: 7 minutes
Want to receive - and react to - SMS and MMS messages on a LinkIt ONE? We'll help you do just that today, using Twilio's Programmable Wireless and Amazon Web Services' IoT, API Gateway, and Lambda. Upon receiving an incoming SMS or MMS, a Twilio number will trigger a Webhook that sets our infrastructure in motion.
If you haven't done so yet, run through our guide on sending SMS or MMSes with the LinkIt ONE and Twilio Programmable Wireless. We'll be building on top of the same infrastructure in this post, and will assume you have it in place. As before, this code will work with either Programmable Wireless or WiFi.
Already ran through the last guide? Awesome, let's let the LinkIt talk back!
Building Infrastructure to Receive Incoming Messages
We're going to turn the architecture from the sending article on its head for this objective. Now, when Twilio receives and incoming message, it will post to an endpoint you expose with API Gateway. API Gateway will trigger Lambda, which we will give permission to post directly to the twilio
topic on MQTT.
Remember, the LinkIt ONE is already subscribed to the MQTT twilio
topic; we simply need to add some business logic which reacts to incoming messages. We can then respond in the same way we did in the sending guide - by using the Lambda send message function.
Mock an API Endpoint with AWS API Gateway
We’re going to use Amazon’s API Gateway to expose the endpoint Twilio will hit when it sees incoming messages.
There are quite a few steps here, so we've condensed them for you to take it a step at a time:
- Go to the API Gateway console
- Create a new API in the same AWS region as IoT and the first Lambda function from the previous post
- Name it ‘Twilio-to-IoT’ and enter a description
- You’ll now be redirected to your new API’s ‘Resources’
- In the ‘Actions’ menu, select ‘Create Resource’
- Name it ‘Messages’ and check the ‘Resource Path’ is ‘
/messages
’:
- Create ‘/messages’ by hitting the blue 'Create Resources' button
- In the ‘Actions’ menu, select ‘Create Method’, then ‘
POST
’ - Click the tiny checkbox next to
POST.
In the ‘Integration Type’ select ‘Mock’ - You’ll then be redirected to a screen that looks like this:
- In the ‘Actions’ menu, select ‘Deploy API’
- Create a new stage and name it ‘prod’ (and any description)
- Deploy your mock API Gateway to
prod
- Next, you’ll be redirected to the
prod
stage editor (if not, it’s under your API in ‘Stages’) - Click '
POST
' under messages - Find the ‘Invoke URL’ at the top of the page and copy it somewhere safe; that is the endpoint we will eventually use with Twilio's webhook
Great stuff! You've not got a mock endpoint set-up. We'll eventually return here to add the logic we need to receive and reply to Twilio, but for now, you're done. Next, we're going to move on to Lambda.
Create a New Amazon Lambda Function
In the sending messages article, we created a simple function which POST
ed to Twilio after receiving carefully constructed MQTT messages. For receiving messages, we're going to do roughly the opposite, and forward incoming messages back to the LinkIt over the same channel.
Again, this is quite a few steps, so we've condensed them to make them easier to follow.
- Go to the AWS Lambda console
- Select ‘Python 2.7’ and ‘Blank Function’
- For triggers, select ‘API Gateway’
- Select the brand new ‘
Twilio-to-IoT
’ API with stage ‘prod’ - Use ‘Open’ security
- DOWNLOAD THIS ZIP FILE with our code
Here's a look at receiving messages:
As a message comes in from Twilio, we quickly do some checks for validity, message size, and the like. On an embedded platform you'll want to do a lot of this on the server.
Of special note, you can see we're checking for the existence of the X-Twilio-Signature
header. This signature is a hash of the POST
ed form plus your API Secret, which you can find in the Twilio console. See more about how Twilio helps you secure incoming requests.
Let's continue the build!
- Change ‘Code entry type’ to ‘Upload a .ZIP file’ and upload the ZIP file
- Set the following FOUR environment variables:
AUTH_TOKEN
(from the Twilio Console)AWS_TOPIC
(set this totwilio
, no quotes)REQUEST_URL
(use the Invoke URL from API Gateway we called out above)AWS_IOT_REGION
(use the region your LinkIt IoT resides in, e.g.: us-east-1 or us-west-2) - Set ‘Handler’ to ‘twilio_functions.twilio_webhook_handler’
- For ‘Role’, create a new role and use the IoT Button template (remember what you name this role, you'll need it later)
For now, that's all you'll need to do on the Lambda side. However, we're not quite finished with this specific functionality. You need to give a user some new permissions.
As you can see in the code, at one point we do this:
aws_region = os.environ['AWS_IOT_REGION']
aws_topic = os.environ['AWS_TOPIC']
client = boto3.client('iot-data', region_name=aws_region)
client.publish(
topic=aws_topic,
qos=0,
payload=json.dumps({
"To": form_parameters[u'To'],
"From": form_parameters[u'From'],
"Body": form_parameters[u'Body'],
"Type": "Incoming"
})
)
We're using the boto3 package and trying to publish
directly to the twilio
MQTT topic in whichever region you set in the environmental variables.
However, if you ran this now... you'd have no luck. Let's fix that.
Grant Your Code More Permissions with IAM
Go to IAM by using the 'My Security Credentials' in your name pulldown (top of the screen):
- Click on the 'Roles' link on the left
- Find the role you made for the Lambda function and click on it to make it active
- Click on the 'Create Role Policy' button under 'Inline Policies':
- Pick ‘Custom Policy’
- Here’s the policy to use:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Publish"
],
"Resource": [
"*"
]
}
]
}
- Name it with your choice of name (you won't come back to it) and save it
And with that, Lambda can now publish to the twilio
MQTT topic. Let's return now to API Gateway and build out our mock API.
Fully Build Out Your API in API Gateway
By default, API Gateway is made to handle JSON data. Twilio expects, however, to be able to POST
form data and to receive XML
in the form of TwiML. These next steps will both ensure our Lambda function is called, as well as change the API Gateway defaults to handle form POSTs as well as XML.
Ready to dive in? We've carved up the steps for you to follow once again. Start by heading back to the API Gateway Console.
- After logging in (if necessary), click 'Resources' under your API:
- Click the ‘ANY’, in purple, which was automatically added by Lambda with the name of the function
- In the ‘Actions’ menu, choose ‘Delete Resource’
- You’re now in the same place as the original Mocked API
Add a Lambda Integration (Integration Request)
At this point, we need to add back the Lambda integration.
- Click ‘Integration Request’ and change the ‘Integration Type’ to Lambda function
- Select your region and function
- Click 'Save'
- Click through the 'overwriting' prompt
- Next, click the right arrow to expand the ‘Body Mapping Templates’
- Delete any
body mapping
s that currently exist (e.g.:application/json
) - Add a new
body mapping
for:application/x-www-form-urlencoded
- Add this as the
body mapping
template:
#set($httpPost = $input.path('$').split("&"))
{
"twilioSignature": "$input.params('X-Twilio-Signature')",
#foreach( $kvPair in $httpPost )
#set($kvTokenised = $kvPair.split("="))
#if( $kvTokenised.size() > 1 )
"$kvTokenised[0]" : "$kvTokenised[1]"#if( $foreach.hasNext ),#end
#else
"$kvTokenised[0]" : ""#if( $foreach.hasNext ),#end
#end
#end
}
Here we’re taking every POST
ed parameter and mapping it to JSON to pass to Lambda. In Lambda, you'll recall, we use the POST
ed parameters to validate requests are from Twilio.
- ‘Save’ the template
- Click the back arrow ‘Method Execution’ at the top
Pass Through the X-Twilio-Signature Header (Method Request)
To validate incoming requests, we need to pass along the X-Twilio-Signature
header as discussed above. Let's add that now.
- Click ‘Method Request’
- Expand ‘HTTP Request Headers’
- ‘Add header’ and add the header ‘X-Twilio-Signature’
- Save that and return to the main screen with the ‘Method Execution’ link
Add XML Support to Your API (Integration Response)
When Twilio hits your endpoint, it expects XML in return. Now, let's modify the API to return that XML.
- Click ‘Integration Response’.
- Expand the right arrow by clicking on it
- Delete anything that exists in the ‘Body Mapping Templates’ area
- Click ‘Add mapping template’ and add ‘
application/xml
’. - For the template itself, use:
#set($inputRoot = $input.path('$'))
$inputRoot
We are simply passing along all data with this template, echoing inputRoot
into the body. This lets us write XML directly into the body without API Gateway attempting to rewrite anything.
- Click the ‘Method execution’ link to return to the main API screen
Continue XML Support (Method Response)
There is one last step for our XML. We need to return application/xml
when we give the all clear 200
.
- Click ‘Method Response’
- Modify the ‘Response Body' for
200
to be ‘application/xml’. - Go back to ‘Method execution’ by clicking the link at top
Almost done now!
Deploy Your API
There is just a single API Gateway objective left - deploying!
- In ‘Actions’, scroll down to ‘Deploy API’
- Deploy it to prod
- Copy the ‘Invoke URL’ to your clipboard
Make sure that you have copied the URL to the clipboard. The last step is with Twilio itself; we're going to paste that URL into the Webhook and test the integration!
Set Up Your Twilio Webhook
The last step is to change the behavior of one of your Twilio phone numbers in the console. We will set the message webhook to the URL you copied in the above step.
- Go to the Twilio Console now
- Click the ‘#’ icon to see the numbers you own
- Pick - or buy - a number which handles MMSes and SMSes (or just SMSes, depending on what you plan to send)
- Paste the execution Invoke URL from API Gateway in the ‘Messaging’ Webhook:
And that's it! Power cycle your LinkIt and wait for it to connect to AWS IoT.
Then text it something like 'Racecar'.
C'mon, you know you want to...
Building Out the Internet of Things with Twilio and a LinkIt ONE
With this guide and the guide on sending messages with Twilio's Programmable Wireless, AWS, and the LinkIt ONE, you've now got both inbound and outbound messaging working with your board.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.