Sending missed call notifications from Asterisk

    In this post I will tell you about the possibilities of sending notifications of missed calls using Asterisk. I will try to give simple configuration examples and expand on this topic in more detail, then you can experiment at your discretion or needs. Asterisk offers quite wide opportunities for solving various problems, therefore the same task can be solved in different ways, the main result is the stable operation of your services.

    Sending a missed call report by email



    What we have:
    Incoming multi-channel line with the number +7 (495) 1234567, IVR, 4 operators in the call queue.

    Tasks:
    1. Send a report on a missed call, indicating the caller’s number, time of receipt of the call and waiting time on the line.
    2. If the subscriber waited on the line for more than 10 seconds and for some reason hung up the phone without waiting for the operator to answer, we send a report on the missed call.
    3. Enter in the database (in the current MySQL example) data on which operator in the queue answered the call and fix the time at which the conversation was completed.



    As a solution, I will give an example configuration (one of the possible solutions), with comments on the most interesting moments in my opinion.
    This is how the IVR configuration of working hours + call queues looks like:

    [globals]
    CIDFILE=/etc/asterisk/inc-calls/call-noanswer
    SQLHOST=db.domain.ru
    SQLUSER=asterisksql
    SQLPASS=Gt6Rju8FkS
    SQLDB=asteriskdb
    IVRWORK=custom/IVR_company_wav
    [incoming-74951234567]
    exten => h,1,Set(WAITTIME=10)
    exten => h,n,Set(CTALL=$[${CDR(duration)}])
    exten => h,n,Set(CTANSWER=$[${CDR(billsec)}])
    exten => h,n,Set(CTDTIME=$[${CTALL}-${CTANSWER}])
    exten => h,n,NoOP(${CDR(disposition)})
    exten => h,n,NoOP(${CTDTIME})
    exten => h,n,GotoIf($["${CDR(disposition)}" = "NO ANSWER"]?timecheck:n1)
    exten => h,n(n1),GotoIf($["${CDR(disposition)}" = "BUSY"]?timecheck:n2)
    exten => h,n(n2),GotoIf($["${CDR(disposition)}" = "FAILED"]?timecheck:n3)
    exten => h,n(n3),GotoIf($["${CDR(disposition)}" = "ANSWERED"]?n4:misscall)
    exten => h,n(n4),MYSQL(Connect connid ${SQLHOST}${SQLUSER}${SQLPASS}${SQLDB})
    exten => h,n,MYSQL(Query resultid ${connid} UPDATE office_calls SET active=0 WHERE asterisk_id='${QID}')
    exten => h,n,MYSQL(Clear ${resultid})
    exten => h,n,MYSQL(Disconnect ${connid})
    exten => h,n(hang),Hangup()
    exten => h,n(timecheck),GotoIf($[${CTDTIME} > ${WAITTIME}]?misscall:hang)
    exten => h,n(misscall),Goto(noanswer,s,1)
    exten => s,1,NoOp(${CALLERID(num)})
    exten => s,n,Set(CALLID=74951234567)
    exten => s,n,Set(CALLER=${CALLERID(num)})
    exten => s,n,Set(__QID=${CDR(uniqueid)})
    exten => s,n(begin),GotoIfTime(10:00-22:00,mon-sat,*,*?workdays:outofoffice)
    exten => s,n(workdays),NoOp(Incoming CALL from ${CALLERID(num)} to ${EXTEN})
    exten => s,n,Answer()
    exten => s,n,ResetCDR(w)
    exten => s,n,Wait(1)
    exten => s,n,Background(${IVRWORK})
    exten => s,n,Queue(operators,t,,,300,,startflag1)
    exten => s,n,NoOp(${DIALSTATUS})
    exten => s,n,Goto(noanswer,s,1)
    exten => s,n,Hangup()
    


    Please note that if IVR is running and you need to find out the exact waiting time of the subscriber on the line (otherwise, you will also count the time that the subscriber listened to the voice menu), then after Answer () add ResetCDR (w). Another interesting point - we need to enter a record in the database as soon as the agent in the queue answers the call - here the startflag1 macro will help us, which will be executed as soon as any operator in the queue answers the call.
    Everything is quite simple here, if you did not answer the call, go to the noanswer context, which looks like this:

    [noanswer]
    exten => s,1,NoOp(UID CALL: ${UNIQUEID} / DATE: ${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}))
    exten => s,n,Set(RANDOM=${RAND(1000,9999)})
    exten => s,n,Set(COUNT=${DB(fwcid2/count)})
    exten => s,n,GotoIf($[${ISNULL(${COUNT})}]?:nextstep)
    exten => s,n,Set(DB(fwcid2/count)=1)
    exten => s,n,NoOp()
    exten => s,n,NoOp(UNIQID = ${COUNT})
    exten => s,n,Set(COUNT=$[${COUNT} + 1])
    exten => s,n,Set(DB(fwcid2/count)=${COUNT})
    exten => s,n,System(echo"Неотвеченный вызов с номера +7${CALLERID(NUM)} в ${STRFTIME(${EPOCH},,%H:%M)}" > ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
    exten => s,n,System(echo"" >> ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
    exten => s,n,System(echo"Время ожидания абонента на линии составило ${CTDTIME} сек" >> ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
    exten => s,n,System(echo"hello" | mutt -x -s "+74951234567: пропущенный звонок ${STRFTIME(${EPOCH},,%d.%m.%Y)} ${STRFTIME(${EPOCH},,%H:%M)}" -e "set from="voip@domain.ru"" -e 'set realname='Asterisk'' voip@domain.ru < ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
    exten => s,n,System(/bin/rm -f ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
    exten => s,n,Hangup()
    


    $ {STRFTIME ($ {EPOCH} ,,% H:% M)} - call arrival time.
    $ {CALLERID (NUM)} - the number of the caller.
    $ {COUNT} - for the most part, an example of working with ASTBD, the value of the variable is added to the end of the created file to make it unique, in case you receive a call from the same number at the same time.

    Now about adding records to the MySQL table.
    $ {SQLHOST / SQLUSER / SQLPASS / SQLD} - I defined these variables in the globals section.
    $ {QID} - the variable that we pass into the macro, after defining it with the incoming call 'Set (__ QID = $ {CDR (uniqueid)})'. Notice the two leading underscores that let you inherit the variable in macro macro-startflag1.

    [macro-startflag1]
    exten => s,1,Set(CALLID=74951234567)
    exten => s,n,MYSQL(Connect connid ${SQLHOST}${SQLUSER}${SQLPASS}${SQLDB})
    exten => s,n,MYSQL(Query resultid ${connid} INSERT INTO office_calls VALUES (NULL,'${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}',1,'${CALLID}','${CDR(src)}','${CDR(dstcha
    nnel):0:9}','${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}','${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}','${QID}'))
    exten => s,n,MYSQL(Clear ${resultid})
    exten => s,n,MYSQL(Disconnect ${connid})
    exten => s,n,Hangup()
    


    Let's consider one more task: it is required to generate an XML file with missed calls.
    The file format should be as follows:

    <?xml version="1.0" encoding="UTF-8"?><callback_request><id>100XXXX</id> --- XXX какой-то уникальный идентификатор
      <name></name> --- номер телефона, на который пришел звонок
      <phone>123456</phone> --- номер телефона, с которого пришел звонок
      <comment>Пропущенный звонок</comment><completed>false</completed><created_at>11.12.2012 - 17:19</created_at> --- дата звонка
      <updated_at>11.12.2012 - 17:19</updated_at> --- дата звонка
      <no_answer/></callback_request>


    In solving the problem, I will use the System () command and the perl script.
    Install XML :: Writer

    yum install perl-XML-Writer
    


    The script /etc/asterisk/scripts/genxml.pl is as follows:

    #!/usr/bin/env perl# Create XML fileuse strict;
    use warnings;
    use XML::Writer;
    # Out to file #open STDOUT, ">", "REQUEST.20121211171903.xml" or die "$0: open: $!";my $doc = new XML::Writer();
    # Pring attributes
    $doc->xmlDecl('UTF-8');
    $doc->startTag("callback_request");
    $doc->dataElement( id =>"$ARGV[0]");
    $doc->startTag( "name");
    $doc->characters( "$ARGV[1]");
    $doc->endTag( "name");
    $doc->dataElement( phone =>"$ARGV[2]");
    $doc->dataElement( comment =>"Пропущенный звонок");
    $doc->dataElement( completed =>"false");
    $doc->dataElement( created_at =>"$ARGV[3]");
    $doc->dataElement( updated_at =>"$ARGV[3]");
    $doc->emptyTag( "no_answer");
    $doc->endTag();
    $doc->end();
    


    The script is launched as follows:

    exten => s,n,System(/usr/bin/perl /etc/asterisk/scripts/genxml.pl "100${RANDOM}""74951234567""${CALLERID(NUM)}""${STRFTIME(${EPOCH},,%d.%m.%Y - %H:%M)}" > /srv/www/domain.ru/xml/REQUEST.${STRFTIME(${EPOCH},,%Y%m%d%H%M%S)}.xml)
    


    I hope this material will be useful to you.
    Thanks for attention.

    Also popular now: