📜 ⬆️ ⬇️

Balancing outgoing calls via GSM gateway

In our organization, Asterisk is used, and for outgoing calls, the Yeastar TG800 GSM gateway for 8 SIMs is connected to it. Every month we buy a package of minutes for each SIM card.

To make an outgoing call, it is usually used to iterate the SIMs in order until a free one is found:

exten => _X.,n,Dial(SIP/gsm1/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm2/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm3/${EXTEN},,tT) 

etc.
')
In this case, the most calls go through the first SIM card, and the least through the last one. Therefore, by the middle of the month, the minutes at the first SIM cards end earlier than at the last ones, and a situation arises where you can make a call after 4 SIM cards out of 8, since the first four minutes have ended. This is bad, as there are 4 outgoing lines instead of 8.

To avoid this, you need to make calls not in the same order, but in accordance with the balance of minutes on the sim card.

Along the way, I write down the remnants of minutes, relevance (how much was checked) and when the package was activated in the MySQL database.

You can go to the page and quickly find out the remains:

image

To check balances, you need to enable the API on the gateway, to do this, go to the SMS section, then to the API settings. Everything is clear there, you need to specify a login with a password and the allowed subnet for connection.

We will check the balance every hour, for this we will add a script call to cron (I have every 53rd minute of an hour):

 53 */1 * * * root php %path-to-script%/getbalance.php 

Next, we need to create 8 text files (or how many sim cards you have) with names from nc2.txt to nc9.txt. The numbers are such because the gateway numbers its ports in exactly this way, from 2 to 9.

In each command file to the gateway. Example for nc2.txt:

 action: login username: ****** secret: ******* action: smscommand command: gsm send ussd 2 *255*0# action: logoff 

An example is given for Tele2. Accordingly, in the file nc3.txt instead of "ussd 2" we write "ussd 3". The script sends these commands to the gateway, in response, we receive files with the names from nc2out.txt to nc9out.txt.

The answer will be (for Tele2):

 Asterisk Call Manager/1.1 Response: Success Message: Authentication accepted Response: Follows Privilege: SMSCommand 1:Received USSD success on span: 2 USSD Responses: 2 USSD Code: 64 USSD Len: 85 USSD Message: Ostatok v pakete: 968 min./mes., 5000 SMS/mes., 20480 MB/mes. Parametry' tarifa *107# --END COMMAND-- Response: Goodbye Message: Thanks for all the fish. 

Specification: it is necessary to switch the operator's answers to translit, otherwise we get the text in an inconvenient encoding.

Next we pull out the number of remaining minutes, sort and write the call order in the files from out1.txt to out8.txt (this is already for an asterisk, so the numbering is normal). That is, if the order of the call was 5, 4, 3, 2, 1, 7, 8, 6, then in the file out1.txt we write the number 5, in the file out2.txt we write 4, and so on.

It remains to read these files in the dialplan and make calls in the correct order:

 exten => _X.,n,set(SIMNUM1=${SHELL(/usr/bin/php -f %pathtoscript%/getsim1.php)}) exten => _X.,n,set(SIMNUM2=${SHELL(/usr/bin/php -f %pathtoscript%/getsim2.php)}) exten => _X.,n,set(SIMNUM3=${SHELL(/usr/bin/php -f %pathtoscript%/getsim3.php)}) exten => _X.,n,set(SIMNUM4=${SHELL(/usr/bin/php -f %pathtoscript%/getsim4.php)}) exten => _X.,n,set(SIMNUM5=${SHELL(/usr/bin/php -f %pathtoscript%/getsim5.php)}) exten => _X.,n,set(SIMNUM6=${SHELL(/usr/bin/php -f %pathtoscript%/getsim6.php)}) exten => _X.,n,set(SIMNUM7=${SHELL(/usr/bin/php -f %pathtoscript%/getsim7.php)}) exten => _X.,n,set(SIMNUM8=${SHELL(/usr/bin/php -f %pathtoscript%/getsim8.php)}) exten => _X.,n,Dial(SIP/gsm${SIMNUM1}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM2}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM3}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM4}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM5}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM6}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM7}/${EXTEN},,tT) exten => _X.,n,Dial(SIP/gsm${SIMNUM8}/${EXTEN},,tT) 

Yes, I almost forgot, the file getsim1.php:

 <?php $t = file_get_contents('%pathtoscript%/out1.txt'); echo $t[0]; return $t[0]; ?> 

Now actually the main script getbalance.php.

IP gateway take 10.10.1.1.

