Building an IVR with Twilio and Node-RED


Node-RED Library page: node-red-contrib-twilio-ivr

Project source code at GitHub: node-red-contrib-twilio-ivr

Twilio is fast becoming an important part of Internet’s communication infrastructure. What is Twilio? Twilio is a developer platform that allows you to add capabilities like voice, video, and messaging to your applications. This project uses the Twilio Programmable Voice APIs to bridge the gap between the telephone system and the Internet. It connects the mysterious, traditionally closed world of telephony with the open Internet. If you like building things on the Internet, now you can integrate with those things using the phone system, whether it be via voice calls, text messages, or even wireless devices with Twilio SIM cards. Like many API services, Twilio has a pay-as-you-go model, so I’ve been able to explore all this great functionality for very little money. In this project I will show you how you can build an IVR (Interactive Voice Response) system with Twilio and one of my favorite technologies, Node-RED. And I have a great example IVR that you can call yourself to explore!

Twilio + Node-RED = POWER!

In case you don’t know what an IVR is, it’s that thing when you call a customer service phone number and are presented with a menu system that helps you (or tries to). A caller interacts with the IVR by pressing keypad numbers and speaking commands. To start using Twilio in this way, you need to buy a phone number from Twilio for your callers to call. As a developer, you present “content” to the caller by using a Twilio markup language called TwiML which instructs Twilio how to present your IVR content to whomever calls your number. It’s really just like building a web server that returns HTML that is presented by a web browser. But in this case, we build an HTTP server that returns TwiML to Twilio which audibly presents that content to the caller. The caller’s phone is the browser! Twilio handles the job of connecting telephone callers to your HTTP server.



You can build a TwiML server using any web server technology, like PHP on an Apache server, etc. I chose to use Node-RED because I use it for lots of IoT processing flows. Most importantly, by building a library of nodes specifically designed for building a Twilio IVR, I (and now you) can build sophisticated IVRs by dragging and dropping nodes into a Node-RED flow. And since Node-RED has many libraries available for integration into just about anything (including a way to invoke Twilio APIs), your IVR can integrate with databases, other servers, social media, and anything else in Internet-land. I think Node-RED is the perfect tool for creating IVR flows.

Note that Twilio has their own product like this called Twilio Studio, but I built my system before they announced their product. Besides, mine is free and I think you can build much larger and more sophisticated IVRs with my solution :)

Node-RED IVR Components

Here is an overview of the main components of an IVR built with this system. Instructions for setting all this up for your own IVR is later in this article.

Twilio IVR Library

To make all this easy, I built a library of Node-RED nodes that create TwiML for the response. Some nodes are simple and have a one-to-one correspondence with TwiML markup, like the “play” node for playing MP3 files and the “say” node for speaking text. These nodes create TwiML using the <Play> and <Say> tags. Other nodes are for higher-level IVR concepts, like the “menu” node. It lets you create a menu that is spoken to the caller and arranges for the caller input to route to the correct part of the IVR flow.

Twilio IVR Core Flow

Much of the heavy lifting of the IVR is done by a predefined Node-RED flow called Twilio IVR Core. Your IVR will use this Node-RED flow and you won’t need to change it. The main part is the Universal Router. Twilio always invokes the Universal Router HTTP endpoint (which is /router) which figures out which route to follow through the IVR based on the user’s input or routing information specified by the previously invoked route (more on this later). Routes are a key concept in the IVR. The are a particular path that the caller is on, and have names like /main-menu or /account or /agent.

Example IVR: “Customer Service Hell”

The easiest way to demonstrate the many features you can implement in an IVR was to build a great example. The Node-RED flow “Customer Service Hell” is an example that uses many features. It is designed to frustrate any caller with a maze of menu choices and frustrating interactions. You can call this IVR at (612) 999-2812. (if you are international, dial +1-612-999-2812). Please note that it costs us a small amount of money every time you call, so don’t abuse it, but by all means use it to learn and maybe get a good laugh. Here is a huge image of this Node-RED flow that you can use to follow along. Be sure to look at the route called /nightmare-hold. If you are planning on implementing a Twilio IVR, I suggest you start with this flow by import it into your Node-RED implementation (more on setup later).

Twilio Configuration

