TaCode Tuesdays: Make Your Own Call and SMS Monitoring Tool Using Zang

Posted by Pedram Mohammadi on January 17, 2017

Finally, your call and SMS application is launched. After a lot of overtime, countless cups of coffee, and arduous arguments with quality control, people have actually started using it. The next question now is: how do you make sure the lights are green?  

TACODE TUESDAYS: MAKE YOUR OWN CALL AND SMS MONITORING TOOL USING ZANG  |  http://blog.zang.io/topic/tacode-tuesday

There are many reasons why your SMS and calls fail  – it could be your content structure, encoding, or number validity. But before you can perform a root cause analysis of your dwindling performance, you must first know that there is something wrong. How? Through a call and SMS monitoring tool.

In this week’s TaCode Tuesday, we will teach you how to create your own call and SMS monitoring tool from scratch using Zang APIs. We will create a simple algorithm to compute call and SMS performances based on attributes derived from JSON responses so that you can create a real-time report. We will use the principle behind Control Charts as a visual tool to display in real time the quality of SMS and calls that your application makes.

A Six Sigma tool, Control Charts enables monitoring of process stability and control. Its chart is composed by an Upper Control Limit (UCL), Center and Lower Control Limit (LCL). An Upper Control Limit pertains to data points that are above the average line; on the other hand, the Lower Control Limit pertains to data points that fall below the average line. We can use the same principle of control charts in determining notification triggers every time significant sets of call or SMS data fall below our expected performance.

Before we start developing a call and SMS monitoring tool, here are some basic requirements:

  • Intermediate knowledge of:
    • PHP
    • SQL Lite
    • HTML
    • CSS
  • Working knowledge of Zang APIs
  • Zang subscription

 

Step 1: Fetch these Call and SMS API attributes and store in a database

Call Attributes

  • Direction: The direction of the call from the perspective of TelAPI. "inbound" for calls to TelAPI, "outbound-api" for calls from the TelAPI via REST request, or "outbound-dial" for calls from TelAPI via InboundXML.
  • From: The number that initiated the call.
  • To: The number that was called.
  • Timeout: Number of seconds a call stays on line while waiting for an answer. The max time limit is 999.
  • Status: The status of the call: queued, ringing, in-progress, completed, failed, busy, no-answer.

 

SMS Attributes

  • Direction: Specifies the direction of the SMS: messages from REST API are “outbound-api,” messages from incoming phone numbers to TelAPI are “incoming,” messages from InboundXML initiated during an outbound call are “outbound-call,” and messages from InboundXML initiated via an sms reply are “outbound-reply.”
  • To: The number that received the SMS message.
  • From: The number that sent the SMS message.
  • Status: Status of the SMS: sent, sending, queued, or failed.
  • date_created - The date the SMS resource was created.
  • date_updated - The date the SMS resource was last updated.
  • date_sent - The date the SMS was sent.

 

Step 1.1 Fetch Call Attributes

//Call the Zang List Call Api

<?php

$data = array("To" => "+639173893535",

"From" => "+639157852930",

"Status"=>"completed",

"StartTime"=>"2016-02-23",

"Page"=>"1",

"PageSize"=>"10");                                                                    

$data_string = json_encode($data);                                                                                   

                                                                                                                    

$ch = curl_init('https://api.zang.io/v2/Accounts/:AccountSid/Calls.json');

curl_setopt($ch, CURLOPT_USERPWD, {AccountSid} . ":" . {AuthToken});

curl_setopt($ch, CURLOPT_TIMEOUT, 30);

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     

curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                  

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      

curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          

   'Content-Type: application/json',                                                                                

   'Content-Length: ' . strlen($data_string))                                                                       

);                                                                                                                   

                                                                                                                    

$result = curl_exec($ch);

Step 1.2 Implement JSON parser to the call attributes

//.... implement JSON parser

curl_close($result);

?>

 

//Example JSON results

