Test Call, using Cron Job and PHPAGI, almost there a few Q's


#1

We’re trying to setup Zabbix to monitor whether or not Asterisk/FreePBX is up and running I’ve already got several tests going which report the number of registered SIP and IAX2 trunks, number of active calls, whether or not the service itself is running, and even a test call out to a google voice number to make sure that our outgoing phone calls are working. But I’ve also been asked to make sure that we can monitor whether or not we’re able to receive calls and make sure that the call quality is good enough to get proper DTMF tones.

I wrote/put together 2 bash and 2 AGI scripts that seem to do what I need them to do seperately, but now comes the tough part of making them work togeter.

The first bash and agi together place an outgoing call from our main line and press 9638.

TestCallInDialer.sh

#!/bin/bash
DATE=`date +%d%m%Y-%H%M`
FILENAME=Incoming-"$DATE".call
echo "Channel: Local/4567890123@from-internal" >> /tmp/$FILENAME
echo "Application: AGI" >> /tmp/$FILENAME
echo "Data: TestCallDialer.agi" >> /tmp/$FILENAME
echo "MaxRetries: 2" >> /tmp/$FILENAME
echo "RetryTime: 30" >> /tmp/$FILENAME
echo "Priority: 1" >> /tmp/$FILENAME
echo "Archive: Yes" >> /tmp/$FILENAME
chmod 777 /tmp/$FILENAME
mv /tmp/$FILENAME /var/spool/asterisk/outgoing/
# Uncomment these once Receiver is called from the dial plan to send the data to the zabbix server
#
# sleep 30
# Sends Digits
# DIGITS=`cat /tmp/agitests.log|awk '{print $1}'`
# echo $DIGITS
# /etc/zabbix/./zabbix_sender -z [zabbix server ip] -p 10051 -s [hostname] -k asterisk.testcallindigits -o $DIGITS
# sleep 0.1
# Sends whether the call was successful
# SUCCESS=`cat /var/spool/asterisk/outgoing_done/$FILENAME |grep Status:|awk '{print $2}'`
# echo $SUCCESS
# /etc/zabbix/./zabbix_sender -z [zabbix server ip] -p 10051 -s [hostname] -k asterisk.testcallinsuccess -o $SUCCESS
rm /var/spool/asterisk/outgoing_done/$FILENAME

TestCallDialer.agi

<?php
ini_set('display_errors', 1);
set_time_limit(30);
require('phpagi.php');
error_reporting(E_ALL);

  $agi = new AGI();
  $agi->answer();

  $agi->verbose("before dtmf",3);
  $agi->exec("sendDTMF","w9638");
  $agi->verbose("after dtmf",3);

  // $agi->hangup();
?>

The second bash script and agi receive dtmf tones and write them to /tmp/agitests.log

TestCallInReceiver.sh

#!/bin/bash
# Once TestCallInReceiver is added to the dialplan don't use this batch script except for testing.
DATE=`date +%d%m%Y-%H%M`
FILENAME=Incoming-"$DATE".call
echo "Channel: Local/4567890123@from-internal" >> /tmp/$FILENAME
echo "Application: AGI" >> /tmp/$FILENAME
echo "Data: TestCallReceiver.agi" >> /tmp/$FILENAME
echo "MaxRetries: 2" >> /tmp/$FILENAME
echo "RetryTime: 30" >> /tmp/$FILENAME
echo "Priority: 1" >> /tmp/$FILENAME
echo "Archive: Yes" >> /tmp/$FILENAME
chmod 777 /tmp/$FILENAME
mv /tmp/$FILENAME /var/spool/asterisk/outgoing/
sleep 30
# Sends Digits
DIGITS=`cat /tmp/agitests.log|awk '{print $1}'`
/etc/zabbix/./zabbix_sender -z [zabbix server ip] -p 10051 -s [hostname] -k asterisk.testcallindigits -o $DIGITS
# Sends whether the call was successful
SUCCESS=`cat /var/spool/asterisk/outgoing_done/$FILENAME |grep Status:|awk '{print $2}'`
/etc/zabbix/./zabbix_sender -z [zabbix server ip] -p 10051 -s [hostname] -k asterisk.testcallinsuccess -o $SUCCESS
rm /var/spool/asterisk/outgoing_done/$FILENAME

TestCallReceiver.agi