Of course you have to tell Twilio to invoke your Node-RED server: in the Twilio console, specify your server endpoints in the configuration for your Twilio phone number. Here is an example of how this should look. Node-RED can be congfigured to protect HTTP endpoints with username/password credentials, so you need to specify these as well. Note that the error webhook does not need the credentials (and doesn’t work if you provide them).



How It All Works

Twilio invokes the IVR over HTTP to get the TwiML response for Twilio to present to the caller. A response to the caller may request input from the caller in the form of a menu or may prompt the caller for other input like an account number or invite the caller to speak a command. The Universal Router controls the flow of a call. First, it finds the caller’s session or creates a new session if the call is new. The session keeps track of anything we want to remember since we last returned TwiML to Twilio. (It’s just like a web server session where we keep track of info before responding to the browser.)

Next, the router determines which route to invoke. For example, if a menu was presented to the caller during the last invocation, then the caller’s input must be matched to the correct route to invoke. The session automatically keeps track of any menu that was presented so that the caller’s input can be used to route correctly. For example, if the last menu told the caller to press “1” for accounting, then if they pressed “1”, we route to the /accounting route. Another important thing to note is that if a call is new, the router will invoke a route called /begin, so your IVR needs to define this route as the starting point for a new call.

Next, the router actually invokes the desired call route. Each route in the IVR begins with a Node-RED HTTP endpoint. Even though Twilio does not invoke these HTTP endpoints directly (Twilio always invokes /router), the Universal Router invokes routes via HTTP. The responsibility of a route is to return the TwiML that is to be returned to Twilio. The outer layer of TwiML (the <Response> and </Response> tags) are taken care of by the router.

Examples of Common Route Patterns

Presenting a Menu

A common pattern in an IVR is to present the caller with a menu of choices. Here is the part of the IVR that implements the /main-menu route, as well as the starting point for the whole IVR, /begin. You can see that if a call is new it says a welcome message before connecting to the /main-menu route.



The pattern for a menu-based route is to start with a gather-begin node which tells Twilio that we want user input. See the Twilio documentation for the <Gather> TwiML element. You can configure the gather-begin node to expect DTMF (touch tones) or speech input, or both. You can also provide speech hints to help Twilio recognize speech input. For example if you are presenting a menu that allows the caller to say “representative”, then specify the string “representative” as a speech hint in the gather-begin node to help Twilio recognize the caller’s utterance.



The menu node creates the TwiML that reads a menu to the caller. This node provides lots of flexibility. For each menu item, the item can be spoken (“Say”) or an audio file can be played (“Play”). The word “For” can be prepended to the name of the item if that makes sense. The caller can press a number to choose the item (“Press” option) or can press or say it (“Press or Say” option). You can also specify speech that can be used to choose the item. For example in the second item below, the caller can press 2, say “two” or say “account” to choose the item. Finally, each item specifies which route in the IVR to invoke if chosen. The Universal Router will inspect the input from the caller (whether spoken or entered) and determine the route to invoke.



Also, don’t forget to use a gather-end node before returning to the router. This adds the ending tag </Gather> to the TwiML response.

Using the set-route node

Although menus are a common pattern, not every route in an IVR presents the caller with a menu of choices. Sometimes you want to prompt the caller for input (like an account number) or prompt them to make a recording of some kind. An example of this is the /account route in the Customer Service Hell IVR. Click the image below to see this route. Note that we still need the gather-begin and gather-end nodes since we are asking for input.



Dynamically building a menu

One more pattern that you may find a use for is the ability to build a menu dynamically instead of specifying it all in a single menu node. Below is a particularly insidious part of our Customer Service Hell IVR. After prompting the caller for a 4-digit PIN, it transposes the digits that they entered and tells the caller that their PIN is wrong. The IVR keeps track of the number of times the caller has failed (in the call session), and after multiple failures we add a menu choice for the caller and invite them to “shock the monkey” by pressing ‘*’. (Relax, PETA, it’s just a sound effect.) This ability to dynamically build the “content” returned to the caller is very powerful.



System Setup

Here are the steps to take if you want to actually build and IVR. I suggest you get the example “Customer Service Hell” IVR working first so you can see how everything works together.

