📜 ⬆️ ⬇️

Really useful app for Digium phones

image

Greetings, habrasoobschestvu.

Just over a year ago we developed applications for Digium phones. Despite the fact that the plans were extensive, we stopped only on the following variations:
')


These applications were written to familiarize the community with APIs and examples, even more just for fun. Coft, if you can call it that, does not carry any unique application that would be useful for real business.

Today we decided to return to this topic and share another, in our opinion, a much more interesting application that displays the call on the phone screen if users are in the same pick-up group and allows it to be intercepted.

For details -> habrakat


Due to the fact that the phone itself cannot access the asterisk via HTTP, the client-server structure was chosen. The server on python, which “catches” requests from the asterisk CURL when making a call, and javascript on the phone, which with some frequency polls for the presence of new entries.

server.py
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer import urlparse import json import shelve import datetime import sys import os TIME_FORMAT = '%d.%m.%Y %H:%M:%S.%f' DB_NAME = "db.db" class HttpProcessor(BaseHTTPRequestHandler): def do_GET(self): if "/get" in self.path: fields = self.get_fields() if not fields: print "There are no parameters" return callgroup = fields.get("callgroup") pickupgroup = fields.get("pickupgroup") if callgroup is None or pickupgroup is None: print "There are no pickupgroup or no callgroup" self.send_error(404) return None db = shelve.open( DB_NAME) data = [] for key in db.keys(): if "callgroup" in db[key] and "pickupgroup" in db[key] and str(db[key]["callgroup"]) == str(callgroup) and str(db[key]["pickupgroup"]) == str(pickupgroup): entry = db[key] data.append(entry) # Make simple dict for json self.send_json(data) db.close() def do_POST(self): data = self.get_json_data() if "uid" not in data: print "There are no a number" return uid = str(data["uid"]) print data if "/put" in self.path: db = shelve.open( DB_NAME) db[uid] = data db.close() data = {"status": 200, "message": "OK"} self.send_json(data) elif "/del" in self.path: db = shelve.open( DB_NAME) if uid in db: del db[uid] data = {"status": 200, "message": "OK"} self.send_json(data) def send_json(self, data): self.send_response(200) self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps(data)) def get_json_data(self): length = int(self.headers.getheader('content-length')) field_data = self.rfile.read(length) try: data = json.loads(field_data) except: print "JSON error:" + field_data self.send_error(404) return None return data def get_fields(self): fields_data = self.path.split("?") if len(fields_data) < 2: return GET = {} args = fields_data[1].split('&') for arg in args: t = arg.split('=') if len(t) > 1: k, v = arg.split('=') GET[k] = v return GET if __name__ == "__main__": if os.path.exists( DB_NAME): os.remove( DB_NAME) host = "192.168.1.254" port = 8000 serv = HTTPServer((host, port), HttpProcessor) print "Server running at {}:{}".format(host, port) serv.serve_forever() 



Do not forget to give this file execution rights (chmod + x), run it and add to autorun.

Install the application on the phone



As you probably know, or have heard, Digium phone can be configured using the web interface, or with the help of some proprietary provisioning DPMA. (Digium Phone Module Asterisk).
If you have the simplest setup (via the web), then you need to go to the System tools phone menu and click Enable App Development, then login to the phone at phone_ip-address / app_dev (by default: User: admin, Password: 789) and there click the big green Add App button.



Here is the actual file to download the application itself: pbxware.ru

