I am working on an Asterisk AGI and Python 3 integration. I am having trouble with my script and I am thinking it may be because it is running too many at once and the closing of the socket at the end my be causing the issue.
If I have one call come in at a time or they are staggered the script executes flawlessly. If I have multiple calls come in at once say 5 (which is common in this instance) the socket receiving the data may only process 2 of the fully completed scripts.
I have tried to minimize the script to see if i could get it to execute faster, stripping out things unneeded, removed logging, removed #out lines. The only thing I could do was try and stagger the calls which is not a viable option.
#!/usr/bin/env python3
import serial
import re
from time import sleep
import logging
import logging.handlers
from configparser import ConfigParser
import sys
import asterisk
import asterisk.agi
from asterisk.agi import *
import socket
import os
import sys
config = ConfigParser()
config.read('/var/www/html/config.ini')
LOG_LEVEL = logging.info('LOGGING', 'level')
# Initialize logging
LOGGER = logging.getLogger('axi')
LOGGER.setLevel(logging.INFO)
formatter = logging.Formatter('|%(asctime)s|%(levelname)-8s|%(name)s|%(message)s')
log_file = logging.handlers.TimedRotatingFileHandler('/var/log/axi/input.csv', when='midnight', backupCount=7)
log_file.setLevel(logging.INFO)
log_file.setFormatter(formatter)
LOGGER.addHandler(log_file)
# Only print to console if at DEBUG level
if LOG_LEVEL == 'DEBUG':
log_console = logging.StreamHandler()
log_console.setLevel(logging.INFO)
log_console.formatter(formatter)
LOGGER.addHandler(log_console)
#BAUD = config.get('USB_Settings', 'baudrate')
#PTY = config.get('USB_Settings', 'parity')
#STPB = int(config.get('USB_Settings', 'stopbits'))
#BTSZ = int(config.get('USB_Settings', 'bytesize'))
HOST = config.get('Ethernet_Paging_System', 'IP')
PORT = config.get('Ethernet_Paging_System', 'Port')
agi = AGI()
pin = agi.env['agi_extension']
msg = agi.env['agi_calleridname']
geekspeak = {
"<ESC>": '\\x1b',
"<ETX>": '\\x03',
"<CR>": '\\r',
"<ACK>": '\\x06',
"<NAK>": '\\x15',
"<EOT>": '\\x04',
"<STX>": '\\x02'
}
htmlspeak = {
"<ESC>": '\\x1b',
"<ETX>": '\\x03',
"<CR>": '\\r',
"<ACK>": '\\x06',
"<NAK>": '\\x15',
"<EOT>": '\\x04',
"<STX>": '\\x02'
}
def str2geek(string):
geekstr = str(string)
for key, value in geekspeak.items():
if key in geekstr:
geekstr = geekstr.replace(key, value)
return geekstr
def geek2str(string):
sstr = str(string)
for key, value in geekspeak.items():
if value in sstr:
sstr = sstr.replace(value, key)
return sstr
def html2str(string):
hstr = str(string)
for key, value in htmlspeak.items():
if value in hstr:
hstr = hstr.replace(value, key)
return hstr
#Socket setup
s = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_INET, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except OSError as msg:
s = None
continue
try:
s.connect(sa)
except OSError as msg:
s.close()
s = None
continue
break
if s is None:
LOGGER.info('---Could not open socket')
sys.exit(1)
with s:
s.send(b'\\r')
sleep(0.5)
s.send(b'\\x1bPG1\\r')
strng=(pin)+(msg)
#New Code for Checksum
list_ascii=[ord(i) for i in strng]
#Prints each car decimal value
#print(list_ascii)
b=sum(list_ascii)+31
#Convert sum to 12 bit binary and parse to 4 sections frist 4 middle 4 last 4
h1=(bin(b)[2:].zfill(12)[8:])
h2=(bin(b)[2:].zfill(12)[4:8])
h3=(bin(b)[2:].zfill(12)[0:4])
#Adds 48 decimal value per TAP 1.8
i1=(int(h1, 2)+48)
i2=(int(h2, 2)+48)
i3=(int(h3, 2)+48)
#Gives checksum value
chks=chr(i3)+chr(i2)+chr(i1)
LOGGER.info('---Pin:' + pin + ' - ' + 'Message:' + msg + ' - checksum:' + chks)
s.send('\x02'.encode() + (pin).encode() + '\r'.encode() + msg.encode() + '\r\x03'.encode() + (chks).encode() + '\r'.encode())
resp=str(s.recv(1024))
if resp:
LOGGER.info(html2str(resp))
if '15' in resp:
LOGGER.info('page not accepted')
if resp:
sleep(0.5)
s.send(b'\x04\r')
sleep(0.5)
LOGGER.info('---Page Accepted' + ' - checksum:' + chks)
s.close()
I was hoping to be able to create one script that keeps the TCP socket alive and another will execute on a call to asterisk and send that data either over the socket or to the already running python script and start the process of sending data with variables.
Thank you
Here is how I did it. I got the first script to run on a call to asterisk and the second opens the connection and keeps it open until one side closes. The asterisk script only runs when a call comes into asterisk and converts an inbound SIP message into a TAP 1.8 message used heavily in the nurse call industry. The socket script I run as a service opening the connection to send data.
Asterisk Script
#!/usr/bin/env python3
import serial
import re
from time import sleep
import sys
import asterisk
import asterisk.agi
from asterisk.agi import *
import socket
import os
geekspeak = {
"<ESC>": '\\x1b',
"<ETX>": '\\x03',
"<CR>": '\\r',
"<ACK>": '\\x06',
"<NAK>": '\\x15',
"<EOT>": '\\x04',
"<STX>": '\\x02'
}
htmlspeak = {
"<ESC>": '\\x1b',
"<ETX>": '\\x03',
"<CR>": '\\r',
"<ACK>": '\\x06',
"<NAK>": '\\x15',
"<EOT>": '\\x04',
"<STX>": '\\x02'
}
def str2geek(string):
geekstr = str(string)
for key, value in geekspeak.items():
if key in geekstr:
geekstr = geekstr.replace(key, value)
return geekstr
def geek2str(string):
sstr = str(string)
for key, value in geekspeak.items():
if value in sstr:
sstr = sstr.replace(value, key)
return sstr
def html2str(string):
hstr = str(string)
for key, value in htmlspeak.items():
if value in hstr:
hstr = hstr.replace(value, key)
return hstr
agi = AGI()
pin = '201' #agi.env['agi_extension']
msg = 'TEST' #agi.env['agi_calleridname']
strng=(pin)+(msg)
#New Code for Checksum
list_ascii=[ord(i) for i in strng]
#Prints each car decimal value
#print(list_ascii)
b=sum(list_ascii)+31
#Convert sum to 12 bit binary and parse to 4 sections frist 4 middle 4 last 4
h1=(bin(b)[2:].zfill(12)[8:])
h2=(bin(b)[2:].zfill(12)[4:8])
h3=(bin(b)[2:].zfill(12)[0:4])
#Adds 48 decimal value per TAP 1.8
i1=(int(h1, 2)+48)
i2=(int(h2, 2)+48)
i3=(int(h3, 2)+48)
#Gives checksum value
chks=chr(i3)+chr(i2)+chr(i1)
#Socket setup
s = None
for res in socket.getaddrinfo("localhost", 9988, socket.AF_INET, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except OSError as msg:
s = None
continue
try:
s.connect(sa)
except OSError as msg:
s.close()
s = None
continue
break
if s is None:
sys.exit(1)
with s:
s.send('\x02'.encode() + (pin).encode() + '\r'.encode() + msg.encode() + '\r\x03'.encode() + (chks).encode() + '\r'.encode())
s.close()
Socket Script
#!/usr/bin/env python3
import serial
import re
from time import sleep
import logging
import logging.handlers
from configparser import ConfigParser
import socket
import os
import sys
config = ConfigParser()
config.read('/var/www/html/config.ini')
LOG_LEVEL = logging.info('LOGGING', 'level')
# Initialize logging
LOGGER = logging.getLogger('axi')
LOGGER.setLevel(logging.INFO)
formatter = logging.Formatter('|%(asctime)s|%(levelname)-8s|%(name)s|%(message)s')
log_file = logging.handlers.TimedRotatingFileHandler('/var/log/axi/input.csv', when='midnight', backupCount=7)
log_file.setLevel(logging.INFO)
log_file.setFormatter(formatter)
LOGGER.addHandler(log_file)
# Only print to console if at DEBUG level
if LOG_LEVEL == 'DEBUG':
log_console = logging.StreamHandler()
log_console.setLevel(logging.INFO)
log_console.formatter(formatter)
LOGGER.addHandler(log_console)
HOST = config.get('Ethernet_Paging_System', 'IP')
PORT = config.get('Ethernet_Paging_System', 'Port')
#Socket setup
s2 = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_INET, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s2 = socket.socket(af, socktype, proto)
except OSError as msg:
s2 = None
continue
try:
s2.connect(sa)
except OSError as msg:
s2.close()
s2 = None
continue
break
if s2 is None:
LOGGER.info('---Could not open socket')
sys.exit(1)
#listening Socket
s3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s3.bind(("localhost", 9988))
s3.listen(1)
while True:
conn, addr = s3.accept()
data = conn.recv(1024)
if data:
#with s2:
s2.send(b'\\r')
sleep(0.5)
s2.send(b'\\x1bPG1\\r')
LOGGER.info(data)
s2.send(data)
resp=str(s2.recv(1024))
if resp:
# LOGGER.info(html2str(resp))
if '15' in resp:
LOGGER.info('page not accepted')
if resp:
s2.send(b'\x04\r')
LOGGER.info('---Page Accepted')