First it is assumed you have Node-RED installed and running. If you don’t, then get started at the Node-RED website.

In your Node-RED installation, install the Twilio IVR library:

npm install node-red-contrib-twilio-ivr

Next, you’ll need to add a Node-RED flow with the Twilio IVR Core. You can get this flow from the Node-RED Library entry for this project. In Node-RED, use the Import option on the menu and import from the clipboard. Past the Twilio IVR Core content from the clipboard.

To run the Customer Service Hell IVR, create another flow in Node-RED and import from the clipboard just as you did for the Twilio IVR Core. Past the content of the IVR flow into Node-RED. This IVR relies on audio files which are retrieved by Twilio when you tell Twilio to play an audio file using a “play” or “menu” node. You can download the audio files from this link and you will need to host them on a server. You will specify the base URL of all the audio files in the configuration of your Node-RED “play” and “menu” nodes.

Don’t forget to configure your Twilio account to point your phone number at your Node-RED server (this is described earlier in the article).

Final Notes

You will need to make one change in the Twilio IVR Core flow: the Universal Route contains an HTTP node called “invoke route” which makes the HTTP call to the route endpoints. If your server is protected with a username/password you will need to specify them. You will also need to tell this node whether it needs to use SSL/TLS when connecting.






Published by Michael, on December 15th, 2018 at 10:11 am. Filed under: Telephony,Twilio. | No Comments |





LoRaWAN Networking Part 2: Using End Devices


In part 1 of this series I showed how to set up a simple LoRaWAN gateway, and in a previous article described a simple but powerful LoRaWAN-capable end device that I designed. Now I’ll show how these devices can be used in a real LoRaWAN application.

LoRaWAN Application on The Things Network

The Things Network (TTN) is the Internet infrastructure that allows us to use end devices to do something useful on the Internet. End devices (sometimes called nodes) talk to a nearby gateway, which is connected to the Things Network infrastructure. An application is anything you can imagine on the Internet that does something with the data provided by the end devices. The Things Network bridges the radio technology to Internet technology. The communication does not need to be one-way; applications can downlink data to end devices, too. A common example of an application is a Cayenne dashboard which is an easy way to visualize data from your devices. You can also read data from TTN using Node-RED, a common tool for building IoT solutions.



In part 1 I showed how a gateway is registered to TTN. To connect end device nodes, we also have to define an application in TTN, even if the real functionality of our application is implemented elsewhere on the Internet. An application has a name and a unique ID called a Application EUI. It also creates an Application Access Key that you use to integrate other services like Cayenne or Node-RED to your application. I won’t go into the integration details because there is plenty of info available about that.

After creating a TTN application, you need to add devices to the application so that your code on the devices can talk to TTN. There are 2 ways for a device to authenticate with TTN. The recommended and more secure way is called over-the-air-activation, or OTAA. This is the default mechanism when you create a device in TTN. With OTAA, a device negotiates with the network to establish a network session key and an application session key. The other mechanism is activation-by-personalization, or ABP. With ABP, the keys needed to communicate with the network are hard-coded in the device ahead of time. This makes it much easier and quick to connect, but is less secure.

Before we go any further with details about OTAA and ABP, let’s define the many types of IDs and keys associated with LoRaWAN applications and devices. It can be very confusing, because some of them have very similar names!

Gateway ID: A uniquie identifer for your gateway. You specify this when you register a gateway with TTN.

Application EUI: A unique identifier for an application. It is provided by TTN when you create an application.

Device ID: A name that you assign to a device when you register it in TTN.

Device EUI: A unique identifier for an end device. This may be provided by your hardware so that you can specifiy it when registering a device in TTN. OR, you can have TTN generate one for you.

Device Address: An idenfier for an end device that is used during communication between device and TTN. This is assigned dyamically when using OTAA, but is hard-coded when using ABP.

Application Key: A value that is used for secure communication between device and TTN. This is generated when a device is registered with a TTN application. Each device has a different Application Key.

Network Session Key: A value that is used for secure communication between device and TTN. This is assigned dynamically for a session when using OTAA, but is hard-coded when using ABP.

Application Session Key: A value that is used for secure communication between device and TTN. This is assigned dynamically for a session when using OTAA, but is hard-coded when using ABP.

