Python VoIP developers 101

Part 1: Python example on sending SMS, making VoIP calls

If you are interested in Python developments, take a look at the following clear and easy to read guide. Would you like to know how to send/receive messages and make/answer voice calls? This page provides answers for these questions and gives more information about how to extend your PBX.

1. What you need

2. Get started

Overview

HTTP API enables you to get information from the PBX in real time and to control calls with HTTP requests. Take a look at how it works through the example of Call command. Call command can be used to initiate a voice call. It makes an API extension call a number and does tasks with the call. The tasks are declared in an OzML response document as seen in Figure 1.

how call command works
Figure 1 - How the Call command works

Step 1: Create a call using a HTTP request, for example:

http://ozekixepbx.ip:7780/?command=Call&Dialed=100&ApiExtension=9997&Url=http%3A%2F%2Fyourapp.com%2Fcallconnected.php

Please change the ozekixepbx.ip text to the ip address where the Ozeki Phone System XE is installed. On the yoursite.com the address should be that where the sample applications are running.

Step 2: Accept the CallConnected request from the Ozeki Phone System on your webserver and return an XML to handle the call. Example request sent by the Ozeki Phone System PBX to your webserver: http://yourapp.com/callconnected.php

OzML example response returned by callconnected.php:

<Response>
<Delay>1</Delay>
<Speak>Congratulations, this is your first OzML Response command.</Speak>
<Delay>2</Delay>
<Speak>Have a nice day!</Speak>
</Response>

To send a test response to a call connected request in a simple manner using the tester, fill out the Response OzML field. You can choose from Example OzMLs or write your own one.

User Manual

Using the Apache and Mod_wsgi modul, you are able to run programs (which were written in Python language) in Apache webserver, with these programs you can make outgoing calls, answer incoming ones, and you can also send/receive SMS messages through the Ozeki Phone System.

Downloading Apache 2.2

You need to have an Apache webserver on your PC. Get more information on how to download and install it from the following step-by-step guide.

Installing Python 3.1+ 32 bit

You can download the installation program of Python from its offical website . Be careful! Install Python Version 32 bit, because Apache is only available in it. The best choice is Python 3.1 since mod_wsgi was made for Python 3.1 32 bit and Apache 2.2 32 bit.

Python example projects were made with Python 3.1 32 bit version (download now).
Meanwhile installing Python you need to select "Install for all user" option, otherwise mod_wsgi will not work.

Downloading and Installing Mod_wsgi

With Mod_wsgi Apache modul your program (written in Python) can run at Apache webserver.
There are two solutions to download Mod_wsgi. You can build it from several sources.
You can download the binary files.
Download mod_wsgi-win32-ap22py31-3.3.so file. Then rename it to mod_wsgi.so .
After the successfull downloading, locate the modul at Apache installation directory, Modules folder.
With default Apache installation settings this path is the following:

c:\Program Files (x86)\Apache Software Foundation\Apache2.2\modules\

Afterwards you need to set in a configuration file that your new mod_wsgi modul will be loaded when the Apache webserver starts. This configuration file can be found in the Apache installation folder, under conf folder, called httpd.conf. With default Apache installation settings this file can be found at the following path:

c:\Program Files (x86)\Apache Software Foundation\Apache2.2\conf\

Open the file in a text editor. Find these lines in the httpd.conf file (these lines specify which modules are loaded when Apache webserver starts):

#LoadModule expires_module modules/mod_expires.so
#LoadModule ext_filter_module modules/mod_ext_filter.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule filter_module modules/mod_filter.so
#LoadModule headers_module modules/mod_headers.so
#LoadModule ident_module modules/mod_ident.so

Insert the following line after these lines:

LoadModule wsgi_module modules/mod_wsgi.so

Save the file and restart Apache webserver.

Ozeki Phone System Python Examples

First you need to download the examples for Python. After you have downloaded the .wsgi files, move them into a newly created empty folder. In this manual it is assummed that this folder is located at:

c:\OpsExample

Apache needs your permission to reach the folder, and set mod_wsgi modul, so the examples can run through your browser.
Then open Apache configuration file (httpd.conf).
After opening, search where you can edit Apache access to the folders.

<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>

Under this entry, insert this:

<Directory "c:\OpsExample">
Order allow,deny
Allow from all
</Directory>

</Directory>

Where c:\OpsExample is the path where the downloaded files are found.
After the entry type the following rows in the configuration file:

WSGIScriptAlias /SendSms "c:\OpsExample\SendSms.wsgi"
WSGIScriptAlias /CreateCall "c:\OpsExample\CreateCall.wsgi"
WSGIScriptAlias /ReceiveSms "c:\OpsExample\ReceiveSms.wsgi"
WSGIScriptAlias /ReceiveCall "c:\OpsExample\ReceiveCall.wsgi"

With these lines you associate .wsgi files to a URL. Concering SendSMS.wsgi, adding a path (in our browser) of /SendSMS, you start the SendSMS.wsgi program.
If you enter the URL below, you can start the program:

http://yoursite.com/SendSms

After you have saved the file, restart your Apache webserver. Then, at the registered URL paths, you can reach the Ozeki Phone System Python examples.

Using examples

You have to add an API extension, so the examples of Ozeki Phone System work properly.
You also need the IP address of the PC running the Ozeki Phone System and the configured HTTP API port (7780 by default). You need to modify the example Python projects according to these values.

Now you need to install an API extension on the Ozeki Phone System in order to receive calls and SMS messages. Find out how to install a new API extension.

3. Receive incoming voice calls

You can receive calls with the ReceiveCall.wsgi Python program. The program gets an HTTP request and sends back an OzML response, with the help of the receiveCall() method. The Delay OzML command in the OzML request indicates a one second delay before the execution of the next OzML command. The Speak command uses text-to-speech to play the given text to the callee. In this example OzML response, the parameters of the HTTP request originating from Ozeki Phone System are also used (it contains the current date and the caller ID value).

def receiveCall(environ):
today = datetime.datetime.now();

try:
length= int(environ.get('CONTENT_LENGTH', '0'))

if(length != 0):
body = environ['wsgi.input'].read(length)
receivedData = urllib.parse.parse_qs(str(body))
caller = escape(receivedData['Caller'][0])

except IOError:
return ""

return """<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Delay>1</Delay>
<Speak>Congratulations, you received a test call from {1} at {0} with the python example program.</Speak>
<Delay>1</Delay>
<Speak>For more information, visit www.ozekiphone.com</Speak>
</Response>""".format(today.strftime("%Y-%m-%d %H:%M"), caller)

Code example 1 - Python code to receive calls with ReceiveCall.wsgi

4. Make outgoing voice calls

You can create an outgoing call with the CreateCall.wsgi Python program. The program will issue an HTTP request to the Ozeki Phone System, which will request an OZML response from the program if the call setup was successfull. You can give informations about the call and the access points of Ozeki Phone System XE in createCall() method.

def createCall():    
dict = {}
dict["Dialed"] = "1200"
dict["CallerId"] = "1201"
dict["CallerDisplayName"] = "Mr. Test"
dict["ApiExtension"] = "9997"
dict["Url"] = "http://yoursite.com/CreateCall/CallCreated"
dict["ErrorUrl"] = "http://yoursite.com/CreateCall/CallErrorOccured"

opsLocation = "yoursite.com"
opsPort = 7780
result = ""

try:
requestUrl = "http://{}:{}/?Command=Call&{}".format(opsLocation, opsPort, urllib.parse.urlencode(dict))

result += requestUrl
request = urllib.request.Request(requestUrl)
response = urllib.request.urlopen(request)

if(response.status != 200):
result += "\r\nThe HTTP Status received indicates errors: {}".format(response.status)
return result

except Exception:
result += "\r\nError occured while sending the HTTP request: {}".format(Exception)
return result

result += "\r\nCall successfully created."
return result

Code example 2 - Python code to make an outgoing call with CreateCall.wsgi

The OZML response requested by the Ozeki Phone System is generated by the getOzmlResponse() method. The Delay OzML command in the OzML request indicates a one second delay before the execution of the next OzML command. The Speak command uses text-to-speech to play the given text to the callee. In this example OzML response, the parameters of the HTTP request originating from the Ozeki Phone System are also used (it contains the current date and the caller ID value).

def getOzmlResponse(environ):