{

 "page": 0,

 "num_pages": 29,

 "page_size": 50,

 "total": 1454,

 "start": 0,

 "end": 49,

 "uri": "/v2/Accounts/{AccountSid}/Calls.json",

 "first_page_uri": "/v2/Accounts/{AccountSid}/Calls.json?Page=0&PageSize=50",

 "previous_page_uri": null,

 "next_page_uri": "/v2/Accounts/{AccountSid}/Calls.json?Page=1&PageSize=50",

 "last_page_uri": "/v2/Accounts/{AccountSid}/Calls.json?Page=28&PageSize=50",

 "calls": [

 

   {

   "sid": "{CallSid}",

   "date_created": "Fri, 27 Jul 2012 15:52:02 +0000",

   "date_updated": "Fri, 27 Jul 2012 15:52:11 +0000",

   "parent_call_sid": "",

   "account_sid": "{AccountSid}",

   "to": "+12015554992",

   "from": "Restricted",

   "phone_number_sid": "{phone_number_sid}",

   "status": "completed",

   "start_time": "Fri, 27 Jul 2012 15:52:02 +0000",

   "end_time": "Fri, 27 Jul 2012 15:52:11 +0000",

   "duration": "9",

   "price": "0.020000",

   "direction": "inbound",

   "answered_by": "None",

   "api_version": "v2",

   "forwarded_from": "",

   "p_asserted_identity": "",

   "sip_privacy": "",

   "privacy_hide_number": "False",

   "uri": "/v2/Accounts/{AccountSid}/Calls/{CallSid}.json",

   "subresource_uris": {

       "notifications": "/v2/Accounts/{AccountSid}/Calls/{CallSid}/Notifications.json",

       "recordings": "/v2/Accounts/{AccountSid}/Calls/{CallSid}/Recordings.json"

       }

   },

   {

   "sid": "{CallSid}",

   "date_created": "Fri, 27 Jul 2012 15:51:57 +0000",

   "date_updated": "Fri, 27 Jul 2012 15:52:09 +0000",

   "parent_call_sid": "",

   "account_sid": "{AccountSid}",

   "to": "+12015554992",

   "from": "+17325551234",

   "phone_number_sid": "{phone_number_sid",

   "status": "completed",

   "start_time": "Fri, 27 Jul 2012 15:52:03 +0000",

   "end_time": "Fri, 27 Jul 2012 15:52:09 +0000",

   "duration": "6",

   "price": "0.066000",

   "direction": "outbound-dial",

   "answered_by": "None",

   "api_version": "v2",

   "forwarded_from": "",

   "p_asserted_identity": "",

   "sip_privacy": "None",

   "privacy_hide_number": "False",

   "uri": "/v2/Accounts/{AccountSid}/Calls/{CallSid}.json",

   "subresource_uris": {

       "notifications": "/v2/Accounts/{AccountSid}/Calls/{CallSid}/Notifications.json",

       "recordings": "/v2/Accounts/{AccountSid}/Calls/{CallSid}/Recordings.json"

       }

   }

 

   ...

 

   ]

}    

 

Step 1.3 Convert the JSON string to Object and store in the database

//Implememt JSON parser

<?php

// Convert JSON string to Object

 $someObject = json_decode($someJSON);

 print_r($someObject);      // Dump all data of the Object

 echo $someObject[0]->from; // Access Object data

 

//Accessing Object Data for call attributes

$m_direction ='';

$m_status = 'completed';

 

$m_from = $someObject[0]->from;

$m_to   = $someObject[0]->to;

$m_duration = $someObject[0]->duration;

//$someObject[0]->status;

 

//insert call attributes into the database

 

$sql = "INSERT INTO table_name (id,direction,status,from,to,duration)

VALUES (NULL,$m_direction,$m_status,$m_from,$m_to,$m_duration);";

 

$servername = "localhost";

$username = "username";

$password = "password";

$dbname = "myDB";

 

// Create connection

$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection

if ($conn->connect_error) {

   die("Connection failed: " . $conn->connect_error);

}

 

if ($conn->query($sql) === TRUE) {

   echo "New record created successfully";

} else {

   echo "Error: " . $sql . "<br>" . $conn->error;

}

 

$conn->close();

 

?>

Step 1.4 Fetch SMS attributes

//Call the Zang List SMS Api

<?php

$data = array("To" => "+639173893535",

"From" => "+639157852930"

"DateSent"=>"2016-02-23",

"Page"=>"1",

"PageSize"=>"10");                                                                    

$data_string = json_encode($data);                                                                                   

                                                                                                                    

$ch = curl_init('https://api.zang.io/v2/Accounts/:AccountSid/SMS/Messages.json');

curl_setopt($ch, CURLOPT_USERPWD, {AccountSid} . ":" . {AuthToken});

curl_setopt($ch, CURLOPT_TIMEOUT, 30);

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     

curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                  

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      

curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          

   'Content-Type: application/json',                                                                                

   'Content-Length: ' . strlen($data_string))                                                                       

);                                                                                                                   

                                                                                                                    

$result = curl_exec($ch);

//.... implement JSON parser

curl_close($result);

?>

 

//Example JSON results

{

   "page": 0,

   "num_pages": 8 ,

   "page_size": 50,

   "total": 433,

   "start": 0,

   "end": 49,

   "uri": "/v2/Accounts/{AccountSid}/SMS/Messages.json",

   "first_page_uri": "/v2/Accounts/{AccountSid}/SMS/Messages.json?Page=0&PageSize=50",

   "previous_page_uri": null,

   "next_page_uri": "/v2/Accounts/{AccountSid}/SMS/Messages.json?Page=1&PageSize=50",

   "last_page_uri": "/v2/Accounts/{AccountSid}/SMS/Messages.json?Page=7&PageSize=50",

   "sms_messages": [

 

   {

   "api_version": "v2",

   "sid": "{SmsSid}",

   "account_sid": "{AccountSid}",

   "date_created": "Fri, 27 Jul 2012 13:32:42 +0000",

   "date_updated": "Fri, 27 Jul 2012 13:32:42 +0000",

   "date_sent": "Fri, 27 Jul 2012 13:32:42 +0000",

   "to": "+17325551234",

   "from": "+14245551234",

   "body": "Hi, this is an SMS",

   "status": "sent",

   "direction": "outbound-api",

   "price": "0.070000",

   "uri": "/v2/Accounts/{AccountSid}/SMS/Messages/{SmsSid}.json"

   }

,

   {

   "api_version": "v2",

   "sid": "{SmsSid}",

   "account_sid": "{AccountSid}",

   "date_created": "Fri, 27 Jul 2012 13:31:43 +0000",

   "date_updated": "Fri, 27 Jul 2012 13:31:45 +0000",

   "date_sent": "Fri, 27 Jul 2012 13:31:44 +0000",

   "to": "+17325551234",

   "from": "+14245551234",

   "body": "test message",

   "status": "sent",

   "direction": "outbound-api",

   "price": "0.070000",

   "uri": "/v2/Accounts/{AccountSid}/SMS/Messages/{SmsSid}.json"

   }

 

   ...

 

   ]

}       

 

Step 1.5 Implement JSON parser to the SMS attributes

//Implememt JSON parser

<?php

// Convert JSON string to Object

 $someObject = json_decode($someJSON);

 print_r($someObject);      // Dump all data of the Object

 echo $someObject[0]->from; // Access Object data

 

//Accessing Object Data for call attributes

$m_direction ='';

$m_status = 'completed';

 

$m_from = $someObject[0]->from;

$m_to   = $someObject[0]->to;

Step 1.6 Convert the JSON string to Object and store to the database

//insert sms attributes into the database

 

$sql = "INSERT INTO {table_name} (id,direction,status,from,to,duration,timeout)

