0 purchases
remotephonecontrol 0.1.0
Remote Phone Control - v0.1.0
Some SIP hardphone brands support the features Action URIs and Action URLs on some or all of their phone models. Action URIs are used to remote control a phone by sending it HTTP GET requests. E.g., place a call. Action URLs are used to communicate events occuring on a phone to an HTTP service. E.g. an incoming call.
This Python package primarily serves as a remote controller and a listener for the call related commands to and events from a phone. Its main intent and focus is to automate the testing of call scenarios.
Supported phones
In principle, Remote Phone Control, could be extended to support any phone that provides the Action URI and Action URL features. Currently, only the SNOM models noted under the Stack heading are tested and supported.
Action URIs and methods
These are HTTP GET requests with query parameters to control a phone, make it do something. remote_phone_control hides the URIs and query parameters in a phone class object, e.g. Snom, and its methods. The methods are mapped to and use corresponding URI and query parameters. The table below lists currently implemented methods for Snom class objects. The method names are quite self explanatory. A description is provided if more clarification is needed. Consult SNOM Remote phone control via http for reference.
Method
Arguments
Returns
Description
callout
number: str
bool
pickup
None
bool
hangup
None
bool
hangup_onhook
None
bool
hangup_all
None
bool
senddtmf
digits: str
bool
Send in-band DTMF
senddtmf_sipinfo
digits: str
bool
Send DTMF using SIP-INFO
expect
event: Literal['incoming', 'connect', 'disconnect'], timeout: int = event_wait_timeout
bool
Returns True if your expectation was correct. The default timeout to wait for the event is 15 seconds
clear_events
None
None
Call this together with hangup_all in case a test goes awry and phones are left with dangling, standing calls.
set_disable_speaker
value: Literal['on', 'off']
bool
Turn audible cues/ the speaker on or off
set_setting
setting: str, value: str
bool
setting is the name of the phone setting you want to set to value. For settings name reference browse to the phone's settings page: http://<phone's ip-address>/settings.htm
press_px
x: str
bool
Simulates pressing a free programmable function key
transfer
None
bool
reboot
None
bool
stop
None
None
When you're done consuming Snom, you MUST call stop to stop the Snom's Action Server
Action URLs and handled events
A phone will send an HTTP GET request to the Action URL when triggered by an event. The remote_phone_control package is the endpoint, target, of the request. It will parse and process the request.
Event to Action URL mappings
The events currently handled by remote_phone_control are per the following table.
Event
Description
Action URL used by the phone
Incoming call
There is an incomming call, the phone is ringing
http://<remote_phone_control ip-address>:<port>/event?ip=$phone_ip&event=incoming&local=$local&remote=$remote
On Connected
Fired when a call is established
http://<remote_phone_control ip-address>:<port>/event?ip=$phone_ip&event=connected&local=$local&remote=$remote
On Disconnected
A call is ended
http://<remote_phone_control ip-address>:<port>/event?ip=$phone_ip&event=disconnected&local=$local&remote=$remote
With remote_phone_control you can use these events as verification points when testing a call. E.g., when a phone is called, we can verify if there is an incoming call. When the call is answered, we can check if there's an established call.
For further reference on Action URL s consult SNOM Action URLs
Action URL, format and query parameters
The Action URL is configured on the phone. remote_phone_control will configure this automatically on the phone given the ip-address of the phone. See Usage for an example.
Below, the format used by remote_phone_control to set the Action URL on the phone.
http://<Remote Phone Controller ip-address>:<port>/event?ip=$phone_ip&event=<event>&local=$local&remote=$remote
<Remote Phone Controller ip-address>: The ip-address of the node where a remote_phone_control package is run.
<port>: The Action server port served by remote_phone_control
$phone_ip: A phone variable that will be replaced by the phone's ip-address
<event>: indicates to remote_phone_control what event triggered the request
Currently remote_phone_control parses and handles the following <event>s
incoming
connected
disconnected
$local: A phone variable that will be replaced by the local sip-id related to the event
$remote: A phone variable that will be replaced by the remote sip-id related to the event
Stack
This was used to develop and test the package. Not to say that other combinations of, e.g., Python, Ubuntu, phone models, phone firmware might also work. The SNOM models used are not very recent though. End of life even. So, no guarantees that the package will work for newer models unmodified. But my first impression after skimming through the documentation of recent SNOM models is that the Action URI and Action URL support looks very similar.
Python: 3.8.10
Ubuntu: 20.04.6 LTS
This Python package was tested with the following SIP hardphones
SNOM
Model
Firmware
300
8.7.3.19, 8.7.3.25 8.7.5.17
320
8.7.3.19, 8.7.3.25 8.7.5.17
360
8.7.3.19, 8.7.3.25
Installation
From PyPI
(venv) $ pip install remote-phone-control
From GibHub
(venv) $ pip install git+https://github.com/p4irin/remote_phone_control.git
Verify
(venv) $ python
Python 3.8.10 (default, May 26 2023, 14:05:08)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import remote_phone_control
>>> remote_phone_control.__version__
'0.0.1'
>>> import remote_phone_control.snom
>>> dir(remote_phone_control.snom)
['ActionServer', 'Literal', 'Snom', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'requests']
>>>
Usage
Preconditions
A list of what to account for in order to remote control phones for test automation.
Networking
Preferably use a setup where the node, on which remote_phone_control is running, the phones, the registrar and the call proxy are on the same subnet
If remote_phone_control, the phones, the registrar and the call proxy are on different subnets, make sure they can see, reach each other. E.g., look at you're routing configuration.
No firewall between remote_phone_control and phones
No firewall on remote_phone_control 's node, Ubuntu, as mentioned under Stack
No NAT between remote_phone_control and phones
The phones MUST be provisioned and working
Are registered
Can call each other
Can, optionally, call out to PSTN
Can, optionally, receive incoming calls originating from the PSTN
What data you need
ip addresses of the phones
the username and password of the phones
allocate, list an Action server port for each phone. Each phone will be controlled by a separate instance of a phone class object, e.g. Snom, that will also handle a phone's events through an Action URL
ip address of remote_phone_control 's node. This will be used as the Action server's ip-address for each phone object as you can control several phones from the same node.
a sip-id (outgoing URI) on the phone to use for call operations.
Basic examples
The examples given are included in the package's source as unit tests, in the tests sub directory. The package's tests use Python's standard library unit testing framework. For simplicity's sake, the examples below do not.
Imports and Snom instances
These imports and Snom instantiations must precede all the standalone examples.
import time
from remote_phone_control.snom import Snom
snom_a = Snom(
"nnn.nnn.nnn.nnn", # ip-address of a SNOM phone
"nnn.nnn.nnn.nnn", # Action Server's ip-address
nnnn, # Action Server's listening port
"username", # username to access the SNOM
"password", # password to access the SNOM
"outgoing URI", # a sip-id configured on the SNOM
"extension" # the SNOM's extension
)
snom_b = Snom(
"nnn.nnn.nnn.nnn",
"nnn.nnn.nnn.nnn",
nnnn,
"username",
"password",
"outgoing URI",
"extension"
)
N.B.
The Action Server's ip-address is the ip-address of the node where remote_phone_control is used. Remember, the Action Server is served by remote_phone_control.
The Action Server's listening port MUST be unique for each Snom instance
The outgoing URI is the sip account used for calling
Example: Call out to PSTN
E.g., set your mobile phone to auto answer and call it.
assert snom_a.callout('PSTN number to call') == True
assert snom_a.expect('connect') == True
time.sleep(5) # Represents a 5 seconds conversation
assert snom_a.hangup() == True
assert snom_a.expect('disconnect') == True
snom_a.stop()
SNOM A calls SNOM B, B answers, call is established, B ends the call
snom_a.callout("Extension of SNOM B")
assert snom_b.expect('incoming') == True
snom_b.pickup()
assert snom_b.expect('connect') == True
time.sleep(5) # Represents a 5 seconds conversation
snom_b.hangup()
assert snom_b.expect('disconnect') == True
snom_a.stop()
snom_b.stop()
A calls B, B rejects the call
snom_a.callout("Extension of SNOM B")
assert snom_b.expect('incoming') == True
# Reject the incoming call
snom_b.hangup()
assert snom_a.expect('disconnect')
snom_a.stop()
snom_b.stop()
An actual use case
To get a feel of how you can use this package. It proofed very useful in automating end to end regression tests of a cloud hosted call center web app where an agent is tied to a browser interface, the GUI, and a SIP phone. Call actions displayed and performed on the GUI should be in sync with the actual state of the phone and vice versa. Using Selenium, call actions are executed on the GUI and the state of the phone checked against the expectation using the package. Using the package, call actions are executed on the phone and the GUI state checked using Selenium. Inbound calls, with an external origin, i.e. PSTN, and several other scenarios are checked against both the state of the GUI and the phone. Gluing it all together with Python's standard library unittest framework.
Reference
SNOM
Remote phone control via http
Action URLs
http://<phone's ip-address>/settings.htm
Yealink
Action URI
How to dial or place a call using remote control?
Python
Requests: HTTP for Humans
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.