RaspberryPiでスマートホーム 〜Asteriskで家庭内電話 その3 AGIでシステム連携〜
ラズパイにAsteriskをインストールして、IP電話を使った内線・自動応答メニューができるようになりました。
次は電話とプログラムを連携させてみます。具体的には自動応答メニューで電話がかかってきた時、ボタンが押された時にテキストファイルにログを出力します。
必要なもの
Asteriskをインストールしたラズパイを使います。Asteriskのインストールはこちら。
前回作った自動応答メニューに組み込んで行きます。
準備
AsteriskはAGI(Asterisk Gateway Interface)という仕組みで外部プログラムと連携できます。Asteriskと外部プログラムは標準入出力、環境変数を使ってテキストでやりとりします。なので言語はPerl、PHP、C、シェルスクリプト…なんでもオーケーです。
今回はPHPを使います。まずはラズパイにPHPをインストール。パッケージではPHPのバージョンは5とちょっと古いですが、これを使用します。
$ sudo apt-get install php5 php5-cli
インストールしたら一応確認。
$ php -v
PHP 5.6.38-0+deb8u1 (cli) (built: Sep 20 2018 06:25:59)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
次にPHPからAGIを簡単に扱える便利なライブラリ、PHPAGIをダウンロードします。
the file release areaから”Download Latest Version”のボタンを押してダウンロードします。
展開したら、”phpagi.php”と”phpagi-asmanager.php”を/usr/share/asterisk/agi-binにコピーして、所有者を変えておきます。
$ sudo cp phpagi.php phpagi-asmanager.php /usr/share/asterisk/agi-bin
$ sudo chown asterisk:asterisk phpagi*.php
この2つのファイルは別に場所はどこでも構いませんし、所有者も変えなくていいんですけど、なんとなくそうしときました。
これで準備できました。
作ってみる
ログをとるスクリプトを作ります。権限が面倒臭いのでとりあえず/tmp/test.logに出力するようにしてます。
日時と呼び出し元の内線番号、引数で受け取った2つのテキストを出力します。例えば”called”と”501”を受け取ると
$ sudo cat /tmp/test.log
2018/12/04 19:02:51 103 called 501
と、ログに追記で出力します。
/usr/share/asterisk/agi-binにlog.phpという名前で作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/bin/php -q <?php require('phpagi.php'); $agi = new AGI(); $action = $argv[1]; $target = $argv[2]; $callerid = $agi->request['agi_callerid']; $extension = $agi->request['agi_extension']; file_put_contents("/tmp/test.log", date("Y/m/d H:i:s") . " $callerid $action $target\n", FILE_APPEND | LOCK_EX); ?> |
作成したら所有者を変更して、実行権限をつけます。
$ sudo chown asterisk:asterisk log.php
$ sudo chmod u+x log.php
動かしてみる
では動かしてみます。まずは単純に501に内線したら、ログ出力されるようにします。
/etc/asterisk/extensions.confの[default]コンテクストに一行追加します。
1 |
exten => 501,1,AGI(log.php,"called",${EXTEN}) |
${EXTEN}はエクステンションが入っている変数です。今回の場合は、501になります。
ダイヤルプランをリロードします。
$ sudo asterisk -r
raspberrypi*CLI> dialplan reload
501に内線すると/tmp/test.logにログが出力されます。
続いて、先日作ったメニューに組み込んでみます。テスト用に作った501は消してます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
[default] exten => _10Z,1,Dial(SIP/${EXTEN},30,r) same => n,Hangup() exten => 201,1,Answer() same => n,Playback(hello-world) same => n,Hangup() exten => 301,1,Goto(menu,s,1) exten => 401,1,Answer() same => n,Record(recordings/test.gsm) same => n,Hangup() exten => 411,1,Answer() same => n,Playback(recordings/test) same => n,Hangup() [menu] exten => s,1,Answer() same => n,AGI(log.php,"connected") same => n,agi(googletts.agi,"電話ありがとうございます。",ja,any,1.3) same => n(loop),agi(googletts.agi,"1か2を押してください。9で終了します。",ja,any,1.3) same => n,WaitExten() exten => 1,1,Agi(log.php,"pushed",${EXTEN}) same => n,Agi(googletts.agi,"1を押しました。",ja,any,1.3) same => n,Wait(1) same => n,Goto(s,loop) exten => 2,1,Agi(log.php,"pushed",${EXTEN}) same => n,Agi(googletts.agi,"2を押しました。",ja,any,1.3) same => n,Wait(1) same => n,Goto(s,loop) exten => 9,1,Agi(log.php,"pushed",${EXTEN}) same => n,Agi(googletts.agi,"さようなら。",ja,any,1.3) same => n,Wait(1) same => n,Agi(log.php,"disconnected") same => n,Hangup() exten => i,1,Agi(log.php,"pushed",${INVALID_EXTEN}) same => n,Agi(googletts.agi,"その番号はダメです。",ja,any,1.3) same => n,Wait(1) same => n,Goto(s,loop) exten => t,1,Agi(log.php,"timeout") same => n,Agi(log.php,"disconnected") same => n,Hangup() |
iエクステンションでは${INVALID_EXTEN}に押された番号が入ります。今回新たにtエクステンションを追加しています。これはタイムアウト時に呼ばれます。
301に内線するとメニューのアナウンスが流れるので、指示にしたがってボタンを押すと、ログに記録されます。
sudo tail -f /tmp/test.log
しておくと、リアルタイムに内容がみれます。
感想
今回はテキストにログを吐き出しただけですが、このログを集計するだけでも電話を使ったアンケートシステムになりそうですね。外部スクリプトが動かせるということは、プログラムでできることはなんでもできるということですので、色々と面白いことができそうです。