#!/usr/bin/php
<?php
/*
This script answers the call and prompts for an extension, waits 5 seconds for your input and hangs up.
*/
$debug_mode = false; //debug mode writes extra data to the log file below whenever an AGI command is executed
$log_file = '/tmp/agitest.log'; //log file to use in debug mode
$allowed_ext = array('1234', '0'); //who's allowed to access this script

//Get the AGI variables; I modified the script not to check caller ID of the tester and shouldn't be necessary, but I had problems when I removed it, so I'll leave it in.
$agivars = array();
while (!feof(STDIN)) {
        $agivar = trim(fgets(STDIN));
        if ($agivar === '') {
                break;
        }
        else {
                $agivar = explode(':', $agivar);
                $agivars[$agivar[0]] = trim($agivar[1]);
        }
}
foreach($agivars as $k=>$v) {
        log_agi("Got $k=$v");
}
extract($agivars);

//Prompt for 4 digits
$ext = '';
$result = execute_agi('STREAM FILE please-enter-the "0123456789"');
if ($result['result'] == 0) {
        $result = execute_agi('STREAM FILE users "0123456789"');
        if ($result['result'] == 0) {
                //they haven't entered anything yet
                $result = execute_agi("GET DATA extension 5000 4");
                if ($result['result'] > 0) {
                        $ext = $result['result'];
                }
        }
        else {
                $ext = chr($result['result']);
        }
}
else {
        $ext = chr($result['result']);
}

//we haven't got 4 digits yet
if (strlen($ext) < 4) {
        //still no input after GET DATA timeout
        if (empty($ext)) {
                execute_agi('STREAM FILE please-enter-the ""');
                execute_agi('STREAM FILE users ""');
                execute_agi('STREAM FILE extension ""');
        }
        //we got a single digit during playback of 'please enter the' or 'users'
        while (strlen($ext) < 4) {
                $result = execute_agi('WAIT FOR DIGIT -1');
                //look for digits only
                if ($result['result'] >= 48 && $result['result'] <= 57) {
                        $ext .= chr($result['result']);
                }
                //ignore * or # (or a, b, c, d)
                else {
                        continue;
                }
        }
}
//log_agi("Got extension $ext");

//Writing the digits to /tmp/agitests.log shouldn't be necessary.
$fp = fopen('/tmp/agitests.log', 'w');
fwrite($fp, $ext);
fclose($fp);

//Say back the extension; not neccesary for our testing, but might come in handy for troubleshooting..
//execute_agi('STREAM FILE you-entered ""');
//execute_agi("SAY DIGITS $ext \"\"");
//execute_agi('STREAM FILE goodbye ""');

//Hangs up the Calls
execute_agi('HANGUP');

exit;


//Executes the AGI Commands
function execute_agi($command) {
        global $debug_mode, $log_file;

        fwrite(STDOUT, "$command\n");
        fflush(STDOUT);
        $result = trim(fgets(STDIN));
        $ret = array('code'=> -1, 'result'=> -1, 'timeout'=> false, 'data'=> '');
        if (preg_match("/^([0-9]{1,3}) (.*)/", $result, $matches)) {
                $ret['code'] = $matches[1];
                $ret['result'] = 0;
                if (preg_match('/^result=([0-9a-zA-Z]*)\s?(?:\(?(.*?)\)?)?$/', $matches[2], $match))  {
                        $ret['result'] = $match[1];
                        $ret['timeout'] = ($match[2] === 'timeout') ? true : false;
                        $ret['data'] = $match[2];
                }
        }
        if ($debug_mode && !empty($logfile)) {
                $fh = fopen($logfile, 'a');                if ($fh !== false) {
                        $res = $ret['result'] . (empty($ret['data']) ? '' : " / $ret[data]");
                        fwrite($fh, "-------\n>> $command\n<< $result\n<<     parsed $res\n");
                        fclose($fh);
                }
        }
        return $ret;
}

//AGI Debugger
function log_agi($entry, $level = 1) {
        if (!is_numeric($level)) {
                $level = 1;
        }
        $result = execute_agi("VERBOSE \"$entry\" $level");
}
?>

From what I’ve been reading I believe that I should be able to just call the TestCallReceiver.agi from the dialplan and eliminate the batch script. Unfortunately I’m not very familiar with the dialplan and am a bit hesitant to touch it because this is a production server. Right now I haven’t tested to make sure that they’ll work together, but I’ve tested them with my cell phone and it appears that they both work. The dialer will call me and enter DTMF tones, the Receiver will call me, ask for DTMF tones, and record them to the log file which we will be monitoring with Zabbix. If anyone has some insight on how to make these scipts work together or an idea of where I should be looking I’d greatly appreciate it.