I know that I need to make a cycle instead of copy-paste, but I follow the golden rule of the admin: it works - do not touch :-)

 <?php include '/var/lib/asterisk/agi-bin/lib.php'; $s=0; a2: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc2.txt > %pathtoscript%/nc2out.txt'); $text = file_get_contents('%pathtoscript%/nc2out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text2 = $matches[1]; else goto a2; $s=0; a3: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc3.txt > %pathtoscript%/nc3out.txt'); $text = file_get_contents('%pathtoscript%/nc3out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text3 = $matches[1]; else goto a3; $s=0; a4: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc4.txt > %pathtoscript%/nc4out.txt'); $text = file_get_contents('%pathtoscript%/nc4out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text4 = $matches[1]; else goto a4; $s=0; a5: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc5.txt > %pathtoscript%/nc5out.txt'); $text = file_get_contents('%pathtoscript%/nc5out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text5 = $matches[1]; else goto a5; $s=0; a6: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc6.txt > %pathtoscript%/nc6out.txt'); $text = file_get_contents('%pathtoscript%/nc6out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text6 = $matches[1]; else goto a6; $s=0; a7: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc7.txt > %pathtoscript%/nc7out.txt'); $text = file_get_contents('%pathtoscript%/nc7out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text7 = $matches[1]; else goto a7; $s=0; a8: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc8.txt > %pathtoscript%/nc8out.txt'); $text = file_get_contents('%pathtoscript%/nc8out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text8 = $matches[1]; else goto a8; $s=0; a9: $s++; if ($s>10) exit; system('nc 10.10.1.1 5038 < %pathtoscript%/nc9.txt > %pathtoscript%/nc9out.txt'); $text = file_get_contents('%pathtoscript%/nc9out.txt'); if(preg_match('/te:\ (.*)\ min/',$text,$matches)) $text9 = $matches[1]; else goto a9; $text10 = "0"; system('echo "'.date('l dS FY h:i:s A').' '.$text2.' '.$text3.' '.$text4.' '.$text5.' '.$text6.' '.$text7.' '.$text8.' '.$text9.'" >>%pathtoscript%/balance.txt'); $row = mysql_query("select minutes from `lines` where clid like '%2636'",$link); $row1 = mysql_fetch_assoc($row); $old1 = $row1['minutes']+0; $new1 = $text2+0; if ($old1 < $new1) $row = mysql_query("update `lines` set balancedate=NOW()",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text2." where clid like '%2636'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text3." where clid like '%4036'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text4." where clid like '%4977'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text5." where clid like '%2414'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text6." where clid like '%2451'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text7." where clid like '%2536'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text8." where clid like '%2581'",$link); $row = mysql_query("update `lines` set balance=".$text10.", minutesdate=NOW(), minutes=".$text9." where clid like '%4056'",$link); $n[1] = $text2+0; $n[2] = $text3+0; $n[3] = $text4+0; $n[4] = $text5+0; $n[5] = $text6+0; $n[6] = $text7+0; $n[7] = $text8+0; $n[8] = $text9+0; $p[1] = 1; $p[2] = 2; $p[3] = 3; $p[4] = 4; $p[5] = 5; $p[6] = 6; $p[7] = 7; $p[8] = 8; for($i=1;$i<=7;$i++) for($j=$i+1;$j<=8;$j++) if ($n[$i]<$n[$j]) { $t = $n[$i]; $n[$i] = $n[$j]; $n[$j] = $t; $t = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $t; } system('echo "'.$p[1].'" >%pathtoscript%/out1.txt'); system('echo "'.$p[2].'" >%pathtoscript%/out2.txt'); system('echo "'.$p[3].'" >%pathtoscript%/out3.txt'); system('echo "'.$p[4].'" >%pathtoscript%/out4.txt'); system('echo "'.$p[5].'" >%pathtoscript%/out5.txt'); system('echo "'.$p[6].'" >%pathtoscript%/out6.txt'); system('echo "'.$p[7].'" >%pathtoscript%/out7.txt'); system('echo "'.$p[8].'" >%pathtoscript%/out8.txt'); system('asterisk -rx "dialplan reload"'); ?> 

Content lib.php (there is a connection to MySQL):

 <?php $dbuser = "*******"; $dbpass = "*******"; $dbserv = "localhost"; $dbname = "*******"; $dbengn = "mysql"; function sql_connect($host, $login, $password, $dbname) { $link = mysql_connect($host, $login, $password, true); mysql_select_db($dbname, $link); mysql_query("SET NAMES cp1251"); return $link; } function sql_query($query, $link) { $res = mysql_query($query, $link); return $res; } function sql_fetch_assoc($result) { return mysql_fetch_assoc($result); } $link = sql_connect($dbserv, $dbuser, $dbpass, $dbname); ?> 

Another small explanation.

On each sim card, 10 attempts are made to check the balance (this is not always possible), if at least one failed, we exit and try in an hour.

Why is text10 = "0"? Previously used sims MTS, which returned the balance (in rubles). In Tele2, a common account is used, we don’t put money on specific SIM cards, so there is always 0 there.

Balances are also added to the file balance.txt, so that you can view the history and calculate the statistics of spending.

Who cares how not to lose an incoming call on a SIM card, if they are already talking on it, ask in the comments (doesn't pull on an article).

Thanks for attention!

Source: https://habr.com/ru/post/318004/


All Articles