VALUES (NULL,$m_direction,$m_status,$m_from,$m_to, $someObject[0]->date_created, $someObject[0]->date_updated,$someObject[0]->date_sent,$someObject[0]->timeout);";

 

$servername = "localhost";

$username = "username";

$password = "password";

$dbname = "myDB";

 

// Create connection

$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection

if ($conn->connect_error) {

   die("Connection failed: " . $conn->connect_error);

}

//store values fetch into db table

if ($conn->query($sql) === TRUE) {

   echo "New record created successfully";

} else {

   echo "Error: " . $sql . "<br>" . $conn->error;

}

 

$conn->close();

 

?>

 

Step 2: Create performance measurement backend logic using PHP

We will create performance measurement algorithms for SMS and calls through the use of certain attributes that we initially stored in the database and eventually push them to display on a simple chart.

 

Step 2.1 Determine SMS Performance

To determine SMS performance, we will use these attributes that we initially saved in the database:

Screen Shot 2017-01-17 at 9.27.49 PM.png

Use these attributes to compute the time it takes for a SMS to be sent. The performance measurement process flow below basically tells how your backend logic could do this. After sending an outbound SMS and storing its attributes, select for date_created and date_sent and compute their difference. The output will be categorized to belong in the upper, center, and lower control limits and eventually pushed to display on the site.

Screen Shot 2017-01-17 at 9.34.35 PM.png

Step 2.1.1 Create a threshold for your SMS sending duration to identify if it is within the upper, center, or lower control limits. For this tutorial, let’s say that when an SMS is sent within 1-10 seconds, it is within the center control limit. However, if the SMS is sent in 11 seconds and beyond, it is outside the control limit. If the SMS is sent less than one second, it will be placed in the upper control limit. Configure your limits depending on the performance baseline of your organization.

 

<?php

//where $control_limit is the threshold

if ($m_row-> timdediff <= $control_limit ) { //10 seconds below

// plot chart dot into the center graph

} else if ($m_row-> timdediff >= $control_limit) // 11 seconds above

         //plot chart dot below the center graph

} else { // assume less than a second

     // plot chart dot upper the center graph

}

?>

Step 2.1.2 Compute for the difference between date_created and date_sent and categorize it to fall within the upper, center, or lower control limit.

//compute time diff

//get the values from the parse JSON items

 

$time_limit = 10;//example desired

$sql = "select datecreated,datasent from {tbl_name}";

$result = mysqli_query($sql,$m_connect) or die(mysql_error());

$row = mysqli_fetch_object($result);

 

$row->datecreated //"Fri, 27 Jul 2012 13:32:42 +0000"

$row->datasent //"Fri, 27 Jul 2012 13:32:42 +0000"

 

$m_datecreated = new DateTime($row->datecreated); // example datecreated

$m_datesent = new DateTime($row->datesent);

 

$m_timdediff = $m_datesent->diff($m_datecreated);

 

$m_interval = $m_timediff->formal(dMy);

 

if ($m_interval < $time_limit) {

//display date point

}

else {

//display data point

}

 

//alternative function for getting time difference

function timeDiff($firstTime,$lastTime)

{

  // convert to unix timestamps

  $firstTime=strtotime($firstTime);

  $lastTime=strtotime($lastTime);

 

  // perform subtraction to get the difference (in seconds) between times

  $timeDiff=$lastTime-$firstTime;

 

  // return the difference

  return $timeDiff;

}

//Usage :

$difference = timeDiff("2002-03-16 10:00:00",date("Y-m-d H:i:s"));

$years = abs(floor($difference / 31536000));

$days = abs(floor(($difference-($years * 31536000))/86400));

$hours = abs(floor(($difference-($years * 31536000)-($days * 86400))/3600));

$mins = abs(floor(($difference-($years * 31536000)-($days * 86400)-($hours * 3600))/60));#floor($difference / 60);

echo "<p>Time Passed: " . $years . " Years, " . $days . " Days, " . $hours . " Hours, " . $mins . " Minutes.</p>";

 

