May 24, 2016

At SIGNAL we launched Twilio Programmable Wireless which allows you to add cellular data to your IoT projects using a Twilio SIM card. The LinkIt ONE dev board in the SIGNAL hackpack is a perfect place to try out these new capabilities. In the next 5 minutes you’ll learn how to use the cellular functionality of this device using your Twilio SIM card.

What You’ll Need

Before we get to hacking there are a few things we need to get set up. First, we need to set up the LinkIt ONE board and make sure it is programmable using the Arduino IDE and the MediaTek LinkIt ONE SDK. The steps for getting this set up are outlined in this blog post. Once you’ve completed those steps you’ll want to also make sure to attach the cellular antenna if you haven’t already because it is needed for Twilio Programmable Wireless.

Next, we need to activate the Twilio SIM in our account. If you received a SIM card with a hackpack at SIGNAL your SIM is already activated so you can skip this activation step. Otherwise, you can activate your SIM card in the Twilio Programmable Wireless portion of the console by entering its
ICCID into the text field as shown on this screenshot:

Once you’ve activated your SIM card, plug it into the LinkIt ONE’s SIM card slot as shown in this photo:

That’s all for hardware setup.

Can I Make a Request?

The MediaTek LinkIt ONE SDK includes a library for working with the cellular functionality of the LinkIt ONE development board. To include this library in our project we’ll add it from the Library Manager in the Arduino IDE. Create a new Sketch and under the Sketch menu select Include Library > LGPRS. This will add four header files. We only need two of them: LGPRS.h and LGPRSClient.h. The top of your Sketch should look like this:

#include <LGPRS.h>
#include <LGPRSClient.h>

The LGPRS class allows us to attach to a GPRS network. The LGPRSClient class is what we’ll use to make an HTTP request using the LGPRS connection we’ve established using LGPRS. Add the following code underneath the two #include lines:

#define SITE_URL "putsreq.com"
LGPRSClient client;

For this tutorial I’ve set up a URL on putsreq.com that returns “Hello world”. If you want to see it in action in your browser you can click on this link. In the code above we #define the base URL for this site in SITE_URL. We’ll use this later when we connect to the site and make an HTTP request. The next line declares an LGPRSClient variable that we’ll use to write our HTTP GET request.

All Arduino projects consist of a setup() function that initializes the project and a loop() function that runs indefinitely and does the main work for the project. We’ll start in the setup() method by turning on the cellular radio and connecting it to Twilio Programmable Wireless. Replace your setup() function with the following code:

void setup() {
   Serial.begin(9600);
 
   // Connect to cellular network using Twilio Wireless
   while(!LGPRS.attachGPRS("wireless.twilio.com", NULL, NULL)) {
      Serial.println("Waiting for GPRS signal...");
      delay(1000);
    }
    Serial.println("GPRS attached.");
}


Now would be a great time to make sure everything is working. Click the Upload button in the Arduino IDE and open up the Serial Monitor from the Tools menu. If everything is working correctly you should see “GPRS attached.” printed out in the Serial Monitor.

Next use the LGPRSClient to make a connection to SITE_URL so that we can send requests to our putsreq.com sample. Add the following code to the end of your setup() function:

// Connect client to the test site
Serial.println("Connecting to: " SITE_URL "...");
if(!client.connect(SITE_URL, 80))
{
   Serial.println("Connection successful.");
} else {
   Serial.println("Could not connect to: " SITE_URL);
   return;
}


We first attempt to connect to the site on port 80. If we are successful, “Connection successful” is printed in the Serial Monitor. If not, we return from setup() and print an error message. Now that we’re connected to the site we can make our HTTP GET request. Add this code to the end of your setup() function:

Serial.println("Sending test GET request...");

// Make GET request to test site. Returns "Hello world!"
// We'll display the response in loop()
client.println("GET /m3JKNFhGxaeu0KsXcdLl HTTP/1.1");
client.println("Host: " SITE_URL);
client.println();
Serial.println("Waiting for response from test site...");
Serial.println("————————————————————————");

This code writes out the HTTP GET request lines using the LGPRS client. The response to this request will be available in the loop() function.

Write the loop() function thatreads the results of our HTTP GET request to http://putsreq.com/m3JKNFhGxaeu0KsXcdLl. Replace the loop()function in your Sketch with this code:

void loop() {
  if (client.available()) 
   { 
      char c = client.read(); 
      Serial.print(c); 
   }
}

This code checks to see if there is data available in the client. Once the request comes in it prints out the response to our GET request character by character. At this point our example is complete. Upload the Sketch to your development board and watch Serial Monitor for the results. Here’s what it looks like running on my board:

That’s it, you just wrote your first Twilio Programmable Wireless program!

What’s next?

Now that you have Twilio Programmable Wireless working on your LinkIt ONE board, your IoT projects have access to the Internet using cellular data. Here are some things you might consider doing now that you have this working:

  • Write a GPS tracker that pushes updates to a server
  • Create a weather station that fetches weather data from the Internet

We’re super excited to see what you build with Twilio Programmable Wireless. If you’re at SIGNAL, come see me at the hackpack station and let’s talk about IoT. Otherwise, if you have any questions or comments you can find me on Twitter @brentschooley or email me at brent@twilio.com.

Getting Started with Twilio Programmable Wireless on the LinkIt ONE

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Twilio Add-ons let you supercharge your Twilio API calls with features and capabilities offered by other communications API’s. Let’s add some Add-ons to our account and see how these mashups let us build better apps with fewer API calls.

Activating your favorite Add-ons

Find Add-ons to add to your account by heading over to the new Twilio Marketplace section of the Console. In this post we’ll look at two of them, the Whitepages Pro Phone Reputation and the IBM Watson Message Sentiment Add-ons.

To activate the Whitepages Pro Phone Reputation and the IBM Watson Message Sentiment Add-ons, press the Install button.

For the Whitepages Pro Phone Reputation Add-on, make sure that the Use In Lookups checkbox is selected. For the IBM Watson Message Sentiment Add-on, make sure that the Use In Incoming SMS Message checkbox is selected.

Once both Add-ons are activated we’re ready to start using them.

No more spam or serial-fraudsters!

With the Whitepages Pro Add-on we can retrieve fraud score information as part of a request to the Twilio Lookup API.

To tell Twilio we want this additional data all we need to do is pass the AddOns parameter to the API specifying the unique names of the Add-ons to use.

For example, using the Twilio Node helper library you include an addOns parameter with your Lookup request:

'use strict';

let LookupsClient = require('twilio').LookupsClient;
let client = new LookupsClient('YOUR_TWILIO_ACCOUNT_SID', 'YOUR_TWILIO_AUTH_TOKEN');

client.phoneNumbers('+15108675309').get({
  type: 'carrier',
  addOns: 'whitepages_pro_phone_reputation'
}, (error, number) => {
  console.dir(number.addOns.results['whitepages_pro_phone_reputation'], { depth: 5 });
});

Twilio will do a phone number lookup and mash the results of that API request together with the result from the Whitepages Pro API, placing that data into a property named add_ons.

{
    "country_code": "US",
    "phone_number": "+15108675309",
    "national_format": "(510) 867-5309",
    "carrier": {
        "mobile_country_code": "310",
        "mobile_network_code": "120",
        "name": "Sprint Spectrum, L.P.",
        "type": "mobile",
        "error_code": null
    },
    "add_ons": {
        "status": "successful",
        "message": null,
        "code": null,
        "results": {
            "whitepages_pro_phone_reputation": {
                "status": "successful",
                "message": null,
                "code": null,
                "result": {
                    "results": [
                        {
                            "phone_number": "5108675309",
                            "reputation": {
                                "level": 1,
                                "details": [
                                    {
                                        "score": 1,
                                        "type": "NotApplicable",
                                        "category": "NotApplicable"
                                    }
                                ],
                                "volume_score": 2,
                                "report_count": 1
                            }
                        }
                    ],
                    "messages": []
                },
                "requestSid": "XRbcbde3f247cdd7bfd02b92053a3db9ac"
            }
        }
    },
    "url": "https://lookups.twilio.com/v1/PhoneNumbers/+15108675309?Type=carrier"
}

The reputation of the phone number is described in the add_ons.results.whitepages_pro_phone_reputationproperty with Level 1 meaning there is a low chance of this phone number being fraud related while Level 4 is a 97% chance that this is a fraud related number.

Happy or sad customer SMS?

Programmatically receiving and responding to SMS messages can enable great customer experiences. However without appropriately determining the context of the message we can end up with a static experience that feels robotic to the user.

With the IBM Watson Message Sentiment Add-on you can perform sentiment analysis on every incoming message without making any changes to your application. Because we’ve enabled the Add-on we start getting the semantic analysis results automatically passed in the payload of every incoming SMS webhook request.

Grab the ibm_watson_sentiment information out of the AddOns property from the payload and use it to determine whether the message is positive, negative or neutral and even how strong the sentiment is so that you can reply accordingly.

Give it a try using Node.js by creating a new file called server.js and dropping this code into it:

'use strict';

const bodyParser = require('body-parser');
const express = require('express');
const http = require('http');
const twilio = require('twilio');

const app = express();
const port = process.env.PORT || 3000;

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.post('/sms', (req, res) => {
  let twiml = new twilio.TwimlResponse();
  
  let addOnResults = JSON.parse(req.body.AddOns);
  let sentimentResult = addOnResults.results['ibm_watson_sentiment'];
  if (sentimentResult.status === 'successful') {
    if (sentimentResult.result.docSentiment.type === 'positive') {
      twiml.message('YAY! Glad to see you happy!');
    } else if (sentimentResult.result.docSentiment.type === 'negative') {
      twiml.message('That is unfortunate. Anything I can do?');
    } else {
      twiml.message('Ahoy! How are you?');
    }
  } else {
    twiml.message('We could not determine how you feel :(');
  }
  
  res.type('text/xml').send(twiml.toString());
});

http.createServer(app).listen(port, () => {
  console.log(`listening on port '${port}'`);
});

Install the application dependencies and start the server:

$ npm install body-parser express twilio
$ node server.js

Run ngrok http 3000 in a separate window to expose your server to the public using ngrok. If you want to know more about ngrok you can read more here.

Wire up the Message Request URL of an SMS enabled Twilio Phone Number with your ngrok URL. Send a text message to that number and watch as your application responds with a contextually appropriate message.

Just the beginning

Awesome! We have now supercharged our API calls to improve our customers experience even more and all that with only a few changes. Checking for fraud and the sentiment of a message is just the beginning though. You can find more Add-ons in the Twilio Marketplace.