Code itself
 var incomingGroupCall = {} var screen = require('screen'); //util for debugging var util = require('util'); var app = require('app'); //we needs to get all info about app app.init(); screen.clear(); //Get config of app(we needs settings) var config = app.getConfig(); var callgroup = config.settings.callgroup; //Get callgroup var pickupgroup = config.settings.pickupgroup; //Get pickupgroup var server = config.settings.server; //server uri, like http://{host}:{port} var app_name = config.settings.id; //App name from json file var phonePrefix = config.settings.prefix; //App name from json file var language = config.settings.language || "ru"; var uids = []; // This list contains all uids server give us at runtime var phonesCount = 0; // This variable needs to watch uids missing from uids list var timer; var currentListPos = 0; var listWidget = new List(0, 0, window.w, window.h); var lang = digium.readFile("app", language + ".json"); language = JSON.parse(lang); incomingGroupCall.show = function () { util.debug("Call show"); if (this.visible) { window.add(listWidget); } this.update(); if (timer) { clearInterval(timer); } timer = setInterval(this.update, 1100); }; incomingGroupCall.showGui = function(message, params) { util.debug("Show gui"); var lastSelected = listWidget.selected; listWidget.clear(); listWidget.set(0,0, message); var i=1; if(!params){ return; } params.forEach(function(entry) { var msg = entry.from + " --> " + entry.to; if(i<=9){ msg = "[" + i + "] " + msg; } else if(i === 10) { msg = "[0] " + msg; } else if(i === 11) { msg = "[*] " + msg; } else if(i === 12) { msg = "[#] " + msg; } listWidget.set(i, 0, msg); listWidget.set(i, 1, entry.to); //container to get value in key handler i++; }); listWidget.select(lastSelected); } incomingGroupCall.update = function() { var request = new NetRequest(); request.open("GET", server + "/get?callgroup="+callgroup+"&pickupgroup="+pickupgroup); request.onreadystatechange = function() { //(readyState === 4) indicates a completed request if (4 === request.readyState) { if (200 === request.status) { try { var data = JSON.parse(request.responseText); if (!data || data.length === 0) { if (!digium.app.inForeground) { return; } incomingGroupCall.showGui(language["NO_CALLS"]); return; } //Remove ended calls var currentUids = data.map( function(item) { return item.uid; }); var needsToRefresh = false; var newEntryAvailable = false; uids.forEach(function(uid) { if(currentUids.indexOf(uid) === -1) { uids.splice(uids.indexOf(uid), 1); needsToRefresh = true; } }); // Add new phones to list data.forEach(function(entry) { if (uids.indexOf(entry.uid) === -1) { needsToRefresh = true; newEntryAvailable = true; uids.push(entry.uid); } }); util.debug("New entry:" + newEntryAvailable); if (!digium.app.inForeground && newEntryAvailable) { digium.foreground(); } if(needsToRefresh) { incomingGroupCall.showGui(language["INCOMING_CALLS"], data); } } catch (e) { util.debug('request error: ' + JSON.stringify(e)); incomingGroupCall.showGui(language["SERVER_UNAVAILABLE"]); } } else { util.debug('request error1: ' + request.status); incomingGroupCall.showGui(language["SERVER_UNAVAILABLE"]); } } }.bind(this); request.setTimeout(1000); request.send(); }; //initialize variables incomingGroupCall.init = function () { this.widgets = {}; //stay open when the app is backgrounded digium.app.exitAfterBackground = false; this.visible = digium.app.inForeground; incomingGroupCall.listeners(); // setInterval(digium.restart, 180000); }; incomingGroupCall.listeners = function () { //show the full window when the app is foregrounded digium.event.observe({ 'eventName' : 'digium.app.foreground', 'callback' : function () { util.debug("app.foregrounded"); window.clear(); this.visible = digium.app.inForeground; this.setButtons(); this.show(); }.bind(this) }); //show the idle window when the idleScreen is shown digium.event.observe({ 'eventName' : 'digium.app.background', 'callback' : function () { util.debug("app.background"); this.visible = digium.app.inForeground; window.clearSoftkeys(); this.show(); }.bind(this) }); }; incomingGroupCall.setButtons = function () { window.onkeyselect = function() { var phone = listWidget.get(listWidget.selected, 1); util.debug("Selected " + phone); digium.phone.dial({ "number": phonePrefix+phone }) } window.onkey = function(e) { //Digits keyboard handler try { var key = e.key; if(e.key == "0") { key = 10; } else if (e.key == "*") { key = 11; } else if (e.key == "#") { key = 12; } var phone = listWidget.get(key, 1); if (phone) { digium.phone.dial({ "number": phonePrefix+phone }) } } catch(e) { util.debug("Error in trying to dial"); } util.debug(JSON.stringify(e)); } window.setSoftkey(4, language['EXIT'], function() { digium.app.exitAfterBackground = true; digium.background(); }.bind(this)); window.setSoftkey(3, language['HIDE'], function() { digium.background(); }.bind(this)); } incomingGroupCall.init(); incomingGroupCall.show(); 


In the settings of the new application, you must specify the following options:

callgroup: 1
pickupgroup: 1
server: 192.168.1.254 : 8000 (well, or any other IP where the Python script is running)
prefix: * 8 (prefix for call pickup)
language: ru (supported by en / ru)

Phone Settings Screenshot



If you are using DPMA, then you need to download the application to the phones using this instruction.

Run the application. You can leave it open or collapse into the background.



Change Asterisk Dialplan



So, we recorded the application on the phone, we also launched the repeater on the server. It remains to make changes to the asterisk dialplan so that it informs that the extension came a call with the necessary parameters for callgroup and PickupGroup.

For example, you can use our work dialplan

exten => _7XX, 1, NoOp (Call from $ {CALLERID (num)} to $ {EXTEN})
same => n, Set (CallGroup = $ {SIPPEER ($ {EXTEN}, callgroup)})
same => n, NoOp (Callgroup = $ {CallGroup})
same => n, Set (PickupGroup = $ {SIPPEER ($ {EXTEN}, pickupgroup)})
same => n, NoOp (PickupGroup = $ {PickupGroup})
same => n, System (curl -i -H "Accept: application / json" -H "Content-Type: application / json" -X POST -d '{"uid": "$ {UNIQUEID}", "callgroup ":" $ {CallGroup} "," pickupgroup ":" $ {PickupGroup} "," from ":" $ {CALLERID (num)} "," to ":" $ {EXTEN} "} ' 192.168.1.254 : 8000 / put)
same => n, Dial (SIP / $ {EXTEN}, 60, Tt)
same => n, Set (CallGroup = $ {SIPPEER ($ {EXTEN}, callgroup)})
same => n, hangup ()

exten => h, 1, NoOp (END of App)
same => n, System (curl -i -H "Accept: application / json" -H "Content-Type: application / json" -X POST -d '{"uid": "$ {UNIQUEID}", "callgroup ":" $ {CallGroup} "," pickupgroup ":" $ {PickupGroup} "," from ":" $ {CALLERID (num)} "," to ":" $ {TARGETNO} "} ' 192.168.1.254 : 8000 / del)
same => n, hangup ()

Application in action





When an incoming call on the phone screen pops up our application that shows calls in this call group and allows him to intercept. There is no other alarm (for example, a melody or light indication)

The numbers can be moved using the “up” and “down” buttons, you can intercept the call by pressing the “OK” button, then the selected number is intercepted, or by using numbers and *, #.

Run the application, turn it off and wait for the call). With a new call, the application will unfold. You can roll it again.

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


All Articles