Step 2.2 Determine Call Performance

Determining call performance is much the same like SMS; however, rather than computing for time it takes to send, we will just fetch the timeout attribute from the database.

 

Figure 3: Attributes determining call performance

 

The process flow is almost similar to SMS – just replace the date computations with the timeout attribute.

Figure 4: Call Performance Measurement Process Flow

 

Step 2.2.1 Create a threshold for call timeout to identify if it is within or outside the control limits. For this tutorial, let us say that when timeout is within 1-30 seconds, it is within the control limit. However, if the call is sent in 31 seconds and beyond, it is outside the control limit. If the call connects less than one second and below it is within the upper control limit.

<?php

//where $control_limit is the threshold

if ($m_row->timeout <= $control_limit ) { //30 seconds below

// plot chart dot into the center graph

} else if ($m_row->timeout >= $control_limit) // 31 seconds above

         //plot chart dot below the center graph

} else { // assume less than a second

     // plot chart dot upper the center graph

}

?>

Step 3: The last step is to create a chart that will display your call and SMS performance result. We can use a simple HTML5 and PHP for this; though you may opt to put in some fancy CSS most especially if the report will also be accessible to management. You can also put in some notifications every time data points fall within the lower control limits. Notifications should be triggered by a bulk of call and SMS attributes that fall below the LCL. Below is a sample code for the SMS chart:

<?php

require_once 'phplot.php'; // Open source library for creating plots

 

// Array of custom labels for the Y axis. See the get_label callback.

$y_labels = array("", "Upper Limit", "Center Limit ", "Lower Limit");

 

// Return the string for a Y label:

function get_label($value, $labels)

{

   if (isset($labels[(int)$value])) return $labels[(int)$value];

   return $value;

}

 

//    <=12    13-17   17-28   30-39   40-54    >=55

 

$data = array(

   array('UCL', 1,   1, 2,   2, 4,   3, 3,   4, 3,   5, 5,   6, 6),

   array('LCL',  20,   1, 9,   2, 7,   3, 4,   4, 7,   5, 3,   6, 7),

    array('SMS',  2,   1, 9,   2, 7,   3, 4,   4, 7,   5, 3,   6, 7)

);

$plot = new PHPlot(600, 600);

$plot->SetTitle("Call/SMS Control Chart");

$plot->SetDataType('data-data-xyz');

$plot->SetDataValues($data);

$plot->SetPlotType('bubbles');

$plot->SetDataColors('yellow'); // Use same color for all data sets

$plot->SetDrawPlotAreaBackground(True);

$plot->SetLightGridColor('red'); // Change grid color to make it visible

$plot->SetImageBorderType('plain');

$plot->SetPlotBorderType('full');

$plot->SetXTickIncrement(1); // For grid line spacing

$plot->SetYTickIncrement(1);

$plot->SetPlotAreaWorld(0, 0, 6.5, 6.5);

// Establish the handler for the Y label text:

$plot->SetYLabelType('custom', 'get_label', $y_labels);

$plot->SetXTickPos('both'); // Tick marks on both sides

$plot->SetYTickPos('both'); // Tick marks on top and bottom too

$plot->SetXDataLabelPos('both'); // X axis data labels top and bottom

$plot->SetYTickLabelPos('both'); // Y axis labels left and right

$plot->SetDrawXGrid(True);

$plot->DrawGraph();

?>

Finally, were done! This SMS and call monitoring tool is not only useful to track the performance of your call and SMS solutions but also the success rate of your marketing campaigns. For example, every time SMS falls below the LCL it could mean that delivery has failed. There could be a couple of reasons for this- a wrong number, filtered content, unacceptable sender ID, or your message is too long that it can no longer be supported.

Building your own call and SMS monitoring tool on Zang is simple. Click the button to sign up for free today.  

Start building on Zang




Topics: Ideas, TaCode Tuesday, cPaaS