Interested in offering your own API in the Twilio Marketplace? Request an invite and we’ll get in touch with you.

I can’t wait to see what you build with the new Add-ons! Feel free to contact me on Twitter @dkundel or via email dkundel@twilio.com to tell me more about it.

Supercharge your Twilio API calls with Add-ons

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


We’re delighted to share the reimagined experience of developing on Twilio. A new end-to-end experience for prototyping, building and debugging Twilio apps, our aim with the new Twilio Console, Documentation and Debugger is to accelerate your speed with cutting Twilio code faster than ever before.

After watching one million developers work with the Twilio platform, we’ve learned a lot about what information is important in a developer’s journey and when it is the most critical in the craft of software. The new experience we’ve designed focuses on the moments when a developer is using Twilio for the first time, getting the app into production and troubleshooting inevitable bugs.

Get What You Need Faster With Console

In the run up to SIGNAL, we debuted Console as our sneak peek into the new developer experience from Twilio. The whole suite of Twilio products can be accessed with the new slim dock to the left of the Console.

01_Dashboard

The interface permits pinning of the products you care about for faster access.

02dashboard

And finally the experience is wrapped in a responsive design for developers – the console can sit side-by-side your text editor on a laptop screen.

03dashboard

But perhaps my favorite of the many new features introduced in the Console is the introduction of TwiML Bins. Now you can create static TwiML responses for your webhooks right inside the console without the need to stand up your own publicly available web host.
04dashboard
These webhooks can be applied to one or multiple Twilio phone numbers, dramatically accelerating your ability to get your prototype functional.

Find Your Answers Faster With New Docs

Accompanying the new Console is a redesigned Documentation experience. Starting with our Tutorials launch a few months ago, we’ve been hard at work reimaging Twilio Docs from the ground up to help you find the information you are looking for faster than ever before.

Similar to the new Console, Docs enjoys a new developer responsive design permitting the documentation you’re reading and the code you’re writing to fit side-by-side on an 11-inch Macbook with 80 columns width for your text editor.

Browsing for the right languages and products is also faster with a new filterable sidebar, winnowing the displayed documentation to fit your stack and ideas.

Finally, in-site search helps you specify exactly what you’re looking for with a code-forward implementation that gives you snippets right in the results.

Troubleshoot With Lightning Speed With The Debugger

Once you’ve got the happy path of your app up and running, finding the edges that produce errors quickly becomes critical to getting to production. To provide a speed boost on that stage of your journey, we’ve completely revamped how you find and fix your errors with a new Debugger.

At the top of the nav, you’ll see an new icon for the Debugger. No matter what Twilio product you’re using to build, the Debugger will watch for new errors. If it notices that an error has taken place, it will glow red. Clicking on the icon will give you the option to go to the Debugger or mute these notifications.

When you go to the Debugger, the first thing you’ll see a chart of all the errors that have happened in the last 24 hours. We want it to be instantly clear if there’s something wrong that requires your attention. You can easily tweak the search criteria and the chart and results will instantly reload.

In addition to grouping these debugging events by type, developers can now group errors by the webhook URI that is associated with it, giving you unprecedented insight to the problematic endpoints of your Twilio application.

Debugger2

You can then click on any of those endpoints to see all of the errors associated with just that endpoint:

Debugger1

Robust search fills out Debugger’s ability to pinpoint errors. In addition to searching by webhook URI, developers can search for errors by phone number, Call Sid, SMS Sid or any of the parameters that Twilio included in its HTTP request to your application.

We Can’t Wait To See How Fast You Can Build

With the combination of our newly reimagined Console, Docs and Debugger, developing on Twilio has never been faster. While we are stoked to share this new developer experience from Twilio with you, the journey to accelerate your build time is only just beginning. Included in each part of the experience is an easy way to submit feedback on what you see.


We want to hear what you think – submit feedback either through these channels or hit us up on Twitter at @twilio.

We can’t wait to see how fast you can build.

Introducing The New Developer Experience From Twilio

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 23, 2016

The big day is just a few hours away.

SIGNAL kicks off at 9:30 am PST / 12:30 pm EST /4:30pm GMT tomorrow, May 24th.

If you can’t make it to the big show at Pier 27, don’t worry. You can tune in to the general session live stream right here

As soon Jeffiel hits the stage tomorrow, propelled by some awesome tunes, the SIGNAL train is rolling out of the station full steam ahead.

You may have heard that the Internet in your Things will change tomorrow. We’ll reveal just how that’s going to happen and a whole lot more – product announcements, state of the union updates, and a few big ships that change the way you develop with Twilio.

Stay tuned to @twilio for moment by moment updates. Like us on Facebook to catch our Live moments. We’ll see you tomorrow!

The Big Day: Tune Into SIGNAL’s Live stream Tomorrow

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Today at SIGNAL, we launched something a little unusual. For the first time there is a Twilio product you can physically touch!

It’s called Programmable Wireless and it’s a Twilio SIM card with an unmistakable Twilio flavor. You now have access to program every call, text and data packet that interacts with your IoT or Enterprise cellular device.

In a nutshell, Programmable Wireless gives you:

  • LTE data connectivity, using the Twilio SIM card. It connects through the T-Mobile network in the US. International coverage is coming soon.
  • Voice & SMS via the existing Twilio API, so you can exchange calls and messages directly with your cellular-connected device.
  • An API to programmatically order, activate, control, and track any number of Twilio SIM cards, directly from your software.
  • A new machine-to-machine Commands API that provides a power-efficient and resilient complement to a cellular data link.
  • And a no-shenanigans pricing model optimized for large deployments of low-bandwidth devices as well high-bandwidth use-cases. Check out the pricing details here.

In the months running up to launch, IoT and enterprise communications emerged as the most popular use-cases amongst our alpha customers. And it makes sense. Here’s why.

For IoT

Despite the obvious benefits of cellular — coverage, reliability and ease-of-configuration — the vast majority of IoT devices connect over Wi-Fi or other short-range network. That’s because cellular for IoT is complex to source and manage. For many IoT use cases it’s too expensive and procuring SIM cards is unnecessarily complicated.

Just like other Twilio products, we’ve designed Programmable Wireless to make cellular accessible to developers. There is an IoT-specific pricing plan that makes cellular an economical option for low-usage devices. We are excited to see what cellular-connected IoT solutions will hit the market next.

For Enterprise Communications

As personal smartphones and tablets become our work tools, IT teams struggle to enforce business rules and create customized communication flows. Data and voice traffic that could previously be routed, logged and recorded has now moved outside the realm of the corporate network.

Programmable Wireless brings the power of cloud communications to every cellular-connected device. For these use-cases a high-usage pricing plan ensures the economics stack up.

Availability

Programmable Wireless is in developer preview now and will be broadly available later this year. You can request early access here.

We can’t wait to touch what you build!

Introducing Programmable Wireless. Build with cellular communications.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Today, Twilio announced Add-ons, letting you instantly install partner features and capabilities through the Twilio API. This announcement fits right in with Twilio’s DNA. Being the tinkerers we are, we don’t just obsess about what you build, but also “how” you build.  And with Add-ons we want to make it just as easy to build with the entire ecosystem of communications APIs as it is to build with Twilio.

If you dissect the anatomy of a communications app, it’s much more than the voice and video call or the message. It usually means stitching together a range of technologies and APIs to make something that’s unique to you. Something that fits your business, your customers, and your product. Sometimes Twilio has you covered. Sometimes you need additional specialized communications tools to work side-by-side with Twilio.

We see these creative mashups all the time:

  • You want to use sentiment analysis to automatically pinpoint calls with angry customers and bridge in a supervisor.
  • You want to detect the language of inbound messages to route them to a person who can respond quickly in native tongue.
  • You want to identify demographics of an inbound sales call so you can prioritize people with the best buying profile.
  • You want to use spam or fraud scoring on inbound calls and messages so you can drop them on the floor before they distract your staff.

 

APIs and the whole idea of app composability make all of this possible in the first place. But anyone that’s done it knows that it doesn’t come without some effort. Integrating all these disparate technologies means new authentication models, new accounts to manage and even different programming paradigms and languages that can alter your application’s architecture. And yes, it means new code. Often lots of it.

And it’s usually not the kind code we love to write. It’s not the code that takes groundbreaking ideas about business workflow and customer experience and turns them into reality. No, it’s really the equivalent of glue. Middleware. I’m not trying to hate. Middleware can have an elegance and intrigue about it, but most would rather skip it. Especially when that middleware represents common elements and logic that just repeats what others have already done.

Add-ons

This universal disdain for writing middleware is really the genesis of Add-ons. We think working with 3rd party building blocks should be just as easy as working with Twilio on its own.

Instead of requiring developers to write integrations, Add-ons are pre-integrated capabilities, by partners and Twilio, that you can enable on the Twilio API for your account. It’s done with one click of an “install” button in the Twilio Console. Here’s an example of an Add-on for TCPA compliance:
Add-ons

After that, the behavior of the Twilio API is transformed to incorporate the new capabilities. There’s no need re-architect your application or Twilio communications flows. All of a sudden the same Lookup API that was returning carrier information is now returning a fraud score for the phone number. The SMS API that was sending and receiving messages is now returning sentiment analysis on message bodies. And those are just a couple examples of what’s possible today. As the number of Add-ons grows, so do the possibilities of what you can do with the Twilio API.

Marketplace – A Catalog of Vetted Options

The experience of using Add-ons starts with a new Twilio Marketplace. This is where you browse through available Add-ons, filtered by the Twilio products you want to use Add-ons with.

marketplace

Any Add-on you select has been pre-verified by Twilio before it’s published to make sure it meets criteria of scale, security and reliability.

There are three categories of Add-ons available today and more on the way.

Number Add-ons

of you that aren’t familiar with Twilio’s Lookup product, it’s designed to give you information about a phone number. Things like carrier, number formating, and more recently, caller name. It’s great information for cleaning up your contacts and for using in the call or message flow to give you a better idea about who’s trying to reach you.

Number Add-ons supercharge the Lookup and Programmable Voice API. They do this using Twilio partners. These are partners that, in some cases, have built an entire business dedicated to maintaining specific information about a phone number.

For example White Pages Pro has an Add-on called Phone Reputation. Phone Reputation returns risk information about a phone number so you can identify fraudulent signups and deter bad behavior on inbound calls and messages. It provides a simple, actionable, real-time spam reputation level of 1-4. A level 4 phone number has a 97% likelihood of having engaged in spam or scam, giving you confidence to know when to block a number. Here’s an example of the json response that would be returned.