Is everything clear now? I didn’t think so. Let’s break it down in terms of what information you need for the two approaches, OTAA and ABP.

Over-the-Air Activation (OTAA)

After defining an application in TTN and registering a device, the device code needs some of important information in order to connect to the network successfully via a gateway. OTAA requires 3 pieces of information: Application EUI, Device EUI, and Application Key. The other information — Device Address, Network Session Key, and Application Session Key — will be determined dynamically during the activation process.

See the OTAA example on GitHub. Note the library dependencies required for the examples to work.

Although this method is secure and recommended, connecting to the network can take several minutes or more. The negotiation of session keys requires that the network communicate back down to to the end device during precisely timed receive windows, which can be tricky.

Activation-by-Personalization (ABP)

Using the ABP approach, the device code needs different information in order to connect to the network. ABP requires 3 pieces of information: Device Address, Network Session Key, and Application Session Key. This method of connecting is much faster and reliable, but for a number of reasons is less secure.

See the ABP example on GitHub. Note the library dependencies required for the examples to work.

When using an ABP device, it’s important to disable the frame counter checks in the device settings on TTN. This is one of the things making it less secure.



Range Testing

By driving around with an end device node in my car, I’ve tried to determine my communication range with my gateway. I’ve been a bit disappointed, but there are many things that affect signal propagation. First, despite having an 10-foot antenna mast, my antenna is still not even close to being higher than my house. And I’m hardly an RF engineer when it comes to designing my custom end devices.



They have a simple wire antenna, but my prior experimentation led me to think that this was just as good as any other LoRa antenna I’ve tried. In one test, my son and I each strapped a LiPo battery powered end device to our bikes and went for a long ride, having each node send GPS data every minute to my gateway (I realize that this test used far more duty cycle than one should in a real application). A Cayenne dashboard mapped the received data from each device. The smooth path on the map is the actually path as measured by GPS in my son’s phone. Superimposed on this are two non-smooth paths defined by blue points at which the gateway “heard” the GPS data reported from the end-device. The gateway is in the southwest are of the map, and you can clearly see that it did not receive much data when we are on the northernmost part of our bike ride. The maximum distance for a received signal was about 1.2 miles.



I also experimented between using confirmed vs. unconfirmed messages. Confirmed message get an acknowledgement from the gateway, whereas unconfirmed are more like “fire and forget”. Counterintuitively, it seemed like confirmed messages were more reliable and had better range. Nonetheless, I will continue to do more range testing to try to improve the situation.

Node-RED Integration

An online service like Cayenne makes it super easy to integrate with TTN, but you can also integrate with your own software via MQTT. Data uplinked from your devices to your TTN application are published to MQTT topics that you can connect to in your own application. I love using Node-RED for all sorts of IoT fun. You can use MQTT nodes (here “nodes” refers to Node-RED components, not end devices) to receive the data published by TTN. To make it even easier, TTN has even written custom nodes for TTN integration. If you are a Node-RED junkie like me, I strongly recommend you look into this type of integration so that you can build just about anything based on data from LoRaWAN end devices.



I hope you found these posts about LoRaWAN useful. The learning curve is significant but it’s exciting when a technology is so new.




Published by Michael, on October 28th, 2018 at 11:27 am. Filed under: GPS,IoT,LoRa. | No Comments |





LoRaWAN Networking Part 1: The Gateway


I have been playing with LoRa modules a lot recently (see projects LoRa Weather Station and LoRa Mesh Networking) and even designed my own LoRa development boards. LoRa is an easy way to achieve low-power, long range radio communication with small payloads. To get even more capability out of this radio technology, you can set up a LoRaWAN network that is connected to the Internet and allows mobile nodes to hop between gateways, just like your mobile phone connects to different cell towers as you move around. So this summer I was determined to set up a low-cost LoRaWAN gateway and get it up and running on The Things Network. It was easier than I thought.

Gateway Hardware

A gateway is an Internet-connected LoRa device that listens to multiple LoRa channels and forwards packets between the network backhaul (e.g. The Things Network) and the end device nodes it hears. Think of it like a cell tower for lower-power, mobile end device nodes. There are several gateways to choose from and I decided to try the RAK831 gateway from RAK Wireless, a Chinese company. The RAK831 is a LoRaWAN concentrator board that connects to a Raspberry Pi. I bought their LoRaWAN starter kit because it seemed to have everything you need.



