Raspberry PiでCTI(Computer Telephony Integration)システムを構築する
はじめに
先日、コンタクトセンターの自動応答をTwilioからAmazon Connectに移行しましたが(記事はこちら)、今度はCTI(Computer Telephony Integration)を再構築する機会があったので、設定方法をご紹介します。
弊社CTIの仕組み
- 顧客がコンタクトセンターに電話をかける。
- オフィスの電話が鳴り、同時にFreePBXが着信する。
- FreePBXが着信電話番号をDBに書き込む。
- 電話番号とリレーションした顧客情報がオペレーターの画面に表示される。
- オペレーターは顧客情報やコンタクト履歴等を確認しながら、余裕を持って電話対応できる。
電話が鳴ってから顧客情報が表示されるまで1秒以内なので、オペレーターは電話を取る前に様々な情報を知ることができ、よりスムーズに対応することが可能になります。
AsteriskとFreePBXおよびRasPBXの関係
弊社のCTIはFreePBXが中心になっています。FreePBXはオープンソースのIP−PBXソフトウェアですが、同名のLinuxディストリビューションのことを指す場合もあります。FreePBXのコア部分はAsteriskでできています。Asteriskは単体でIP-PBXとしての機能を持っているので、環境構築と設定ファイルの準備さえすれば、FreePBXなしでもIP-PBXの構築は可能です。ただしAsteriskの設定はかなり難しく、私は一度挑戦して諦めたことがあります。下図は/etc/asterisk
にあるファイルの例です。
FreePBXはGUIで設定できるので(下図参照)、Asteriskの設定ファイル群を直接編集するよりは楽です。ある程度は依存関係をチェックしてくれますし、項目名毎にヘルプがあるのもありがたいです。それでもIP-PBXの設定はすごく難しいのですが…。
FreePBXをRaspberry Piでも動くようにしたのがRasPBXです。弊社のCTIはそこそこ速いマシンにFreePBXディストリビューションをインストールして動かしていますが、今までは予備機がなかったので今回RasPBXを使って予備機の構築に挑戦してみました。
Basix側の準備
brastelに依頼してCTI用のユーザーIDとSIPアカウントを発行してもらいます。CTI用のアカウントができたら、Basixの管理画面でCTIを導入したい外線着信グループに所属させます。BasixではユーザーIDを追加しただけではSIPアカウントは発行されないので、明示的に依頼する必要があります。
FreePBXの設定に必要な情報は以下の4つです。
- SIPサーバーのドメイン(xxxxx.brastel.ne.jp)
- Proxy(basix-proxy.brastel.ne.jp)
- CTI用ユーザーのSIPアカウント
- CTI用ユーザーのSIPパスワード
ドメイン以外の情報はBasixの管理画面では取得できないので、アカウント発行時に控えておきましょう。
RasPBXのインストール
以下のURLから最新のモジュール(zip形式)をダウンロードし、解凍しておきます。
SDカードのマウント先を確認します。Mac以外の環境の方はこちらを参考にしてください。
$ diskutil list
/dev/disk3 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *7.8 GB disk3
1: DOS_FAT_32 NO NAME 7.7 GB disk3s1
アンマウントします。
$ sudo diskutil unmountDisk /dev/disk3
Unmount of all volumes on disk3 was successful
dd
でSDカードに書き込みます。30分ほどかかりました。
$ sudo dd bs=1m if=~/Downloads/raspbx-10-10-2020.img of=/dev/disk3
3836+1 records in
3836+1 records out
4022338560 bytes transferred in 1996.343506 secs (2014853 bytes/sec)
インストール後の各種設定
SSHでログイン
SSHでRasPBXにログインします。初期パスワードはraspberry
です。Mac以外の環境の方はraspbx.local
をraspbx
に読み替えてください。
~ $ ssh root@raspbx.local
The authenticity of host 'raspbx.local (fe80::156:3d9:fac2:4daf%en5)' can't be established.
ECDSA key fingerprint is SHA256:vtE5/AgzCttW9heTjeiUdUwACyoanIphwbJhT5OwmDQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'raspbx.local,fe80::156:3d9:fac2:4daf%en5' (ECDSA) to the list of known hosts.
root@raspbx.local's password:
Linux raspbx 5.4.51-v7+ #1333 SMP Mon Aug 10 16:45:19 BST 2020 armv7l
Welcome to RasPBX - Asterisk for Raspberry Pi
RasPBX is based on Debian. The programs included with the Debian GNU/Linux
system are free software; the exact distribution terms for each program are
described in the individual files in /usr/share/doc/*/copyright.
RasPBX comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
List of RasPBX specific commands:
-----------------------------------------------------------------------------
raspbx-upgrade Keep your system up to date with the latest add-ons and
security fixes
configure-timezone Set timezone for both system and PHP
install-fax Install HylaFAX
add-fax-extension Add additional fax extension for use with HylaFAX
install-fail2ban Install Fail2Ban for additional security
install-dongle Install GSM/3G calling capability with chan_dongle
raspbx-backup Backup your complete system to an image file
root@raspbx:~#
ファイルシステムの拡張
最初はSDカードのサイズに関わらず4GBのディスクスペースしか使えません。
root@raspbx:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 3.5G 2.4G 952M 72% /
devtmpfs 431M 0 431M 0% /dev
tmpfs 463M 0 463M 0% /dev/shm
tmpfs 463M 13M 450M 3% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 463M 0 463M 0% /sys/fs/cgroup
/dev/mmcblk0p1 253M 55M 198M 22% /boot
tmpfs 93M 0 93M 0% /run/user/0
SDカードの容量をフル活用するにはraspi-config
コマンドを実行します。
画像の通り実行していくとファイルシステムがSDカードの上限まで拡張されます。
root@raspbx:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 6.9G 2.4G 4.3G 36% /
devtmpfs 431M 0 431M 0% /dev
tmpfs 463M 0 463M 0% /dev/shm
tmpfs 463M 7.2M 456M 2% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 463M 0 463M 0% /sys/fs/cgroup
/dev/mmcblk0p1 253M 55M 198M 22% /boot
tmpfs 93M 0 93M 0% /run/user/0
/dev/root
のサイズが3.5GBから6.9GBになりました。
パスワードの変更
root@raspbx:~# passwd
New password:
Retype new password:
passwd: password updated successfully
タイムゾーンの設定
configure-timezone
を実行し、Asia → Tokyoの順に選択します。
root@raspbx:~# configure-timezone
Current default time zone: 'Asia/Tokyo'
Local time is now: Fri Feb 19 16:21:13 JST 2021.
Universal Time is now: Fri Feb 19 07:21:13 UTC 2021.
Setting PHP to system timezone: Asia/Tokyo
ロケールの設定
dpkg-reconfigure locales
を実行し、ja_JP.UTF-8を追加します。
root@raspbx:~# dpkg-reconfigure locales
Generating locales (this might take a while)...
en_GB.UTF-8... done
en_US.UTF-8... done
ja_JP.UTF-8... done
Generation complete.
OSのアップデート
パッケージリストを更新します。
apt update
インストール済みのパッケージをアップグレードします。
apt full-upgrade
RasPBX独自のアップグレードを行います。
raspbx-upgrade
アップグレード時にできたキャッシュを削除します。
apt clean
再起動します。
reboot
FreePBXの設定
FreePBXの設定項目は多岐にわたります。ここではBasixに接続してCTIを実現するのに必要な設定に絞って説明します。
初期設定
ブラウザで http://raspbx.local/ にアクセスします。Mac以外の環境の方は http://raspbx/ です。
図のような初期設定画面へ遷移するので管理者のIDとパスワードを設定します。ちなみにこのキャプチャだけはアップグレード前に撮ったので、最新版ではデザインが変わっていると思います。
トランクの設定
「接続」→「トランク」でトランク設定画面を表示し、「トランクを追加」から「SIP(chan_pjsip)トランクを追加」を選択します。
Generalタブでは「トランク名」と「アウトバウンドCID」を設定します。どちらも任意の値で構いません。
「pjsip設定」タブ内の「General」タブではユーザー名、Secret、SIP Server、SIP Server Portを設定します。SIP Server Portは通常のSIPサーバーでは5060です。
「pjsip設定」タブ内の「高度な設定」ではOutbound Proxy、クライアントURI、Server URI、Message Contextを設定します。
設定項目 | 設定値 |
---|---|
Outbound Proxy | sip:basix-proxy.brastel.ne.jp |
クライアントURI | sip:{ユーザー名}@{SIP Server} |
Server URI | sip:{SIP Server} |
Message Context | 任意の値 |
カスタム宛先の設定
「アドミン」→「カスタム宛先」でカスタム宛先設定画面を表示します。
カスタム宛先ではTargetと説明を設定します。Targetは「コンテキスト,exten,優先度」という形式で記述します。ここではcti,s,1
としました。
インバウンドルートの設定
「接続」→「インバウンドルート」でインバウンドルート設定画面を表示します。
「インバウンドルートを追加」をクリックします。
インバウンドルートは「説明」と「宛先をセット」を設定します。「宛先をセット」では先ほど作成したカスタム宛先を選択してください。
extensions_custom.confの編集
最後にブラウザからは設定できない/etc/asterisk/extensions_custom.conf
を編集します。
[cti]
exten => s,1,NoOp(${CALLERID(name)})
exten => s,2,Log(NOTICE,${CALLERID(name)})
exten => s,n,AGI(inbound.py)
exten => s,n,Return()
exten => s,n,AGI(inbound.py)
が特に重要です。
この設定により、電話がかかってくる度に/var/lib/asterisk/agi-bin/inbound.py
が実行されます。ここではPythonにしましたが、どんな言語でも実行可能です。
すべての設定が完了したら「設定適用」をクリックします。
CTI用プログラムの作成
サンプルとしてFirestore上に電話番号を格納するCTIプログラムを作成しました。/var/lib/asterisk/agi-bin
に配置してください。Firebaseの設定は調べればすぐに分かるので省略します。
#!/usr/bin/python3
import datetime
import firebase_admin
import json
from asterisk.agi import *
from firebase_admin import credentials
from firebase_admin import firestore
from pytz import timezone
now = datetime.datetime.now(timezone('UTC')) # タイムスタンプ
# firebase初期処理
cred = credentials.Certificate('{Firebase認証用JSONファイルのパス}')
firebase_admin.initialize_app(cred)
# 着信時の情報を取得
agi = AGI()
caller_id = agi.env['agi_callerid'] # 着信電話番号
# Firestoreに書き込み
db = firestore.client()
doc_ref = db.collection('inbound').document()
doc_ref.set({
'phone_number': caller_id,
'timestamp': now,
})
モジュールのインストール
pip3をインストールします。
apt install python-pip python3-pip
Firebase Admin SDKをインストールします。
pip3 install firebase-admin
Asterisk用インターフェースをインストールします。
pip3 install pyst2
inbound.py
に実行権限を追加します。
chmod +x inbound.py
動作確認
/var/log/asterisk/full
を表示しながら電話をかけてみます。
tail -f /var/log/asterisk/full
ログに電話番号およびres_agi.c: Launched AGI Script /var/lib/asterisk/agi-bin/inbound.py
という内容が表示されていれば成功です。
Firestore上には新たなドキュメントが追加されます。電話番号と顧客情報を紐づけてフロント側を作れば、CTIシステムの完成です。
終わりに
Asteriskの設定ファイルを書くのはかなり難しいですが、FreePBXはブラウザからポチポチ入力すればなんとなく動く設定が作れるので面白いですよ。内線電話網の構築や、通話録音、IVR、FAXの送受信など、およそ電話関連の機能は一通りそろっているので、小規模な事業所ならこれだけで本格的なコールセンターを構築できます。外線接続周りの設定は難しいですが、挑戦してみてはいかがでしょうか。
Discussion