From: +13232633791
To: +16504567080
{. . .}
AddOns: {
  . . . 
  "results": {
"whitepages_pro_phone_reputation": {
    . . . 
       "result": {
          "results": [
            { "phone_number": "3232633791",
              "reputation": {
                "level": 1,
                "details": [
                  { "score": 2,
                    "type": "NotApplicable",
                    "category": “NotApplicable" 
                }
                ],
                "volume_score": 1,
                "report_count": 0
              }
            }
          ]
      }
 }
}

Another great example is an Add-on called Mobile Ownership from a Payfone. This returns phone number registration information so you can check if an owner has changed before sending a message. That way you stay compliant and avoid complaints from people that haven’t opted in to hearing from you.

Messaging Add-ons

Messaging Add-ons, as the name implies, add insights into the content of messages. For instance, our partner IBM offers Add-ons that use natural language processing technology and machine learning algorithms. This way you can extract semantic meta-data from content, such as information on people, places, companies, topics, and languages. Here’s an example of what their Watson Insights Add-on returns:

From: +13232633791
Body: Hi there! I'm testing out Twilio's new add-ons
To: +16504467080
{. . .}
AddOns: {
  . . . 
  "results": {
    "ibm_watson_insights": {
  . . . 
        "language": "english",
        "keywords": [
           {"text": "new add-ons”, "relevance": "0.935276",
            "sentiment": { "type": “positive", "score": “0.415215" }},
          {"text": “Twilio", "relevance": "0.728652",
            "sentiment": {"type": "positive","score": "0.415215"}}
        ],
        "entities": [
          {"type": "Company","relevance": “0.77978", "text": "Twilio",
            "sentiment": {"type": "positive","score": "0.415215"},"count": "1",           
            "disambiguated": {
              "name": “Twilio", "dbpedia": "http://dbpedia.org/resource/Twilio",
              "freebase": "http://rdf.freebase.com/ns/m.0h1bs6j"
            }
          }
        ]
      }
    }  
  }
}

There are lots other Messaging Add-ons available. Even a Food delivery Add-on from msg.ai that parses out the urgency and the topic someone is sending for food delivery services.

Recording Add-ons

Recordings Add-ons are coming soon. These allow you to get information about call recordings with services like IBM Watson & Voicebase and more are on the way. For your voice calls, you can gather everything from language identification, to sentiment analysis, to voice transcription.

Publish your own Add-on

Add-ons are all available to install and use from the new Twilio Marketplace. And the beauty of a Marketplace is that it’s open to anyone to publish an Add-on. After a short vetting process, you can offer your API to more than 1 million web and mobile developers by publishing to the Twilio Marketplace. These aren’t just any developers, these are developers who build voice, video, and messaging apps with Twilio.

We handle the billing as well. It’s a rev-share model with Twilio. You set the price and Twilio handles all payment processing through one bill, saving you and your customers the extra accounting steps.

You can start your submission and learn more here

More Intelligent Communications

Add-ons are all about making communications more intelligent, with sentiment analysis, speech transcriptions, demographic insights and more. They let you to do more with less code.

Look through the Marketplace and see what Add-ons will be most useful for you.

We can’t wait to see what (and how) you build.

Introducing Twilio Add-ons: Do more with less code

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 20, 2016

Today we’re celebrating a new milestone together.  There are now 1 million of your fellow developers building with Twilio. Whether you’ve been here 7 years or 7 minutes, you make up this million. Thank you for being a part of this.

Your growth as developers is inextricably tied to Twilio’s growth. Watching you build ambitiously leads us to create tools that serve that ambition. You’re out there conquering development’s Koopa Troopas. We aim to offer you a suite of tools you need to make that work easier — a programmatic super mushroom, cape feather, or fire flower.

Back in 2012, when Twilio hit 100,000 developers on the platform, we invited the community to share their milestones. The funny thing about placing milestones is that you can see how far you’ve travelled since placing the last one. We caught up with a few developers who have come a long way since sharing their  2012 milestones.

  • Kevin Mann (CallRail)
  • Hassan S. Ali (The Onion)

Hassan S. Ali’s Milestone

Kevin Mann’s Milestone

If you a milestone related to your journey as a developer that you’d like to share? Record a 60 second video sharing your story, post it on YouTube and share it on Twitter using the hashtag #TwilioMilestone. We’ll be compiling all your milestones and sharing them in another post in June.

We can’t wait to hear more of your stories. And we can’t wait to see what you build with us next.

1 Million Developers: Celebrating Your Milestones

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Even in a place like the Marvel universe communication is key in resolving conflicts and team performance. Get Tony Stark, Steve Rogers and the other Avengers in a conference call and who knows, the whole Civil War thing might have been avoided.

With conference events, we can build a dashboard how Iron Man would have probably built it for the Avengers to monitor their conference calls.

No worries there will be no spoilers! ;)

Mission Briefing

There is no successful mission without a proper briefing. For this mission we will be using the following tools:

Additionally our dashboard will be using AngularJS. While this project doesn’t require any substantial AngularJS knowledge you can brush up your AngularJS skills in this article: Build a Video Chat using AngularJS

Alright we should be properly prepared to start coding. Ready? Let’s go!

Systems Setup

Our core mission is to add a dashboard to an existing conference call phone number. Start by cloning this project:

git clone -b template git@github.com:dkundel/twilio-conference-dashboard.git
cd twilio-conference-dashboard
npm install

This will install all necessary dependencies for us and provide us with a basic server to work on.

Copy the .env.example in the main directory to a new file called .env and add the credentials of your Twilio account from the Console.

Now we are ready to run the server. For this, we can either type node index.js from the main directory of the project or use the npm run dev script. The latter uses nodemon to make sure that the server is reloaded every time we do a code change.

You can verify if everything works by opening http://localhost:3000 in your browser. You should see a screen that looks like this:

Establishing Communications

Now that we have our application running we need to connect a Twilio phone number to it so we can dial into the conference. For this we first need to expose our application to the internet via a public URL. This is where ngrok comes into play.

Run ngrok http 3000 in a separate terminal and keep it running. You will get an ngrok URL that we will use with our Twilio phone number.

Navigate to http://<your_ngrok_url>.ngrok.io/voice and make sure that the TwiML returned looks like this:

<Response>
    <Say>Welcome to the conference!</Say>
    <Dial>
        <Conference waitUrl="http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient">myConference</Conference>
    </Dial>
</Response>

This TwiML instructs Twilio to first respond to every call with a voice saying “Welcome to the conference!” using the <Say> verb. Afterwards, it uses the <Dial> to direct the call into a <Conference>. The waitUrl attribute specifies which webhook Twilio should contact for instructions what to do while the call is waiting for the conference to start. In our case, we use a Twimlet that plays a song for us.

In the Console locate one of your existing phone numbers or buy a new number and add the ngrok URL as the Webhook value:

Call the phone number and you should be able to hear “Welcome to the conference” followed by some music. That’s awesome, however, we are not done yet.

Receiving Status Updates from HQ

We want to receive updates whenever the status of the conference changes. For this we need to add two new attributes statusCallback and statusCallbackEvent to the <Conference> element.

Open voice.js in the lib folder and add the two new properties to the conference TwiML:

//...
node.conference('myConference', {
  waitUrl: 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient',
  statusCallback: '/status',
  statusCallbackEvent: 'start end join leave mute'
});
//...

We’re telling Twilio that when the start, end, join, leave and mute conference events happen, we want it to make an HTTP request to the /status route of our application.

Reload http://<your_ngrok_url>.ngrok.io/voice and you should be able to see the updated XML.

<Response>
    <Say>Welcome to the conference!</Say>
    <Dial>
        <Conference waitUrl="http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient" statusCallback="/status" statusCallbackEvent="start end join leave mute">myConference</Conference>
    </Dial>
</Response>

Now lets create that new /status route back in our Node application. Create a new file named status.js in the lib folder. Export a new request handler that for now just logs the request body:

'use strict';

function statusRouteHandler (req, res, next) {
  console.log('Status Update:');
  console.dir(req.body);
  res.send('Ahoy!');
}
module.exports = statusRouteHandler;

Next add the /status route to index.js:

// configuring middleware
// ...

// configure routes
app.post('/mute', require('./lib/mute'));
app.all('/voice', require('./lib/voice'));
app.post('/status', require('./lib/status'));

// start server
// ...

That’s it! Give your number another ring and you should be able to see events being logged in the console. Make sure to wait until the music starts before you hang up in order to properly join the conference. The events you should see pop up in the console are participant-join, participant-leave and conference-end. There is no conference-start event since the conference will only start once at least two participants are in.

Gathering Caller Intel

If we have a close look at the data we receive in the statusCallback request, we get data about the conference like the callback event, conference friendly name, and the conference SID. We’ll store those in a variable named data and for use in our dashboard. One thing we don’t get is much about the actual caller, like their phone number. To get that we can use the Twilio Node.js helper library and the CallSid to look up the Call resource.

'use strict';

const twilio = require('twilio');
const client = twilio();

function statusRouteHandler (req, res, next) {
  const eventName = req.body.StatusCallbackEvent;
  const callSid = req.body.CallSid;
  let data = {
    name: req.body.FriendlyName,
    conference: req.body.ConferenceSid
  };
  
  if (eventName.indexOf('participant-') !== 0) {
    res.status(200).send();
    return;
  }
  
  client.calls(callSid).get((err, call) => {
    if (err) {
      console.error('An error occurred!');
      console.dir(err);
      res.status(500).send('error!');
      return;
    }
    
    console.dir(call);
    res.status(200).send();
    return;
  });
}

module.exports = statusRouteHandler;

Dial the number again and you now have the phone number of the caller which you can use to locate even more information from a source like a local database. Say for example we wanted to find out which superhero was calling into the conference. You could use the handy database of superhero phone numbers that you keep, or you could just use the one I’ve included in the project.

Use it by calling PeopleService.get(callSid).then() to retrieve a profile:

'use strict';

const twilio = require('twilio');
const client = twilio();
const PeopleService = require('./superheroService');

function statusRouteHandler (req, res, next) {
  // ... excluded for readability ...
  client.calls(callSid).get((err, call) => {
    if (err) {
      console.error('An error occurred!');
      console.dir(err);
      res.status(500).send('error!');
      return;
    }
    data.number = call.fromFormatted;
    data.muted = req.body.Muted === 'true';
    data.sid = callSid;
    PeopleService.get(callSid).then((profile) => {
      data.profile = profile;
      console.log('User info:');
      console.dir(data);
      res.status(200).send();
    });
  });
}