#2

Ok you only need a cronjob for the call file the other will execute via dialplan:

for example:

the cron job will move this call file:

Channel: Local/9876@music MaxRetries: 0 RetryTime: 15 WaitTime: 15 Application: AGI Data: test.agi

The Agi test is:

[code]#!/usr/bin/php -q

<?php ini_set('display_errors', 1); set_time_limit(30); require('phpagi/phpagi.php'); error_reporting(E_ALL); $agi = new AGI(); $agi->answer(); $agi-> exec("sendDTMF","w987#"); 'w is for wait .5 secs and the # is for terminate the password lenght $agi->exec("echo",""); // $agi->hangup(); ?>[/code]

In the dialplan at context music you have:

[music] exten => 9876,1,Answer() same => n,Authenticate(987) same => n,Agi(test2.agi) same => n,hangup()

And finally the test2 AGI file contains your routine for write into your logs, exmaple:

[code]#!/usr/bin/php -q

<?php ............. exec("echo 'its entered a valid password' >> yourlog.txt") ............... ?>

[/code]

Even I think you can run the second AGI directly and within request the dtmf code with get_data function and write the recieved data to your log.


#3

Hi
you don’t even need an agi , all this can be accomplished using the dialplan. Just the cronjob to move the call file.

Ian


#4

[quote=“ianplain”]Hi
you don’t even need an agi , all this can be accomplished using the dialplan. Just the cronjob to move the call file.

Ian[/quote]

Sure its truth, maybe someting like:

call file:

Channel: Local/2222@test MaxRetries: 0 RetryTime: 15 WaitTime: 15 Application:SendDTMF Data: w7898#

[test] exten => 2222,1,Answer() exten => 2222,n,Read(digits,,4) exten => 2222,n,GotoIf($["${digits}" == "7898"]?ok:hangup) exten => 2222,n(ok),System(echo "I got this ${digits}" > /root/mylog.txt) exten => 2222,n,Hangup() exten => 2222,n(hangup),System(echo "The digits ${digits} are wrong" > /root/mylog.txt) exten => 2222,n,Hangup()


#5

Here we go. Nice and simple.

Context on sending server-------------------------

[code][calltest]

exten => 123,1,Noop(callfile test)
exten => 123,n,Dial(${TRUNK1}/01234561234|10)
exten => 123,n,Noop(The Call was ${DIALSTATUS})
exten => 123,n,System(/usr/local/sbin/calltest.sh FAIL)
exten => 123,n,Hangup()

exten => 321,1,Noop(callfile test)
exten => 321,n,Answer()
exten => 321,n,WaitExten(60) ; Record(/tmp/testcall.wav)
exten => 321,n,Noop(I had no digits)
exten => 321,n,Hangup()

exten => 1234,1,Noop(I heard that and alls OK)
exten => 1234,n,System(/usr/local/sbin/calltest.sh OK)
exten => 1234,n,Record(/tmp/monkey.wav)
exten => 1234,n,Hangup()

exten => i,1,System(/usr/local/sbin/calltest.sh FAIL)
exten => i,n,Hangup()[/code]

callfile on sending server a cron job copies this to a new name and then moves it--------------

Channel: Local/123@calltest/n WaitTime: 30 RetryTime: 30 MaxRetries: 1 Context: calltest Extension: 321 Priority: 1 Account: calltest

cronjob file--------

#! /bin/sh /bin/cp /root/callfile /root/call /bin/chown asterisk:asterisk /root/call /bin/mv /root/call /var/spool/asterisk/outgoing/call

context on receiving server

[testing] ; we receive a ddi call to 427999 exten => 427999,1,Noop(test call incoming) exten => 427999,n,Playback(welcome) exten => 427999,n,SendDTMF(1234ww) exten => 427999,n,Playback(welcome) exten => 427999,n,Hangup()


#6

Hi,

Simple use the AMI interface to know the Asterisk is running or not. Through AMI you will get all the events of live call status and SIP and IAX register/Unregister and many more…

Cheers…

Regards,

Ketan


#7

Hi

Yes ami does tell you that , and we have custom nagios pluging to check sip peer status ISDN status etc. This script was developed for a customer to test full functionality of the line end to end. IE can it receive a call and interact by dialing digits and what the quality is like.

Ian


#8

We Use Nagisk with Icinga and NagiosQL to check the pbx and extensions state.