In fact, it had more than I really needed. Here are the components that were essential to me:

  • RAK831 LoRaWAN concentrator board
  • Raspberry Pi 3 with SD card preloaded with all the drivers and setup for The Things Network
  • Converter board to attach the RAK831 to the Raspberry Pi. This board also has a GPS receiver on it.
  • GPS antenna
  • Glass fiber antenna with 6dBm gain, so I could set up a tall antenna mast
  • a 5 meter RG-58 tie line for the antenna
  • heat sink for the concentrator board. I’m not sure it’s necessary.

The kit also came with a WisNode board which is like an Arduino + LoRa end device. It also came with a board called a LoRa Tracker, which I found useless because it requires some strange programming environment to use. Besides I had already designed my own end devices with GPS.

Configuration

I got a lot of information from this article on hackster.io about how to configure the Raspberry Pi to connect to The Things Network. Many of the steps are not necessary because the required software was preloaded. I did not have to enable SPI on the Raspberry Pi, or download the iC880a-based gateway software from GitHub. This had already been done.

I did set my WiFi credentials in /etc/wpa_supplicant/wpa_supplicant.conf as instructed.

Then the main task is to set up the configuration file for the gateway. First, you need to determine the gateway ID. It is unique to the hardware because it is based on the MAC address of the network interface. Here’s a handy script to get it:

GATEWAY_ID=$(ip link show eth0 | awk '/ether/ {print $2}' | awk -F\: '{print $1$2$3"FFFE"$4$5$6}'); echo ${GATEWAY_ID^^}

Configuring the gateway is a little confusing. First, there’s a global configuration file that is not specific to your gateway but is specific to the region you are operating in (EU, US, Australia, etc.). I’m in the US, so I used the US global configuration file from the Things Network’s gateway-conf project on GitHub.

The gateway_conf section near the end is the important part. This has the correct router information for your region. This file goes in /opt/ttn-gateway/bin. IMPORTANT: in order for my gateway to work, I had to enable GPS in the global_config.json file by adding this to the gateway_conf section:

{
  "gateway_conf": {
  	...

    "gps": true,
    "gps_tty_path": "/dev/ttyAMA0",
    "fake_gps": false,

  	...
  }
}

Information specific to your gateway goes in a file /opt/ttn-gateway/bin/local_config.json. Here you use the key information from the global_config.json plus your gateway_ID, location information about where your gateway is, and contact info. Here’s mine:

{
  "gateway_conf": {
    "gateway_ID": "B827EBFFFEF11045",
    "servers": [
      {
        "server_address": "router.us.thethings.network",
        "serv_port_up": 1700,
        "serv_port_down": 1700,
        "serv_enabled": true
      }
    ],
    "ref_latitude": 45.0466,
    "ref_longitude": -93.4747,
    "ref_altitude": 277,
    "contact_email": "michael@nootropicdesign.com",
    "description": "nootropic design RAK831 LoRa gateway"
  }
}

When the gateway starts, the local_config.json info is merged with the global_config.json information.

The tricky thing is that your gateway configuration can be controlled by a remote file in GitHub. The gateway-remote-config GitHub repo is a collection of many local config files for TTN Gateways. When your gateway starts up, it actually pulls the latest content from GitHub. If it finds a file for your gateway, it removes the local_config.json file and creates a symbolic link from bin/local_config.json to the file in the cloned repo on your Raspberry Pi!

If you want to do this, fork the gateway-remote-config repo on GitHub, commit your own local config file to your forked repo named for your GatewayID (e.g. B827EBFFFEF11045.json), and then submit a pull request to the master repo. In a few days, your local configuration file will be merged and when your gateway starts, it will use it.

My final configuration is the /opt/ttn-gateway/bin/local_config.json which is a link to the
my config file in GitHub. The gateway_conf section in global_config.json simply contains this:

{
  "gateway_conf": {
    "gps": true,
    "gps_tty_path": "/dev/ttyAMA0",
    "fake_gps": false
  }
}

The Things Network

You’ll need to register your gateway on The Things Network using their registration instructions. This is easy.