module.exports = statusRouteHandler;

Connection Established. Waiting for data…

Now that we have all the caller data collected we need to send it to our dashboard whenever there is a new conference event. To do this we will use a WebSocket wrapper called Socket.IO.

Require the Socket.IO module in our index.js and pass it an HTTP server instance. We are returned an io instance that allows us to send messages and listen for events. Because we want to send those messages to the dashboard when Twilio requests the /status route, we’ll pass the instance of Socket.IO into that route handler.

// configuring middleware
// ...
const io = require('socket.io')(server);

// configure routes
app.post('/mute', require('./lib/mute'));
app.all('/voice', require('./lib/voice'));
app.post('/status', require('./lib/status')(io));

io.on('connection', (socket) => {
  console.log('a user connected');
 
  socket.on('disconnect', () => {
    console.log('user disconnected');
  });
});

// start server
// ...

Change the function export to accept the instance of Socket.IO and then use that instance to pass our dashboard client the conference event data. Additionally change the route handler to return the caller data via a Socket.IO message instead of an HTTP response by using the emit method:

'use strict';

const twilio = require('twilio');
const client = twilio();
const PeopleService = require('./superheroService');

let io;

function statusRouteHandler(req, res, next) {
  const eventName = req.body.StatusCallbackEvent;
  const callSid = req.body.CallSid;
  const accountSid = req.body.AccountSid;
  let data = {
    name: req.body.FriendlyName,
    conference: req.body.ConferenceSid
  };
  
  if (eventName.indexOf('participant-') !== 0) {
    io.emit(eventName, data);
    res.status(200).send();
    return;
  }
  
  client.calls(callSid).get((err, call) => {
    if (err) {
      console.error('An error occurred!');
      console.dir(err);
      res.status(500).send('error!');
      return;
    }
    data.number = call.fromFormatted;
    data.muted = req.body.Muted === 'true';
    data.sid = callSid;
    PeopleService.get(callSid).then((profile) => {
      data.profile = profile;
      console.log('User info:');
      console.dir(data);
      
      io.emit(eventName, data);
      res.status(200).send('');
    });
  });
}

module.exports = function (ioInstance) {
  io = ioInstance;
  return statusRouteHandler;
}

The last thing we need to do is to listen for the respective events in our dashboard. For this, we need to open the conference.service.js file in the public folder. I already made sure to include the Socket.IO client library in the index.html and added it to Angular’s dependency injection. So we are ready to use it and populate the initialize function of the service.

Since we need to perform some basic actions for every event we will maintain an array of all events we are listening on and loop over them. The events we are interested in are:

var events = [ 
  'conference-start',
  'conference-end',
  'participant-join',
  'participant-leave',
  'participant-mute',
  'participant-unmute'
]

For each of the events, we create a new eventData object that contains the event name, the data it sent as well as a readable message that we generate with getEventMessage(event, data). Additionally, we maintain an object containing all participants. This object has to be updated depending on the message.

Once we have all necessary data we broadcast it in order to inform components such as our controller that there has been an update. For this we use the $rootScope.$broadcast

function of AngularJS.

Stitching all of this code together we end up with the following code in our public/conference.service.js:

(function () {
  // ... excluded for readability ...
  function ConferenceService($http, io, $rootScope) {
    var participants = {};
    var socket = io();
    
    var events = [ 
      'conference-start',
      'conference-end',
      'participant-join',
      'participant-leave',
      'participant-mute',
      'participant-unmute'
    ];

    initialize();

    function initialize() {
      events.forEach(function (event) {
        socket.on(event, function (data) {
          var eventData = {
            event: event,
            data: data,
            message: getEventMessage(event, data)
          };
          
          if ('participant-join') {
            data.joined = Date.now();
          }
          
          if (event === 'participant-leave') {
            delete participants[data.sid];
          } else if (event.indexOf('participant-') === 0) {
            participants[data.sid] = data;
          }
          
          $rootScope.$broadcast('conferenceStatus.update', eventData);
        });
      });
    }
    // ... excluded for readability ...
  }
})();

That’s it. The connection is established and the data is being piped through. If you navigate to in your browser to http://localhost:3000/ and start calling into the conference with a couple of phones you should be able to see your dashboard being populated with the team and the respective log messages!

Comms and dashboard up and running. Time to save the world!

We did it! We have not only a way to easily get everyone in the same conference call but a way to monitor status changes in the conference. Building a dashboard using these events is just the beginning and I’m curious to hear what you build with it! Talk to me on Twitter @dkundel, via email at SIGNAL.

If you didn’t register yet for SIGNAL, there is still time! Iron Man didn’t RSVP yet but there will be certainly enough bots and you shouldn’t miss $bash. Use DKUNDEL20 to get a 20% discount when registering. I’m looking forward to seeing you there!

Conference Monitoring à la Iron Man

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Arduino is an amazing platform for building interactive hardware projects. In the next ten minutes we’ll get our first program running on the SeeedStudio LinkIt ONE development board.

Hackpacks are back!

If you’re coming to SIGNAL (you are coming to SIGNAL right? – use promo code BSCHOOLEY20 for 20% off your ticket) you’ll be receiving a LinkIt ONE in the Hackpack we’re giving to every attendee. Stop by the Hackpack station and we’ll help you get it up and running.

What is the LinkIT ONE?

The LinkIt ONE is a development board that is made by the collaboration of SeeedStudio and MediaTek. It features an ARM7 EJ-S™ processor on a board that is pin-out compatible with Arduino. Onboard you’ll find support for:

  • GSM/GPRS radio for cellular connectivity
  • Wi-Fi radio
  • GPS radio
  • Bluetooth radio 2.1 / 4.0
  • AAC/MP3 support with built-in codecs
  • SD card slot

It comes with all of the antennae you need for the radios in the device. Here’s what they look like:

Once assembled the completed package looks like this:

We won’t be using the Wi-Fi, cellular or GPS in this tutorial but with this setup you’ll be ready to go for any hacking you do involving these capabilities.

Now that we have the hardware sorted out, let’s install the software we need to build an app.

Getting Ready for Development

Here’s everything we need to install to program the LinkIt ONE:

  • Arduino IDE
  • Mediatek USB COM port driver for LinkIt ONE
  • Mediatek LinkIt ONE SDK

Let’s start by installing the Arduino IDE. You can find the latest version here. The current version at the time this blog post is being written is 1.6.9. On Windows you can choose the installer if you have admin access to the machine or the zip file if you do not. If you need help installing the Arduino IDE, you can find guides for your OS of choice here:

To communicate with the LinkIt ONE over USB we need to install a USB COM port driver. Download and install the USB COM port driver for your OS from the links below:

MediaTek says to reboot at this point (and several other points) but I’ve found it unnecessary during my installation. Your mileage may vary.

The last step in our installation phase is installing the MediaTek LinkIt ONE SDK. This step is done entirely in the Arduino IDE so open that now.

In the IDE, open the Preferences dialog. On Windows this is in the File menu. On the Mac it is under the Arduino menu item. The dialogs in Arduino IDE look almost identical between Windows and Mac so I’ll just show the Mac version in the following screenshots.

Set the Additional Boards Manager URLs field to http://download.labs.mediatek.com/package_mtk_linkit_index.json and then click OK:

Under the Tools menu choose Board->Boards Manager…:

When the dialog opens it will download the latest list of compatible boards and one of them will be the LinkIt ONE. Search for “link” in the search box at the top, click the row for LinkIt ONE and press the Install button:

Next, let’s update the firmware on the LinkIt ONE board. Set the LinkIt ONE board into Mass Storage/Firmware Update mode by setting the outer switch to the up position. Here’s what that should look like:

Once you have that switch set correctly, plug the LinkIt ONE into your computer using a micro USB cable.

In the Arduino IDE select Tools->Board->LinkIt ONE:

Next, select Tools->Programmer->LinkIt Firmware Updater:

Select Tools->Burn Bootloader to launch the LinkIt ONE Flash Tool:

Click the download button in the Flash Tool:

When the following screen appears, unplug your USB cable and replug it in again and the upgrade will begin automatically:

When it’s done, flip the outer switch back to the down position for normal operation mode. That’s all for configuration. Let’s write our first Arduino program for the LinkIt ONE.

Make the LED Blink

In the Arduino world there’s a canonical ‘Hello World’ that is the simplest program you can write to show physical output. The program is called Blink and running it on an Arduino board makes the onboard LED connected to digital pin 13 blink on and off. On the LinkIt ONE you can find that LED here:

Arduino programs, referred to as Sketches with a .ino file extension, are written using two functions: setup() and loop(). The setup function is used to, as you probably guessed, set up anything that needs to be configured before the main program runs. This is where you’d configure your input and output pins, set up network connectivity, initialize values, etc. The loop function is the main program and it repeats indefinitely.

Our setup function will set pin 13 as an output pin. We can write the value HIGH to that pin to turn the LED on and LOW to turn it off. Create a new Sketch if you haven’t already and replace the setup function with the following code:

void setup() {
  // Set pin 13 to be an output pin
  pinMode(13, OUTPUT);
}

The loop function for our Sketch will use the digitalWrite function to toggle pin 13 from HIGH to LOW with a one second delay between each. The effect is that the LED will turn on for one second and turn off for a second and repeat until the device is powered off. Replace the loop function in your Sketch with this code:

void loop() {
  // Turn the LED on
  digitalWrite(13, HIGH);

  // Wait 1 second
  delay(1000);

  // Turn the LED off
  digitalWrite(13, LOW);

  // Wait 1 second
  delay(1000);
}

We’re ready to upload our Sketch to the LinkIt One. Under the Tools menu select Port and then choose one of the ports that ends with “(LinkIt ONE)”:

Click the Upload button to compile and load your Sketch onto the LinkIt ONE. If everything is configured correctly the Sketch will start running on the board and you should see the LED blink off and on.

Congratulations on writing your first program on the LinkIt ONE!

What’s Next?

Now that you have your LinkIt ONE board up and running, feel free to use your imagination on what to build next. Here’s some things you might consider doing next:

  • Use the GPS and cellular functionality to make a car tracker
  • Get some Grove sensors (like the accelerometer, touch sensor, temperature sensor, etc.) and program something cool with them. There’s a starter kit on Amazon that has a bunch of sensors to try out.

I’m really excited to see what you build with this device. If you’re coming to SIGNAL you’ll be receiving one of these devices. Come say hi at the Hackpack station and let’s talk about what you might build with it. If you have any questions or comments you can find me on Twitter @brentschooley or email me at brent@twilio.com.