today = datetime.datetime.now();

try:
length= int(environ.get('CONTENT_LENGTH', '0'))

if(length != 0):
body = environ['wsgi.input'].read(length)
receivedData = urllib.parse.parse_qs(str(body))
callee = escape(receivedData['Callee'][0])

except IOError:
return ""

return """<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Delay>1</Delay>
<Speak>Congratulations, you have initiated a test call to {1} at {0} from the python example program.</Speak>
<Delay>1</Delay>
<Speak>For more information, visit www.ozekiphone.com</Speak>
</Response>""".format(today.strftime("%Y-%m-%d %H:%M"), callee)

Code example 3 - Python code to make an outgoing call with CreateCall.wsgi

If the given OZML response is invalid, the Ozeki Phone System will issue an HTTP request to the given ErrorUrl, which will be handled by the callErrorOccured() method (the method saves the error message into a new file).

5. Receive SMS message

You can receive incoming SMS messages with the ReceiveSms.wsgi Python program. The Ozeki Phone System will issue an HTTP POST request to the URL registered to ReceiveSms.wsgi. The program receives the HTTP request and saves the information into a new file using the receiveSms() method. The method also sends back a response SMS to the sender, indicating that the SMS has been successfully received.

def receiveSms(environ):

body = ""

try:
length= int(environ.get('CONTENT_LENGTH', '0'))
except ValueError:
length= 0

try:
if(length != 0):
body = environ['wsgi.input'].read(length)
receivedData = urllib.parse.parse_qs(str(body))

f = open('D:/receivedSms.txt', 'w')
for key, value in receivedData.items():
f.write("{}: {}\r\n".format(str(key), str(value)))
f.close()

sendSms(receivedData);

except IOError:
return "Failed to save sms."   

return "SMS received."

Code example 4 - Python code to send SMS messages via ReceiveSms.wsgi

6. Send SMS message

You can send SMS messages via SendSms.wsgi. The program will send an SMS message (through the given path) to Ozeki Phone System. The method SendSms() is responsible for sending out the message. You can also specify the attributes of the message and the location of Ozeki Phone System in this method.

def sendSms():    
dict = {}
dict["Sender"] = "+36301234567"
dict["Recipient"] = "+36301234568"
dict["Message"] = "Test message from Python"
dict["ApiExtension"] = "9997"
dict["DeliveryReportURL"] = "http://yoursite.com/SendSms/DeliveryReportReceived"

opsLocation = "yoursite.com"
opsPort = 7780
result = ""

try:
requestUrl = "http://{}:{}/?Command=SendSms&{}".format(opsLocation, opsPort, urllib.parse.urlencode(dict))

result += requestUrl
request = urllib.request.Request(requestUrl)
response = urllib.request.urlopen(request)

if(response.status != 200):
result += "\r\nThe HTTP Status received indicates errors: {}".format(response.status)
return result

except Exception:
result += "\r\nError occured while sending the HTTP request: {}".format(Exception)
return result

result += "\r\nSMS successfully sent."
return result

Code example 5 - Python code to send SMS messages via SendSms.wsgi

Ozeki Phone System will send the delivery report to the url specified by the DeliveryReportURL parameter. SendSms.wsgi handles the incoming delivery report and save the information into a new file, with the help of receiveDeliveryReport() method.

def receiveDeliveryReport(environ):
body = ""

try:
length= int(environ.get('CONTENT_LENGTH', '0'))
except ValueError:
length= 0

try:
if(length != 0):
body = environ['wsgi.input'].read(length)
receivedData = urllib.parse.parse_qs(str(body))

f = open('D:/receivedDeliveryReport.txt', 'w')
for key, value in receivedData.items():
f.write("{}: {}\r\n".format(str(key), str(value)))
f.close()

except IOError:
pass

Code example 6 - Python code to send SMS messages via SendSms.wsgi

7. Create a more advanced project

The Ozeki Phone System offers a lot more options for Python developers. You can interact with existing calls, control and configure the PBX, you can introduce new communication techniques and media formats.
For a complete list of Python commands, check out: http://www.ozekiphone.com/examples/doc/

If you have any questions or need assistance, please do not hesitate to contact us at  info@ozekiphone.com

More information