Enclosure and Antenna

I mounted my gateway in a waterproof enclosure with wires going in for the 5V power, LoRa antenna, and GPS antenna. It did not get too hot in the summer, and I will soon see how well it fares in a Minnesota winter. I am hoping that the heat generated by the enclosed Raspberry Pi will keep the hardware from freezing, but I have no idea!



The antenna mast is PVC pipe and I used a 5 meter RG-58 cable to connect the concentrator board to the glass fiber antenna. There is power loss in 5 meters of cable, but the antenna still provides a net gain after accounting for this. I think it looks great and I hope my neighbors don’t think it is an eyesore.



In Part 2 of this article I’ll get into the details of using LoRaWAN nodes with the gateway. Stay tuned.




Published by Michael, on October 27th, 2018 at 3:57 pm. Filed under: GPS,IoT,LoRa. | No Comments |





SAMD21 LoRa Development Board with GPS


Project source code at GitHub: samd21-lora-gps

I’ve been doing some LoRa projects lately in order to learn as much as I can about this exciting new radio technology (see this LoRa mesh networking project and this LoRa weather station). ATmega328-based Moteino modules work great for a lot of projects, but I wanted a LoRa node with more processing power, more memory, and an onboard GPS receiver. The ATmega328 is just too constrained with memory — I’ve outgrown it. I really wanted a LoRa board with an ARM Cortex microcontroller like the SAMD21. This is the microcontroller used on the Arduino Zero. So, my ideal board is a SAMD21 with LoRa radio module and GPS receiver, all programmable with the Arduino IDE.

But, where is such a board? I could not find one so I decided to design and make one myself.



Hardware Design

Microchip/Atmel makes a SAMD21 chip and there are several variants. Most designs use the ‘G’ variant, but I wanted to use the simpler ‘E’ variant because it comes in a TQFP-32 package that I can very easily solder in my reflow oven without any trouble, or even by hand if I have to.

The GPS module is a cheap Quectel L80 with a MTK3339 chipset. It is easy to use but the backup power circuit requires a charging circuit, so I don’t have battery backup for quick startup. I mainly chose this module because it has big soldering pads with 2.54mm spacing for easier prototyping.

The LoRa radio module is a HopeRF module soldered to the bottom of the board.



Here is the schematic and image of the board design. The Eagle files are in the hardware directory of the samd21-lora-gps GitHub repo.






Burning a Bootloader

To make this board work with Arduino, I had to burn the Arduino bootloader onto the chip using an Atmel-ICE programmer. My board has 5 test points on the bottom for this purpose. The Atmel-ICE needs connections for VTG (3.3V), SWDIO, SWCLK, RESET, and GND. The board has to be powered over USB during the programming procedure. In the Arduino IDE, I selected Tools->Board = Arduino/Genuino Zero (Programming Port), Tools->Programmer = Atmel-ICE, and then just clicked Tools->Burn Bootloader. In a few seconds, my board had a bootloader and is now programmable as an Arduino Zero!

Programming the Board

I was careful in my design to allow this board to be used as an ordinary Arduino Zero even though it uses a different variant of the SAMD21 chip. The downside of this is that the default SPI pins defined for the Arduino Zero board use pins that are not present in the ‘E’ variant of the SAMD21. Luckily the design of the Arduino system is flexible enough that we can define a different SPI interface on different pins. There is a great article by Adafruit on this topic but it may be pretty hard to understand. The bottom line is that by using these lines in your Arduino sketch:

SPIClass SPI1(&sercom1, 12, 13, 11, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3);
pinPeripheral(11, PIO_SERCOM);
pinPeripheral(12, PIO_SERCOM);
pinPeripheral(13, PIO_SERCOM);

You can now use interface SPI1 to communicate with the LoRa module. I wrote a simple test sketch that reads the GPS module and broadcasts the GPS coordinates on the radio every 15 seconds. See the samd21-lora-gps GitHub repo.

This test code uses the RadioHead library to control the LoRa radio. The RadioHead library is flexible so I was able to use the SPI1 interface by defining a couple of new files, RHHardwareSPI1.[cpp,h].




Published by Michael, on October 27th, 2018 at 7:57 am. Filed under: IoT,LoRa. | 5 Comments |