Getting Started with Arduino on the LinkIt ONE

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 19, 2016

We talk a lot about how to send SMS Messages from web applications, but how to send an SMS from Android? There are a couple of extra considerations for that. Still, we’ll be have it shipped in 15 minutes. Let’s go!

The Problem

While Twilio is a REST API and theoretically you could make an HTTP request to it directly, you would need to store your Twilio credentials inside your app which poses a serious security issue. An attacker could decompile the application, extract your credentials and use your Twilio account for anything they liked.

To avoid this we will create a backend application that implements the Twilio REST API, wraps up your credentials and sends SMS messages for you. Then you can call your backend application from your Android application and send SMS messages without distributing your credentials.

Our tools

For our app to be able to send a text message using the Twilio REST API we will need the following:

If you just want to skip to coding your mobile app, feel free clone this repository with the backend, or just deploy it to Heroku.

You will also find the entire Android application in this repository.

Creating our backend

Because I’ll be using Java to create this backend, I’m gonna start by opening IntelliJ IDEA and creating a new Java project there. We wrote a Getting Started with Gradle and the Spark Framework tutorial in the past in case you need help setting things up.

Now that our project is created, open build.gradle and add the following plugins and dependencies to it.

group 'uk.co.placona'
version '1.0-SNAPSHOT'

buildscript {
    repositories { jcenter() }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3'
    }
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'

sourceCompatibility = 1.8
mainClassName = 'SMSBackend'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    compile 'com.sparkjava:spark-core:2.5'
    compile 'com.twilio.sdk:twilio-java-sdk:5.10.0'
    compile 'org.slf4j:slf4j-simple:1.6.1'
}

Create a new class in SMSMobileBackend/src/main/java called SMSBackend

 and add a Main method to it.
import static spark.Spark.*;

public class SMSBackend {
   public static void main(String[] args) {
       get("/", (req, res) -> "Hello, World!");
   }
}

Run the application by opening the Gradle tab, double-clicking shadowJar and running the generated jar file in SMSMobileBackend/build/libs.

When you load up http://127.0.0.1:4567 on your browser you should see a hello world message.

Let’s make sure this application is also available externally with the help of ngrok so our mobile app can get access to it. In your terminal run:

ngrok http 4567


Now that you know your setup is correct and copied the URL ngrok generated for you, go back to the SMSBackend class and create a new endpoint to handle sending SMS messages. Our android application will then be able send requests to it. Your class should end up like this:

import com.twilio.sdk.TwilioRestClient;
import com.twilio.sdk.resource.instance.Sms;

import java.util.HashMap;
import java.util.Map;

import static spark.Spark.*;

public class SMSBackend {
   public static void main(String[] args) {
       get("/", (req, res) -> "Hello, World");

       TwilioRestClient client = new TwilioRestClient("YOUR_TWILIO_ACCOUNT_SID", "YOUR_TWILIO_AUTH_TOKEN");

       post("/sms", (req, res) -> {
           String body = req.queryParams("Body");
           String to = req.queryParams("To");
           String from = "YOUR_TWILIO_PHONE_NUMBER";

           Map<String, String> callParams = new HashMap<>();
           callParams.put("To", to);
           callParams.put("From", from);
           callParams.put("Body", body);
           Sms message = client.getAccount().getSmsFactory().create(callParams);

           return message.getSid();
       });
   }
}

Just make sure you replace the Account Sid, Auth Token, and Twilio phone number with the ones you can get from the dashboard. Restart the application and we should be all set with this.

Creating our App

Now that we have our backend running head to Android Studio or your favourite Android IDE and create a new project called Twilio SMS.

When the project is finished loading, open the app’s build.gradle and add the dependency OkHttp to it. OkHttp is an open source project by Square that makes it really easy for us to make an HTTP request to our Java backend.

dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   testCompile 'junit:junit:4.12'
   compile 'com.android.support:appcompat-v7:23.3.0'
   compile 'com.squareup.okhttp3:okhttp:3.2.0'
}

When you save the file, your IDE will ask you to sync the dependencies of the project. Go ahead and let it do its thing. Once it completes, you will have the dependency downloaded.

Open AndroidManifest.xml and add the Internet permission to your app. We will need that to make HTTP requests to our backend app.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="uk.co.placona.twiliosms">

   <uses-permission android:name="android.permission.INTERNET"/>

Let’s create our layout by opening res/layout/activity_main.xml and add two text fields for telephone and message, and a button to send it.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="uk.co.placona.twiliosms.MainActivity">

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Phone Number"
       android:id="@ id/textView"
       android:layout_alignParentTop="true"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true" />

   <EditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@ id/txtNumber"
       android:hint=" 44 12345 67890"
       android:layout_below="@ id/textView"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:layout_alignParentRight="true"
       android:layout_alignParentEnd="true" />

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Message"
       android:id="@ id/textView2"
       android:layout_below="@ id/txtNumber"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true" />

   <EditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:inputType="textMultiLine"
       android:ems="10"
       android:id="@ id/txtMessage"
       android:layout_below="@ id/textView2"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:layout_alignRight="@ id/txtNumber"
       android:layout_alignEnd="@ id/txtNumber" />

   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Send"
       android:id="@ id/btnSend"
       android:layout_centerVertical="true"
       android:layout_alignRight="@ id/txtMessage"
       android:layout_alignEnd="@ id/txtMessage" />
  
</RelativeLayout>

If you run the application now, you will see that your app looks like this:

If you enter a message and hit Send however, you will notice that nothing happens. That’s because we’re still not making a request to our backend. Let’s do this now.

Open MainActivity.java

 and add the following member variables and imports to the top of the class:
package uk.co.placona.twiliosms;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

private EditText mTo;
private EditText mBody;
private Button mSend;
private OkHttpClient mClient = new OkHttpClient();
private Context mContext;

In the body of the onCreate method, initialise the widgets so we get references to our UI.

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   mTo = (EditText) findViewById(R.id.txtNumber);
   mBody = (EditText) findViewById(R.id.txtMessage);
   mSend = (Button) findViewById(R.id.btnSend);
   mContext = getApplicationContext();
}

Now create a new method in this class called post

. This method will return the response from the HTTP request we will make to our backend application.
Call post(String url, Callback callback) throws IOException{
    RequestBody formBody = new FormBody.Builder()
            .add("To", mTo.getText().toString())
            .add("Body", mBody.getText().toString())
            .build();
    Request request = new Request.Builder()
            .url(url)
            .post(formBody)
            .build();

Call response = mClient.newCall(request);
response.enqueue(callback);
return response;
}

The code above will take a URL and a callback as arguments, and will build a new multipart form body for us, which we will then pass along to a new asynchronous request.

The last thing we need to do now is hook this up to our button, so when we press it, the post method gets called and the SMS message is sent.

Back on the onCreate method, paste the following code just under the send

 variable.
