[read this post on Mr. Fox SQL blog]
Recently I did a presentation at our local SQL Server User Group (SSUG) on Managing Streaming Data Pipelines Using Azure Data Services and as such wanted to build a compelling Azure demo that worked with simple streaming data which under certain event conditions would trigger an outbound phone call.
If interested the presentation deck is here – SSUG Melbourne – Building Streaming Data Pipelines Using Azure Cloud Services
The solution had several key components and stages outlined in the architecture below.
- A mobile phone app which generates JSON events with the X, Y, Z location of the device and G (g-force) detected in the device during movement.
- An Azure IoT Hub (AIH) which accepts the JSON events posted from the mobile device
- An Azure Stream Analytics (ASA) job that queries the Event Hub and routes the event data to several outputs, including…
- Azure Blob Storage (for archive of all event data)
- Power BI (for a live dashboard of all event data)
- Azure SQL Database (ASDB) (for tabular storage of all event data)
- Azure Event Hub + Azure Function (AF) (for queuing events which have a G Force reading greater than 3 and then triggering a phone call back to the original device from which the event originated)
The entire demo solution is actually really interesting (tsk, of course!) – and I will blog about other separate parts of this presentation at some point later. However the part of the demo that received the most interest was the external phone call integration with Azure Functions.
To be clear up front – Azure itself does not have native phone capability – so to make outbound phone calls I leverage an external “Twilio” API from within an Azure Function, and “Twilio” connects the outbound call.
And so, lets see the Twilio phone setup and c# Function code in action!
To set the scene, I will briefly describe each of the pipeline Azure data services up to the Twilio phone integration point, and then deep dive into the details.
Windows 10 Mobile Phone App
This is a screenshot of the Windows 10 Mobile Phone App which sits on the mobile device and generates the JSON events. Yeah, its still in a bit of development, however the interface is simple, effective and elegant (pft! of course)!
[Quick “thanks!” call out to one of my Microsoft colleagues Andrew Cobb for sharing his v1.0 phone app code for me to build on!]
JSON Event / Message
The JSON event being generated by the mobile phone app is intentionally very simple.
{ "DataTypeKey": "+61411143030", "X": -0.12, "Y": 0.63, "Z": -1.67, "G": 3.93 }
At pace the mobile phone app can send 20 events/second registering the X, Y, Z and G of the device in that instant. The event also records the source mobile phone number as the DataTypeKey field (ie the Primary Key). This architecture allows multiple individual devices to send data into Azure and still be uniquely identified.
The event is sent securely over the mobile data network into an Azure IoT Hub (in Azure Melbourne DC) which is configured to only allow connections from specific registered devices.
At full speed the volume of data per device equates to 72K events/hour/device @ 96B/event = 6.6MB/hour/device.
Azure IoT Hub
When an IoT Hub is created you will be provided an endpoint hosted in Azure. This is the target for the JSON events being generated from the mobile phone app.
Azure IoT Hubs are more complex than an Azure Event Hub, perform a lot more device functions and also have stronger security capability. However, operationally they work pretty much the same.
If you want to learn about the differences then this is a great article – https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-compare-event-hubs
Azure Stream Analytics
A Stream Analytics (ASA) job is defined which listens to the IoT Hub message endpoint for new JSON events landing in the hub. As mentioned above, the ASA job scans the input and writes data to 4 outputs based upon set criteria.
For this blog post I’m only going to focus on the output path leading to the Azure Function…
- The ASA job has an input from the IoT Hub where mobile phone app JSON events reside in queue
- The ASA job queries the Hub events for where [G] > 3.00
- Finally the ASA job writes any matched events as JSON line output to a separate Azure Event Hub for additional downstream processing by the Azure Function.
By following a [Iot Hub –> Stream Analytics –> Event Hub] pattern ensures the solution has an asynchronous architecture which allows processing of JSON events to physical phone calls without being heavily coupled to the stream analytics engine itself.
Azure Stream Analytics (ASA) SQL Query Definition…
Azure Function
The Azure Function works by a trigger which is setup to fire when an event lands in the Azure Event Hub. In this case its any event where the [G] was greater than 3. The Azure Function reads the JSON string and creates an outbound Twilio phone call to the phone number listed in the event payload.
Creating the Azure Function
You can create a new Azure Function from the Azure Portal. Search for and create a new “Function App” by specifying the required details. [Not Shown]
Once created browse to the Function App, click the [+] to add a new Function, then select to add a Custom Function.
Select the EventHubTrigger-CSHARP and fill in the details for your trigger.
FYI – the EventHubName (below) is just an internal reference name, and not the actual name of your source Event Hub you are triggering from.
The important part is the actual connection to the source Event Hub where the Function trigger will fire from. Click the [NEW] button to add the Event Hub Connection String that points the Azure Function to the Azure Event Hub.
You can get the Connection String for the Event Hub from the Azure Portal under the Shared Access Policies properties for the Event Hub. [Not Shown]
Finally click [CREATE]
This has now created the Azure Function. We now need to configure it to incorporate the required references to Newtonsoft JSON SDK and Twilio SDK.
As an aside – you can also do fine tuning of the Event Hub Function Trigger by changing the Consumer Group and also the Event Hub Cardinality, which is an indicator if the events in the hub are single atomic messages, or are an array of messages.
I’ve used the $Default Consumer Group on the Azure Event Hub – but ideally you should have your own dedicated consumer group. If you need to learn more about Consumer Group you can see this here – https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-features#event-consumers
For the event hub cardinality the default is single, and my code is based on there being a single event string (not many).
Creating Azure Function References to the Required SDK’s
To reference other assemblies in Azure Functions you need to add a project file to your solution called “project.json” and make the SDK references (in JSON format) in that file. Its pretty simple to do.
We need to add a reference to both Newtonsoft JSON (we’re using 9.0.1) and Twilio (we’re using 4.7.2).
Here’s the JSON of my project.json file so you can just copy/paste.
{ "frameworks": { "net46": { "dependencies": { "Newtonsoft.Json": "9.0.1", "Twilio": "4.7.2" } } } }
NOTE – my c# code is based on the Twilio 4.x SDK. Currently Twilio advise new developments to use the 5.x SDK. There are differences between them so be aware! If moving to 5.x then this could help – https://www.twilio.com/docs/libraries/csharp/migrating-your-csharp-dot-net-application-twilio-sdk-4x-5x
Azure Function c# Code to Call the External Twilio API
Now we can finally put in the c# code!
To add our c# Function code we need to update the run.csx file and paste in the code.
Don’t worry too much about the code for now – I will explain some of the key parts in the Twilio section below, what they mean and how they work. The bits in the c# code that we will need to update from our Twilio account are shown as “<TWILIO HERE>”
#r "System.Data" #r "Newtonsoft.Json" using System; using System.Configuration; using System.Data.SqlClient; using System.Net; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Twilio; public static void Run(string myEventHubMessage, TraceWriter log) { // Variables var accountSid = "<TWILIO ACCOUNT HERE>"; var authToken = "<TWILIO KEY HERE>"; var PhFrom = "<TWILIO PHONE HERE>"; // Twilio's number // get each JSON line from the hub event as there may be multiple events together StringReader strReader = new StringReader(myEventHubMessage); log.Info($"myEventHubMessage: {myEventHubMessage}"); var JSONLine = strReader.ReadLine(); // Get First JSON Line from Event Hub String // Loop through all the JSON events in the Hub Message while (JSONLine != null && JSONLine.Trim() != "") { // get fields from individual JSON event log.Info($"JSONLine: {JSONLine}"); JObject j = JObject.Parse(JSONLine); var PhTo = j["datatypekey"]; var x = j["x"]; var y = j["y"]; var z = j["z"]; var g = j["g"]; // Define the message to be spoken var msgtxt = $"Warning,%20Warning,%20Warning.%20G%20force%20limit%20exceeded.%20Recorded%20Value%20{g}."; log.Info($"msgtxt: {msgtxt}"); // Make a TWILIO call to the operator mobile var url = $"http://twimlets.com/message?Message%5B0%5D={msgtxt}"; // Basic Voice Message //url = url + "&Message%5B1%5D=http://demo.twilio.com/docs/classic.mp3"; // Add Some Dodgy 80's Music to the Message! var twilio = new TwilioRestClient(accountSid, authToken); var options = new CallOptions(); options.Url = url; options.To = PhTo; options.From = PhFrom; var call = twilio.InitiateOutboundCall(options); log.Info($"call.sid: {call.Sid}"); // Get Next JSON Line from Event Hub String JSONLine = strReader.ReadLine(); } }
Twilio
For people who dont know Twilio its a cloud based PAYG service that enables phones, VoIP, and messaging to be embedded into web, desktop, and mobile software. They manage the telecom hardware for you with a 99.95% SLA and expose a globally available cloud API that you (the developer) can interact with to build intelligent and complex communications systems.
- This is their corporate home page – https://www.twilio.com/
- This is a nice summary of what they can do as part of their service – https://www.twilio.com/what-is-cloud-communications
Essentially they can do A LOT – and I recommend reviewing their full capability. However to reduce confusion, for this solution we just need to use the “Programmable Voice” feature to make outbound calls – https://www.twilio.com/voice/features
Twilio Pricing
You can see Australia pricing for Twilio here – https://www.twilio.com/voice/pricing/au
For my solution I selected one of their available landline numbers which is used as the outbound phone number from which my phone calls are routed.
Pricing as at blog writing was…
- $2.50/month for a local phone number
- $0.035/min to make outbound calls from that number
- $0.01/min to receive inbound calls to that number (which I’m not using here)
Creating a Twilio Account and Selecting a Phone Number
To get yourself setup for Twilio, you need to Setup a Trial Account here – https://www.twilio.com/try-twilio
You can learn about the difference between a Trial and Full here – https://support.twilio.com/hc/en-us/articles/223136107-How-does-Twilio-s-Free-Trial-work-
- Trial will give you some free credit – but once used you need to upgrade
- Trial will only give you a single phone number
- If the Trial phone number is unused for more than 30 days, they will remove it
Once registered and you have selected and verified your phone number, then you are ready to go!
For our Azure Function c# code to work you will need to input the details of your Twilio account and phone number into the Azure Function above.
- var accountSid = “<TWILIO ACCOUNT HERE>”;
- var authToken = “<TWILIO KEY HERE>”;
- var PhFrom = “<TWILIO PHONE HERE>”;
You can find this information in your Twilio Console here – https://www.twilio.com/console
About Twilio To and From Phone Number Formats
An important note about all phone numbers in Twilio regardless of where you are calling from or to is that they follow the international standard E.164 and can have a maximum of fifteen digits. If you use the wrong format your code won’t work.
The are usually written as follows: [+][country code][subscriber number including area code]
- +14155552671
- +61411143030 (not +610411143030)
- +442071838750 (not +4402071838750)
You can read about valid number formatting here – https://support.twilio.com/hc/en-us/articles/223183008-Formatting-International-Phone-Numbers
Enabling Geo-Permissions for Phone Numbers
One of the things that tripped me up the first time I used Twilio, was that I didn’t enable my phone for geo-permission calling rights within my country (in this case Australia). I dont know why I had to do this for my own country – after all I had registered an Australian phone number on Twilio!!
Now, just because I am in a rant – even moreso, the setting to enable geo-permissions is buried deep in the menu system in an obscure place. AND…even moreso, there is a setting for both VOICE and SMS! Ensure to set them both.
- VOICE – https://www.twilio.com/console/voice/settings/geo-permissions
- SMS – https://www.twilio.com/console/sms/settings/geo-permissions
Verifying Phone Connectivity Using the Twilio API Explorer
Once all is setup its recommended to test this out to confirm its working within Twilio before you attempt to debug phone problems in your Azure Function c# code.
This is an easy test via the Twilio API Explorer!
In our case we want to create an outgoing programmable voice call – https://www.twilio.com/console/dev-tools/api-explorer/voice/calls/create
You only need to enter 2 fields to test it out;
- TO – The phone number you want to call in E.164 format
- URL – A call command string. You can use this sample one I’ve created here – simply cut/paste this into the URL box – http://twimlets.com/message?Message%5B0%5D=You%20have%20received%20a%20call%20from%20Mr%20Fox%20SQL!&
Once done – scroll down and click [MAKE REQUEST]
This will send the call request to the API and if it works you will see a response in the right panel like this below – and then in about 5 sec you will receive a phone call from the number you registered with a spoken voice message
However if this is not working – then you need to go back and confirm you have everything setup as per the above – and you have verified your phone numbers too.
Using Twilio Twimlets – Customising Your Interactions!
Now you may be wondering how I got that spoken message above to work?
“You have received a call from Mr Fox SQL!“
This is a great feature in Twilio which gives the ability to create a “command string” to be sent as part of the voice call which can do some amazing things – these are called TWIMLETS. This feature provides the phone commands in the form of a URL.
You can see the information about what Twimlets are and how to use them here – https://www.twilio.com/labs/twimlets
In the Azure Function c# code the call from Twilio will create a voice message with a custom “SAY” command specific to G-Force value present in the JSON Event. In this case I am using the Simple Message Twimlet here – https://www.twilio.com/labs/twimlets/message
The Simple Message Twimlet web page has a nice URL generator which you simply enter the text you want Twilio to SAY and it will provide you back the fully coded URL. You can simply cut and paste that URL into your Azure Function code – and you’re done!
Twimlets are super cool – I encourage you to try it out with your own combinations including… voice, music, menu systems, call backs, conferences, hold music… and more!
Summary
So there you have it – an easy method to make an external outbound phone call from a JSON message payload sent to an Azure IoT Hub! This solution can be easily customised to create any number of phone combinations using the incredible Twilio services right in Azure. (see below for project idea!)
If you want to learn more, then Microsoft have helpful documentation showing how to use Twilio for voice and SMS capabilities from Azure – https://docs.microsoft.com/en-us/azure/twilio-dotnet-how-to-use-for-voice-sms
And so – Call your friends, or call your non-friends, but regardless – Have Fun!
As per my usual disclaimer – ensure that you give the above a test as your milage may vary!
Where Can I Learn More About Streaming Data?
There’s stacks of resources, solutions and demos out there – and below are some click-once prebuilt solutions that will deploy to your Azure Subscription which you can then look at in detail. Then below is also some Free edX self-paced courses which bring you through setting up streaming solutions on Azure.
Cortana Intelligence Gallery Pre-Built Solutions (one-click deploy)
- Vehicle Telemetry – https://gallery.cortanaintelligence.com/Solution/Telemetry-Analytics
- Personalised Offers – https://gallery.cortanaintelligence.com/Solution/Personalized-Offers-2
- Energy Demand Forecasting – https://gallery.cortanaintelligence.com/Solution/Demand-Forecasting-3
EdX Self-Paced Courses (3-4 hrs/week for ~4 weeks)
- Developing IoT Solutions with Azure IoT – https://www.edx.org/course/developing-iot-solutions-azure-iot-microsoft-dev225x
- Processing Real-Time Data Streams in Azure – https://www.edx.org/course/processing-real-time-data-streams-azure-microsoft-dat223-2x-0
- Orchestrating Big Data with Azure Data Factory – https://www.edx.org/course/orchestrating-big-data-azure-data-microsoft-dat223-3x-0
Future Project – Building a Generic Phone Solution
There’s some pretty easy ways to change the code and make it more generic for any end user phone messaging purposes just by changing the JSON Event structure as per the below and making some code changes to Azure Stream Analytics (ASA)….
- PhoneID = the ID of the target device. Create a JSON Reference Data file containing the definitive list of Phone Devices (ID + Phone Number) and then use this to join to the data stream in the Azure Stream Analytics job. This will give you the Phone Number to be called.
- MessageID = the ID of the Voice/SMS Message. Create a JSON Reference Data file containing the definitive list of Messages (ID + Message) and then use this to join to the data stream in the Azure Stream Analytics job. This will give you the Voice/Text Messages to be spoken or sent.
- CommID = an indicator of how the message is communicated to the device. It could simply be VOICE = 1, TEXT (SMS) = 2, BOTH = 3
{ "PhoneID": 27, "MessageID": 14, "CommID": 1 }
To learn more about how to do this in ASA
- This explains how ASA Reference Data files work – https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-use-reference-data
- And this shows you how to create the ASA Reference Data Joins in your ASA SQL Query Code – https://msdn.microsoft.com/library/azure/dn949258.aspx
So with this generic architecture you can actually make a simple but effective generic Azure Phone Communication solution that takes a modified JSON Event structure into Event Hub, and have an Azure Function call/SMS the number !
A project for another time perhaps!
Disclaimer: all content on Mr. Fox SQL blog is subject to the disclaimer found here