mSend.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        try {
            post(mContext.getString("YOUR_NGROK_URL/sms"), new  Callback(){

                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mTo.setText("");
                            mBody.setText("");
                            Toast.makeText(getApplicationContext(),"SMS Sent!",Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});

 

We use the onClick listener method on the button to to know when to make a request to our post method.

Run the application again, and when the Send button is clicked we pass on the URL we want to post our data to, and upon getting a callback we either show an error message, or display a Toast on the screen saying the SMS message was sent.

Your app is now safe

There’s a warm feeling about knowing that we were able to squash at least one vulnerability from our app by just following a few simple steps. It is also great to now have a backend we can use with other other platforms as we can just perform direct HTTP requests to it.

Using a pattern like this, we could also add phone number lookups to an application or generate phone calls. If you want to use IP Messaging, Video or Client, you’ll want a server to generate access tokens for those services too. Get your backend right and you’re ready to do anything with Twilio in your application.

I would love to know more about the apps you’re building. Hit me up on Twitter @marcos_placona or by email on marcos@twilio.com to tell me more about them.

How to Send an SMS from Android

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 18, 2016

Today, we are announcing Public Beta for Conference Events. You will be able to subscribe to changes in participant and conference states and be notified accordingly. You will not have to poll the API’s anymore to maintain the state of each participants. This drastically reduces the complexity of your application. Conference Events will be available for free. We’ve also made Call Progress Events available for free to bolster this capability.

Webhooks for Key Events

You can enable Call Progress Events by using the new

StatusCallbackEvent
TwiML parameter, now available for the
Conference
; noun within the
Dial
verb. This complements the
StatusCallbackEvents
already available on
Number
,
Client
, and
SIP
. The
StatusCallbackEvent
parameter will trigger a webhook on specific state changes of the conference or participants resources.
So far, you could only receive an event when a conference ended, if you had specified that the conferences was to be recorded. Now you can subscribe to all the following events.

  • conference-start
    The conference has started and audio is being mixed between all participants. This occurs when there is at least one participant in the conference and a particpant with
    startConferenceOnEnter="true"
    joins.
  •  

  • conference-end
    The last participant has left the conference or a particpant with
    endConferenceOnExit="true"
    leaves the conference.
  •  

  • participant-join
    Notifies when a participant joins.
  •  

  • participant-leave
    Notifies when a participant leaves.
  •  

  • participant-mute
    Notifies when a participant have been muted. This can be done through an API call to the participant resource.
  •  

  • participant-unmute
    Notifies when a participant have been un-muted. This can be done through an API call to the participant resource.

 
 
For example, if you want to request a webhook on all the possible conference state changes, you can do so with TwiML.



TeamMeeting

In this case

StartConferenceOnEnter
was set to the default value of true so the conference starts whenever the second participant joins.
ConferenceEvents
 

Modify the status of a participant

In addition to eliminating the need to poll resources to check status change, you will no longer need to discover and maintain Conference and Calls SIDs. They will be returned back in the same webhook, so you can use that info to modify the participant resource.

Expanding our example diagramed above, you can mute all the participants except the presenter, Mary, whenever everybody have joined and the Team Meeting is ready to start. As some participants might never join, you can avoid keeping the others waiting too long by setting a timer after the conference starts.

This is an example of webhook you would get when the participant Alice joins the call.

AccountSid    AC25e16e9a716a4a1786a7c83f58e30482
CallSid    CA8a0727575027a5c4d9614e633c929546
ConferenceSid    CF47001dbd9067b3007c1fcd05f43183f8
EndConferenceOnExit    false
FriendlyName    TeamMeeting
Muted    false
StartConferenceOnEnter    true
StatusCallbackEvent    participant-join

 
You can store Alice’s call SID and update any associated UIs.
Alice1
 
Let’s say we got a call SID for participants Alice (xxx), Bob (yyy) and Charles (zzz) before the timer expired. You can now POST your API request to mute them and start Mary’s presentation.
 
Alice2
 

$ curl -XPOST https://api.twilio.com/2010-04-01/Accounts/AC5ef8732a3c49700934481addd5ce1659/Conferences/CFbbe4632a3c49700934481addd5ce1659/Participants/CA386025c9bf5d6052a1d1ea42b4d16662.json \
    -d "Muted=True" \
    -u 'AC5ef8732a3c49700934481addd5ce1659:{AuthToken}'

 
This is just a simple use case but the possibilities are endless. You can control any call leg and take actions in response to a given change in participant status.
We think Conference Events will help you build Collaboration and Call Center application faster and more efficiently. Learn more about Call Progress Events in our TwiML docs for . We can’t wait to see what you build.

Introducing Conference Events

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 17, 2016

You don’t need to spend hours analyzing call recordings to figure out who said what. Those days are over. Today, we are excited to announce Dual-Channel Recording. With a simple TwiML command, you can get a recording of your call with two distinct channels, one per party. Now you can find out who said what, with one line of code.

Learn more about Dual-Channel Recording right here

The Conversations with Your Customers Are an Invaluable Mine of Information

It’s easy to sense the level of customers frustration or delight from what they say verbally. For example, voice conversations with your customers can provide subtle sentiment nuances about your products. Or repeated requests and inquiries can signal emerging trends and their most pressing needs. Gauging the same subtlety from their online transactions is much more difficult as the human connection is missing. Yet, in the average call center, less than 10% of recorded calls are retrieved or analyzed.

Businesses miss out on valuable data because mining call recordings for data can be expensive and time consuming — if you don’t have the right tools. Context is key when it comes to analyzing calls. Without the knowledge of who said what, typical programmatic call analysis isn’t worth much. Companies commonly listen back to conversations and manually analyze the customer’s feedback and sentiment. That plan can quickly become unfeasible when you scale. When your call volume grows, you need an easier way to pick out the two parties on a call.

You won’t have to sit down and manually parse the customer’s voice from the agent’s anymore. Using Dual-Channel recording, transcription and keyword analysis is simple with each party’s audio separated into its own track. You can now extract the data you need programmatically, using one TwiML command.

Here are a few ways you can use Dual-Channel Recordings to save yourself time, and add value to your business.

  • Product Manager – Build Dashboards to surface commonly recurring product requests, and customer complaints.
  • Online Directory Owner – Analyze what listing professionals said about your pricing to their customers. This will help you forecast the volume you can deliver.
  • Call Center Manager – Add transcriptions of past calls to your agents’ interface. This will give them context they can use to avoid asking the customer questions they’ve already been asked.

The Power of Call Recording

CallRevu, for example, uses call recordings to train car dealership sales reps and monitor their performance in real time.

“Our business is all about helping our dealerships understand their engagement with their customers. With dual-channel recording we will be able to efficiently extract insights from their call recordings and give tailored guidance to dealership reps to optimize sales opportunities.” – Mike Markette, Partner and COO of CallRevu

CalRevu aggregates thousands of calls quarterly in the automotive sector and extracts keywords and trends from such massive volume of info. CallRevu’s customers convert their leads faster using this data.

Voice conversations are chock full of insights you can use to deliver a better customer experience. We’re excited that you can now grab those insights, and make the most of them easily with Dual-Channel recording. Apply here.

Introducing Dual Channel Recording

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Logo-BusinessLeaseIn this case study we see the successful partnership between corporate learning and text to speech. Business Lease uses audio support from ReadSpeaker in its Learning and Development program. Geert van de Wouw, Knowledge Development Consultant at Business Lease, discusses their experience with the services from ReadSpeaker.

ReadSpeaker:  What role does eLearning play in the Learning & Development program of Business Lease?

Geert van de Wouw: At Business Lease is Care our number one priority for our customers and drivers. We strive to make things as easy and convenient as possible. Our employees are most important in making this happen. They are the difference between a lease company and Business Lease. To cultivate this atmosphere, every new employee will take a plunge in a “warm Care bath,” as we say. This method is a combination of traditional presentations given by the managerial staff, and eLlearning modules to expand employee knowledge. Those people who have been employed long-term at Business Lease will walk through this eLearning program to refresh and increase their knowledge.

RS: Since 2014 you have been using text-to-speech technology from ReadSpeaker to benefit the learning program of Business Lease. What was the main reason to start using this technology?

GW: We find Care important not only for our customers and drivers, but also for our employees. Due to our international presence with English as the language of communication, we offer the possibility to use text-to-speech technology in our eLearning environment. Analysis showed that 48% of those using ReadSpeaker didn’t turn it off throughout the eLearning process. Because of the success of our introduction program in all countries, we created more modules. Nevertheless, a good introduction program can only succeed when the content is right. The moment you present out-dated or incorrect content, you lose credibility. From this perspective and the constantly changing market in which we are moving, it was in our best interest to update content on a regular basis. Updates are easy to apply when it comes to text in our eLearning modules, but audio turned out to be a lot more difficult. A native speaker being absent/present poses a risk of being able to effectively update the modules. This is a separate matter from the risk when a native speaker is not present from some reason or other. Therefore, we came into contact with ReadSpeaker to consider replacing speakers with text to speech. It allows us to generate the audio every given time of day, to be able to run updates faster and to create new modules.

RS: Do you find ReadSpeaker to be user-friendly to generate audio in you eLearning environment?

GW: ReadSpeaker is easy to use and very user-friendly, though of course there’s always room for improvement. Text to speech, even considering the quick development, is not yet at the same level as a native speaker. Nonetheless, there are so many possibilities to try to replicate natural speech. To make it more appealing for our employees, we added more additional breaks between sentences. By varying the length of these breaks, you can make the text to speech sound more realistic. At the moment we are doing this manually, but we call it ‘Care’ to add this for our colleagues, so we’re happy to do this.

RS: From your internal investigation, it turned out that half of the customers use audio. Do you have the feeling that audio is an addition to the learning environment and leads to more positive results?

GW: We work with different cultures, different language levels and different positions in our company, all using the same eLearning modules. A casual link between better learning results and audio support is unfortunately not possible to make at this point. However, we have received feedback that adding audio creates more perception to our modules. Besides that, our employees pointed out that it helps to go through the content structurally and not too quickly.

RS: Would you recommend Text to Speech technology to other corporate learning parties?

GW: It depends on each situation. If you are not dependent on a budget, time is not an important factor and you don’t have a lot of modules, then a native speaker is your best choice. However, we live in a world in which you have to make choices. Our choice wasn’t tough to make. We want to be able to develop quickly and provide updates on a short term notice. If you’re in a situation similar like ours, I can definitely recommend ReadSpeaker’s text to speech.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 16, 2016

Seattle startup KITT.AI, developers of hotword detection, semantic parsing, natural language understanding, and conversational engine technologies, last week launched a software development kit called Snowboy to help developers add voice activation to almost any mobile device for free. Snowboy uses verbal “hotword detection,” the same technology that Amazon and Apple use for products like Alexa and Siri […]

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 13, 2016

Bots can be a super useful bridge between Slack channels and external applications. Let’s code a simple Slack bot as a Python application that combines the Slack API with the Twilio SMS API so a user can send and receive Slack messages via SMS.

Tools We Need

Our bot, which we’ll call “twiliobot”, requires Python, Slack and Twilio APIs and libraries. To write and run our Python code we need:

Here’s a handy step-by-step guide to setting up Python, pip, virtualenv and Flask.

The Slack dependencies are:

Our Twilio requirements include:

Make sure Python version 2 or 3 is installed now. We will configure everything else throughout the remainder of this tutorial.
You can follow along by writing the code in this post or skip ahead to the finished project by cloning the companion GitHub repository.

Setting Our Environment

Now that we know what tools we need to use, go to the terminal (or Command Prompt on Windows) and change into a directory where you want to store this project. Within that directory, create a new virtualenv to isolate our application dependencies from other Python projects you’re working on.

virtualenv twiliobot

Activate the virtualenv:

source twiliobot/bin/activate

Depending on how your virtualenv and shell are set up, your prompt should look like this.

twiliobot-activate.png

We’ll use the official slackclient API helper library built by Slack to access their API to send and receive messages from a Slack channel. Install the slackclient and Twilio helper libraries along with Flask into your virtualenv with the pip command:

pip install slackclient twilio flask

We next need to obtain an access token for our Slack team and our Twilio API credentials.

Slack Web API

Slack provides programmatic access to their chat application through a web API. Open up the landing page for the Slack Web API and sign up to create a Slack team or sign into your existing account.  You can create a new team for free if you don’t have admin privileges on an existing team.
slack-api-sign-in.png

After you have signed in scroll down on the web API page to where you see a button to generate test tokens.
generate-test-tokens.png

Generate a test token for a Slack team on which you have administrative privileges.

We need that test token so our Python code is authorized to call the Slack API. A common practice for Python developers is to export secret tokens like our Slack token as environment variables. Export the token with the name SLACK_TOKEN:

export SLACK_TOKEN='your slack token pasted here'

Switch into our Python environment set up so we can try out the API. With your virtualenv still active, fire up the Python REPL with the python command:

(twiliobot)$ python
Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

Let’s ensure our API token is working with a test – type the following code at the REPL prompt.

import os
from slackclient import SlackClient
slack_client = SlackClient(os.environ.get('SLACK_TOKEN', None))
slack_client.api_call("api.test")

The REPL should return back something like the following dictionary if your API test with the token was successful:

{u'args': {u'token': u'xoxp-361113305843-7621238052-8691112296227-d0d4824abe'}, u'ok': True}

If you get back {u'ok': False, u'error': u'invalid_auth'} then double check that you copied the Slack token correctly into the second line entered on the REPL.

Enter one more quick test for our authentication with another line of code in the REPL:

slack_client.api_call("auth.test")

You should see another dictionary like this one:

{u'user_id': u'U0S77S29J', u'url': u'https://fullstackguides.slack.com/', u'team_id': u'T0S8V1ZQA', u'user': u'matt', u'team': u'Full Stack Python, u'ok': True}

Awesome, we’re authorized to start using the Slack API through our account. We just need a Twilio account and credentials to create our bot!

Sending SMS Messages to Slack

We need access to the Twilio API to send and receive SMS messages. Sign up for a free Twilio account or log into your existing account if you already have one. When you sign up for a new account you’ll be given a Twilio phone number. If you already have an account you can use your existing Twilio phone number or upgrade your account to buy a new number. Click the phone number you want to use for the bot to configure it.

slack-sms-bot.png

Twilio needs a reachable URL to send an HTTP POST request to when an SMS is sent to our Twilio phone number. During development our application is typically running on our local server which cannot be reached from anywhere except our local machine.

To expose my local web server via an externally-accessible domain I typically use ngrok since it’s easy, free and awesome.

Download ngrok and run it with this command:

./ngrok http 5000

You will get a subdomain that forwards requests to that subdomain to your localhost server.

ngrok.png

Copy and paste the https version of the Forwarding URL plus “/twilio” into our phone number configuration under “A messages comes in” as shown here:

configure-number.png

Keep a note of your Forwarding URL, in this case https://9e6d3d38.ngrok.io as we’ll also need that for our Slack outgoing webhook in a future step.

Next, go to the Console Dashboard screen and look for your Account SID and Auth Token:

console-account-sid.png

Copy and paste the Account SID and Auth Token to export them as environment variables.

If you’re still in the Python REPL exit it with a quick CTRL-d or use the exit() command. Back on the command line, export Twilio credentials as an environment variables:

(twiliobot)$ export TWILIO_ACCOUNT_SID='your twilio account sid'
(twiliobot)$ export TWILIO_AUTH_TOKEN='your twilio auth token'
(twiliobot)$ export TWILIO_NUMBER='your twilio phone number, for example +12025551234'
(twiliobot)$ export USER_NUMBER='your phone number, for example +14151230987'

As we did earlier with the SLACK_TOKEN, we will use the newly-exported environment variables in our Python script.

Coding Our Python-Powered Bot

Dive into your favorite text editor such as Vim, Emacs or Sublime Text so we can cut some new Python code. Create a new file named twiliobot.py and start it with the following import statements.

import os
from flask import Flask, request, Response
from slackclient import SlackClient
from twilio import twiml
from twilio.rest import TwilioRestClient

The os module will be used to pull the SLACK_TOKEN, TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN environment variables we exported on the command line. From the Flask framework we import the standard Flask class to instantiate our app, along with the request and Response objects to obtain HTTP input and return appropriate HTTP responses.

The SlackClient import should look familiar as the same line we wrote earlier on the REPL. We’ve also got a couple of new Twilio helper library imports so we can generate TwiML and send outgoing text messages.

With our dependencies imported we can use them to grab those environment variable values and instantiate the Flask app along with Slack and Twilio clients.

TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', None)
USER_NUMBER = os.environ.get('USER_NUMBER', None)

app = Flask(__name__)
slack_client = SlackClient(os.environ.get('SLACK_TOKEN', None))
twilio_client = TwilioRestClient()

Instantiating TwilioRestClient automatically pulls the TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN from environment variables with those exact names.

Add a function named twilio_post to the Python file to handle an incoming HTTP POST request. This POST request will come from Twilio

@app.route('/twilio', methods=['POST'])
def twilio_post():
    response = twiml.Response()
    if request.form['From'] == USER_NUMBER:
        message = request.form['Body']
        slack_client.api_call("chat.postMessage", channel="#general",
                              text=message, username='twiliobot',
                              icon_emoji=':robot_face:')
    return Response(response.toxml(), mimetype="text/xml"), 200

Add a convenience function so we can test whether app works properly and a main function to start the Flask development server when we invoke the script with the python command.

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

Nice! Fire up the Flask app to test it out. Start the Flask app with the `python twiliobot.py` command. We'll see debugging output that indicates the development server is running.
* Running on http://127.0.0.1:5000/ (Press CTRL C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 144-609-426

Time to give our app a try. Send a text message to your Twilio phone number. The SMS will go to Twilio, Twilio will send an HTTP POST request to the ngrok URL you configured in the phone number configuration screen. Then ngrok will forward the POST request to your local machine, which will hit your running twiliobot.py Flask development server. Our Flask web app then uses slackclient to post a message to our Flask channel as twiliobot, just like we see here:

twiliobot.png

Cool, we can send messages to Slack! Next let’s get important messages out of Slack and sent to our phone via SMS.

Receiving Slack Messages via SMS

Our bot can take SMS messages coming to our Twilio phone number and post them as messages to a Slack channel. However, what if we want to see when someone “@” mentions “twiliobot” in a channel? We can set up an outgoing Slack webhook that’ll alert our Python application via an HTTP POST request.

Stop the Flask development server with “Ctrl-C” and modify the existing twiliobot.py file. Add the new highlighted line and the highlighted function shown below.

import os
from flask import Flask, request, Response
from slackclient import SlackClient
from twilio import twiml
from twilio.rest import TwilioRestClient

SLACK_WEBHOOK_SECRET = os.environ.get('SLACK_WEBHOOK_SECRET', None)
TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', None)
USER_NUMBER = os.environ.get('USER_NUMBER', None)

app = Flask(__name__)
slack_client = SlackClient(os.environ.get('SLACK_TOKEN', None))
twilio_client = TwilioRestClient()


@app.route('/twilio', methods=['POST'])
def twilio_post():
    response = twiml.Response()
    if request.form['From'] == USER_NUMBER:
        message = request.form['Body']
        slack_client.api_call("chat.postMessage", channel="#general",
                              text=message, username='twiliobot',
                              icon_emoji=':robot_face:')
    return Response(response.toxml(), mimetype="text/xml"), 200


@app.route('/slack', methods=['POST'])
def slack_post():
    if request.form['token'] == SLACK_WEBHOOK_SECRET:
        channel = request.form['channel_name']
        username = request.form['user_name']
        text = request.form['text']
        response_message = username   " in "   channel   " says: "   text
        twilio_client.messages.create(to=USER_NUMBER, from_=TWILIO_NUMBER,
                                      body=response_message)
    return Response(), 200


@app.route('/', methods=['GET'])
def test():
   return Response('It works!')


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

Go to the Slack Outgoing Webhooks page then click the “outgoing webhook integration” link as shown below.

Scroll down to the Integration Settings section. Select “#general” as the channel to listen on. Enter “@twiliobot” within the “Trigger Word(s)” value. Copy your ngrok Forwarding URL plus “/slack” into the URL(s) text box.

slack-webhook-secret.png

Copy the generated Token in the field below the URL(s) section. Scroll down and press the “Save Settings” button. In case you are wondering, yes, I regenerated my own token after this screenshot. So, no, you can’t use it.

Export the Slack token as a new environment variable:

(twiliobot)$ export SLACK_WEBHOOK_SECRET = 'generated outgoing webhook token here'

Restart your Flask server because it’s time to test out receiving messages via SMS!

Go to your Slack #general channel. You should see that the outgoing webhook integration has been added to the channel.

outgoing-to-twilio.png

Send a message mentioning twiliobot like “@twiliobot hola!” and hit enter. Check your phone:

hola.png

Sweet! That’s pretty simple output but we have a basic way to receive messages from one or more channels and can add whatever Python code we want to handle the input. This is a great hook for expanding our bot or sending messages to another service for processing.

Wrapping it up

Woohoo, all done! Well actually, there’s a whole lot more you can do with the Slack and Twilio APIs. Here are several more ideas to try out now that you’ve got the basics down:

  1. Add natural language processing (NLP) to the Python Flask web app
  2. Try a different Slack client or ditch the helper library entirely and use the Requests library to implement retry logic
  3. Write and customize a more complicated Slack bot

If you want to learn even more about the Slack API and bots, come out to SIGNAL in San Francisco on May 24th and 25th where I’ll be giving a talk called “R2-D2 or Skynet? Combining Slack Bots with the Twilio API” with one of Slack’s developers, Don Goodman-Wilson. You can use the promo code makai20 when you register for 20% off the ticket price.

Questions? Drop a comment below or contact me on these channels:

Twitter: @mattmakai
GitHub: makaimc
Email: makai@twilio.com
Twitch (live coding along with other Twilio Developer Evangelists): Team Twilio

How to Build an SMS Slack Bot in Python

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 12, 2016

There’s something to be said for organization, and the more pieces that are in play the greater need to keep everything orderly. When we’re talking about managing high volume phone calls interactive voice response is the manna for your trek through the desert. One of the great things about using an IVR to centralize incoming calls is that it doesn’t... Read More

The post Case Study: How to Use IVR as a Hub for All Your Voice-Based Customer Service Needs appeared first on Plum Voice.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


This is post 10 of 11 in the series “TextAid Features”

Welcome to the tenth post in our in-depth series about the different features in TextAid.

 This week, we’ll have a look at the download audio feature in TextAid. Watch our quick video to get a feel for this tool.

The download audio tool can be found under the icon download audio icon.

The download audio tool will create an audio file of whatever audio you would hear when you click ‘listen’ within the TextAid window.

If you have the text editor open in TextAid, the download audio tool will create an audio file of the entire text.

If you have a document open in TextAid (PDF), the download audio tool will produce an audio file of the current page open in the document. Consequently, to create audio of the entire document, you will need to use the download audio tool once per page.

Use the download audio tool to study offline—download the files and then upload the mto your different devices. Additionally, listen to your own written texts as a way to check for fluency.

Get started with ReadSpeaker TextAid today!

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


May 11, 2016

What’s that? You want to add filters to your video application that serve no purpose other than looking awesome? Check out how easy adding CSS filters are to elements on your page.

In a recent post we saw how to introduce React.js into an existing application. Let’s pick up where we left off and add our video filters as a new React component.

Start by cloning this repo and moving into it:

git clone -b conversation-react-component git@github.com:eddiezane/react-twilio-video-post.git
cd react-twilio-video-post

Follow the instructions in the README.md to get your credentials configured. If you want to learn how this app was built go back and run through this post. It will take you about 10 minutes.

Fire up the app:

node .

Open http://localhost:3000 in two browser tabs to confirm everything is working (it’s secretly required that you make a goofy face).

Filters Are Simple

CSS filters are really straightforward to use. They are simply CSS rules that we’ll apply to the video div’s via a CSS class. We’ll base our filters off of this excellent example.

Start by opening up our application’s stylesheet located at public/style.css and adding in the following classes to the bottom:

.nofilter {}

.sepia {
  -webkit-filter: sepia(1);
  filter: sepia(1);
}

.invert {
  -webkit-filter: invert(0.8);
  filter: invert(0.8);
}

.grayscale {
  -webkit-filter: grayscale(1);
  filter: grayscale(1);
}

.saturate {
  -webkit-filter: saturate(4);
  filter: saturate(4);
}

.blur {
  -webkit-filter: blur(3px);
  filter: blur(3px);
}

.filter-list {
  list-style: none;
}

This set of filters will change the video to sepia, inverted, grayscale, over saturated, and blurry. You should get creative and add your own to the list as well. The example shows how you can combine filters.

Next we’ll introduce two new React components to handle applying the filters.

The Filter component will represent a single filter as an li whose name value is passed in via a prop along with a filterClickCallback to handle the filter being selected. The FilterList component will create and hold all of the Filter‘s inside a ul.

Open up our React code at public/conversationcontainer.jsx and add the FilterList component at the bottom:

 

class FilterList extends React.Component {
  render() {
    const filters = this.props.filters.map((filter, index) => {
      return <Filter name={filter} key={index} filterClickCallback={this.props.filterClickCallback} />;
    });

    return (
      <ul className='filter-list'>
        {filters}
      </ul>
    );
  }
}

The render method maps over the list of filter properties that are passed in and creates a new Filter for each.

Now add the Filter component at the bottom.

class Filter extends React.Component {
  render() {
    const name = this.props.name;
    return (
      <li>
        <button onClick={() => this.props.filterClickCallback(name)}>
          {name}
        </button>
      </li>
    );
  }
}

Add a constructor to the existing ConversationContainer to establish the initial filter list. We’re also binding the filterClickCallback method which we’ll write next.

module.exports = class ConversationContainer extends React.Component {
  constructor(props) {
    super(props);
    const filters = ['none', 'sepia', 'invert', 'grayscale', 'saturate', 'blur'];
    this.state = { filters };
    this.filterClickCallback = this.filterClickCallback.bind(this);
  }

Right below the constructor add the filterClickCallback method which will update the state of our active filter:

  filterClickCallback(filter) {
    this.setState({
      activeFilter: filter
    });
  }

Then modify the render method of ConversationContainer to include the FilterList and filter CSS classes from our state:

render() {
    return (
      <div>
        <div ref='remoteMedia' className={`media-container ${this.state.activeRemoteFilter}`}></div>
        <div ref='localMedia' className={`media-container ${this.state.activeFilter}`}></div>
        <FilterList filters={this.state.filters} filterClickCallback={this.filterClickCallback} />
      </div>
    );
  }

Start the server back up and open http://localhost:3000 in two browser windows again. Connect a conversation and start clicking to apply the video filters. You should seriously consider making a scary monster face here.

Getting Real-Time

You may have noticed that the filter isn’t applied to both pages. We need some way of communicating that the other client should show whichever filter we have selected for our video on their page.

I’ve chose to use one of my favorite libraries, Socket.io, to solve this. Socket.io is a WebSocket library with an easy to use API. Check out my buddy Sam’s post if you haven’t used Socket.io before.

Install Socket.io by running:

npm install —save socket.io

Now let’s configure our server to use Socket.io. Open index.js and make the following changes:

// Create http server and run it
var server = http.createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 3000;
server.listen(port, function() {
    console.log('Express server running on *:' + port);
});

io.on('connection', function(socket) {
  socket.on('filter', function(data) {
    socket.broadcast.emit('filter', data);
  });
});

We’ve imported the library,connected it to our Express server and added a listener for a custom filter event that our clients will emit when a new filter is selected. Time to wire the client up.

Pop back into public/conversationcontainer.jsx and import the client side library:

const React = require('react');
const ReactDOM = require('react-dom');
const io = require('socket.io-client');

Inside componentDidMount initialize the Socket.io client and listen for the filter event to update the state:

componentDidMount() {
    const conversation = this.props.conversation;
    conversation.localMedia.attach(this.refs.localMedia);

    conversation.on('participantConnected', participant => {
      participant.media.attach(this.refs.remoteMedia);
    });

    const socket = io('/');

    socket.on('filter', filter => {
      this.setState({
        activeRemoteFilter: filter
      });
    });

    this.setState({ socket });
  }

Finally, emit the same event at the top of filterClickCallback:

filterClickCallback(filter) {
    this.state.socket.emit('filter', filter);

Start up the app one last time and open your browser tabs. Connect one to the other and start clicking your new filter buttons and watch as they are applied across browsers.

Wrapping It Up

CSS filters are a quick and easy way to add a bit of fun and customization to your web apps. The best part is that these CSS filters can be applied to everything from images to iFrames, or as we saw in this post, Video!

Using React we were able to create a set of reusable components to encapsulate our filter UI into a set of declarative elements which cut down on the complexity and length of our UI code. Those components would be at home in any UI, from the most complex to what we used them for: adding a bit of fun and pizazz.

Finally, throw in few lines ofSocket.io to coordinate filters across clients and you’ve built yourself a simple way to share the fun with your video conference friends.

Have a crack at adding some filters of your own and be sure to let me know what you come up with.

How To Add React Powered CSS Filters To Twilio Video

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Third party libraries are often a necessity when building iOS applications. Carthage is a ruthlessly simple tool to manage dependencies in Swift.

What about CocoaPods?

At this point, many iOS developers might be wondering how Carthage differs from CocoaPods which is another dependency manager for iOS described a recent tutorial tutorial. Carthage emphasizes simplicity, described in this Quora answer by a Carthage collaborator.

Unlike CocoaPods, which creates an entirely new workspace, Carthage checks out the code for your dependencies and builds them into dynamic frameworks. You need to integrate the frameworks into your project manually.

How to install dependencies with Carthage

Let’s build an app that will display a recent picture taken on Mars using this NASA API with Alamofire to send HTTP requests and SwiftyJSON to make handling JSON easier. I will be using Xcode 7.3 and Swift 2.2 for this tutorial.

Start by creating a Single View Application Xcode project called PicturesFromMars. Select “Universal” for the device and enter whatever you want for the rest of the fields:

XcodeProj.gif

The three dependencies we are using are Alamofire, SwiftyJSON and AlamofireImage to load an image from a URL.

In order to install dependencies, we’ll first need to have Carthage installed. You can do this by installing it manually or via Homebrew by opening up your terminal and entering this command:

brew install carthage

Carthage looks at a file called Cartfile to determine which libraries to install. Create a file in the same directory as your Xcode project called Cartfile and enter the following to tell Carthage which dependencies we want:

github "Alamofire/Alamofire" ~> 3.3
github "Alamofire/AlamofireImage" ~> 2.0
github "SwiftyJSON/SwiftyJSON"

Now to actually install everything run the following in your terminal:

carthage update --platform iOS

This is where things start to really differ from CocoaPods. With Carthage, you need to manually drag the frameworks over to Xcode.

Open your project in Xcode, click on the PicturesFromMars project file in the left section of the screen and scroll down to the Linked Frameworks and Libraries section in Xcode.

Now open the Carthage folder in Finder:

open Carthage

Drag the frameworks in the Build/iOS folder over to Xcode as seen in this GIF:

DragDependencies.gif

Now your Swift code can see these frameworks, but we need to make sure the device that the app is running on has them as well.

  1. In your project settings, navigate to your “Build Phases” section.
  2. Add a “New Copy Files Phase”
  3. Go down to the “Copy Files” section
  4. Under “Destination” select “Frameworks”
  5. Add the frameworks you want to copy over as seen in this GIF:

EmbedFrameworks.gif

Now that you have the frameworks linked, head over to ViewController.swift and try importing the libraries to see if things are working:

import Alamofire
import AlamofireImage
import SwiftyJSON

You can see if everything builds correctly by pressing “Command-B.”

Screen Shot 2016-05-04 at 3.31.23 PM.png

Getting ready to use the libraries we just installed

Before we can load images from Mars, we’ll need a UIImageView. Go over to Main.storyboard and add a UIImageView to your ViewController as seen in this GIF:

ImageView.gif

Set the constraints so that the UIImageView takes up the whole screen. Click on the “pin” icon and at the top in the four boxes, enter 0 and click on each of the directional margins. Also update the frames as seen in this GIF:

Constraints.gif

We have a UIImageView but no way to control it. Create an outlet for it in ViewController.swift called marsPhotoImageView.

You can do this several different ways, but I usually do this by opening the “Assistant Editor” with one screen having Main.storyboard open while the other displays ViewController.swift. While holding the “Control” key, click on the UIImageView in main.storyboard and drag the line over to ViewController.swift. Here is another GIF demonstrating how to do that:

ImageView.gif

The app will grab a picture from Mars taken on the most recent “Earth day” from NASA’s API for the Curiosity Rover and will load that image in our UIImageView.

Images are usually not available right away so let’s grab images from 5 days ago to be safe. We’ll need a quick function that generates a string that is compatible with this API. In ViewController.swift add this new function:

func getDateString() -> String {
    let calendar = NSCalendar.currentCalendar()
    let yesterday = calendar.dateByAddingUnit(.Day, value: -5, toDate: NSDate(), options: [])
    let components = calendar.components([.Day , .Month , .Year], fromDate: yesterday!)

    return "\(components.year)-\(components.month)-\(components.day)"
}

With this taken care of, we can send a request to the Mars Rover API, grab an image URL and load it in the marsPhotoImageView.

Handling HTTP requests with Alamofire and SwiftyJSON

Alamofire and SwiftyJSON are installed and imported in our code. All we need to do now is send a GET request using Alamofire to receive an image URL that we will use to load our UIImageView’s image property.

Replace your viewDidLoad with the following code:

override func viewDidLoad() {
    super.viewDidLoad()
    let dateString = getDateString()
    Alamofire.request(.GET, "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos", parameters: ["api_key": "DEMO_KEY", "earth_date": dateString])
    .responseJSON { response in
        if let result = response.result.value {
            let json = JSON(result)
            if let imageURL = json["photos"][0]["img_src"].string {
                // Replace "http" with "https" in the image URL.
                let httpsURL = imageURL.stringByReplacingOccurrencesOfString("http", withString: "https")
                let URL = NSURL(string: httpsURL)!

                // Set the ImageView with an image from a URL
                self.marsPhotoImageView.af_setImageWithURL(URL)
            }
        }
    }
}

Notice that we are replacing the http in the URLs with https because we can only send requests to secure URLs by default.

Run the app in the simulator and check out the latest picture from the Mars Rover!

MarsPhotos.gif

Building awesome things is so much easier now

There are a ton of APIs out there that you now have access to using Carthage to manage dependencies. Twilio has some awesome APIs if you want to add Video chat or in app chat to your iOS app.

I can’t wait to see what you build. Feel free to reach out and share your experiences or ask any questions.

Getting started with Carthage to manage dependencies in Swift and iOS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Last updated: May 24, 2016 11:01 PM All times are UTC.
Powered by: Planet

Speech Connection and Logos are Trademark of Nu Echo Inc. Copyright 2006-2008.