Cisco 7961G電話機にツイッターを表示する

題名は7961電話機となっているがCiscoの電話機の設定は(ある程度)互換性があるので他の機種でも使える筈。

CiscoのIP電話では電話機がアイドル状態になったときに(指定時間後に)指定したコンテンツを電話機の画面に表示させることができる。
このアイドル時のコンテンツ表示は基本は固定(1コンテンツを表示したまま)だけど、HTTPレスポンスヘッダのRefreshで時間とリダイレクト先の指定を行うと(HTMLコンテンツと同じく)コンテンツの表示を自動更新できる。

電話機に表示するコンテンツを自動更新する基本

7961G電話機の基本的な設定は「Cisco7961Gの設定

電話機の設定に追加・変更するもの (テスト用)
1
2
3
4
5
6
<device>
  中略
  <idleURL>http://local.example.com/idleA.xml</idleURL>
  <idleTimeout>60&ft;/idleTimeout>
  中略
</device>

電話機がアイドル状態になって60秒経つとidleURLに指定したコンテンツを電話機の画面に表示する。
これに対応するようウェブサーバ側を設定する。

Nginxの設定例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
server {
  listen :80;
  server_name local.example.com;
  #中略
  location /idleA.xml {
    add_header 'Refresh' '10; url=http://local.example.com/idleB.xml';
  }
  location /idleB.html {
    add_header 'Refresh' '10; url=http://local.example.com/idleA.xml';
  }
  #中略
}
表示するコンテンツの例 (上のidleA.xml, idleB.xml)
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<CiscoIPPhoneText>
  <Title>お知らせ</Title>
  <Text>コンテンツ本文</Text>
</CiscoIPPhoneText>

日本語を書く場合CiscoのドキュメントではShift_JISにしろということになっているが、上の例のようにエンコード指定するならUTF-8で問題無いみたい。

ここまで出来たら、ウェブサーバの設定変更を反映させるために設定を読み直させる。

FreeBSD上のNginxの場合
# service nginx reload
または
# /usr/local/etc/rc.d/nginx reload

電話機の設定を変更したら電話機をリセットする。
受話器を置いた状態で[directory]キーまたは[settings]キーを押してから[*][*][#][*][*]を押して再起動(リセット)を待つ。

上の設定例を試すと
idleA.xmlを表示すると10秒後にidleB.xmlにリダイレクトする。
idleB.xmlを表示すると10秒後にidleA.xmlにリダイレクトする。
要するにidleA.xmlとidleB.xmlを交互に10秒ずつ表示する。

これはidleA.xml, idleB.xmlがプレーンなXMLテキストファイル(静的コンテンツ)として作成される場合を想定したもの。
シンプルすぎるけど、コールセンターの電話機であればオペレータ向け超簡易版デジタルサイネージ(単なるお知らせ)みたいな使い方としてはアリかもしれない。

実際の運用ではテキストファイルを書いてウェブサーバに置くのではなくCGI等で動的にコンテンツを生成するであろうからHTTPレスポンスヘッダはCGI側で出力する筈。となるとウェブサーバ側でHTTPレスポンスヘッダを付ける必要はない筈。(ウェブサーバ側で付けたらダメじゃないけど)

ツイッターのタイムラインを電話機に表示する

ここからが本題

電話機の画面にツイッターのタイムラインを表示させる。電話機のアイドルタイムが60秒を超えたらタイムラインを表示。以降、60秒ごとにタイムラインの表示を更新する。取得頻度を上げて取り続けるとツイッター側から取得制限がかかるので注意する。120秒程度に伸ばす方が安全かも。
電話機の画面が狭いので表示するのは最新1,2ツイートだけで十分だと思うが一応3つ取る。
前回表示以降にタイムラインにツイートが増えていようがいまいが常に最新を取って表示するという単純なものにする。

電話機の設定に追加・変更するもの (上で追加したテスト設定は消す)
1
2
3
4
5
6
<device>
  中略
  <idleURL>http://local.example.com/idle.php</idleURL>
  <idleTimeout>60</idleTimeout>
  中略
</device>

twitter取得にはTwitterOAuthを使う。それについてはNanoPi NEOがTwitterを声でツブヤクンデスに書いているのでこの記事では入手方法等は省略。

idle.php
 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
<?php
require_once("./twitteroauth/autoload.php");
use Abraham\TwitterOAuth\TwitterOAuth;

date_default_timezone_set('Asia/Tokyo');

$consumerKey = 'KeyKeyKeyKeyKeyKeyKeyKey';
$consumerSecret = 'SecretSecretSecretSecretSecretSecretSecretSecret';
$accessToken = 'TokenTokenTokenTokenTokenTokenTokenTokenTokenToken';
$accessTokenSecret = 'TokenSecretTokenSecretTokenSecretTokenSecret';
//認証
$connection = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);

//タイムライン取得
$timeline = $connection->get('statuses/home_timeline', ['count' => '3']);
//var_dump($timeline);

$twout = "";
foreach($timeline as $tw){
    //ツイートIDと時刻
    $twout .= $tw->user->name . " " . date('Y-m-d H:i:s', strtotime($tw->created_at)) ."\n";
    //ツイート本文中のURLは消す
    $twout .= preg_replace('/https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+/', '', $tw->text) . "\n\n";
}

// ↑ twitter  ↓ XML出力

header('Content-Type: text/xml');  //レスポンスヘッダ XMLコンテンツとする
header("Refresh: 60;");                     //レスポンスヘッダ 60秒で更新

$dom = new DomDocument('1.0', 'utf-8');
$dom->formatOutput = true;

$out = $dom->appendChild($dom->createElement('CiscoIPPhoneText'));
$out->setAttribute("WindowMode", "Wide");
$out->appendChild($dom->createElement('Title', 'twitter'));
$out->appendChild($dom->createElement('Text', $twout));
echo $dom->saveXML();
?>

TwitterOAuthの2.0以降ではcomposerで指示通りにTwitterOAuthをインストールしないとcaBundleが無いだののエラーで困るかも。で、composerでTwitterOAuthをインストールしたなら2行目のPathは適切に変更。

CiscoのドキュメントにはCiscoIPPhoneTextで属性にWindowModeを指定できるようなことは書いてなかったように思うけど試してみたら機能したのでWideを指定してテキスト表示エリアを電話機の画面横いっぱいに拡げている。できればテキストエリア下のプロンプト表示用の領域もテキスト表示用に使いたいところだけどドキュメントにそれらしいのが載っていないので諦めた。

ここまで出来たら電話機をリセットする(前述)。
PHPでHTTPレスポンスヘッダを出すようにしているのでこの記事最初の設定例のようなウェブサーバに何か追加するというのは特には要らない。

電話機にツイッターのタイムラインを表示する
電話の操作をしない(アイドル)状態で60秒後に電話機にツイッターのタイムラインが表示されるようになった。これが自動更新される。もちろん更新されるまでにツイートが増えてなれば表示は変わって見えない。

これで電話機を見る回数が増えるかしら?・・・・実はこれを作ってから暫く経つんだけど増えなかった。もう少し画面の情報量が多くないとねぇ。せめて1画面に5ツイート程度表示できれば電話機でツイートを読もうかなという気にもなるところなんだけど。

関連記事:

Cisco 7961G電話機のサービスメニュー設定

題名は7961GとなっているがCiscoの電話機の設定は(ある程度)互換性があるので他の機種でも使えるかも。

Cisco 7961G電話機のメニュー設定 1
電話機の前面。業務用の多機能電話としてはそんなにボタンは多くない。ボタンを増やしたければオプションの拡張モジュールで電話機の隣に増設するということらしい。

Cisco 7961G電話機のメニュー設定 2
この記事はこのボタンに対応するメニューや機能について。

7961G電話機の基本的な設定は「Cisco7961Gの設定

SEPxxxxxxxxxxxx.cnf.xml (xxxxxxxxxxxxは電話機のMACアドレス)
 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
52
53
54
55
<?xml version="1.0" encoding="UTF-8"?>
<!-- エディタ用UTF-8日本語識別コメント -->
<device>
  中略
  <phoneServices useHTTPS="false">
    <provisioning>2</provisioning>

    <phoneService type="1" category="0">
      <name>Missed Calls</name>
      <url>Application:Cisco/MissedCalls</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="1" category="0">
      <name>Received Calls</name>
      <url>Application:Cisco/ReceivedCalls</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="1" category="0">
      <name>Placed Calls</name>
      <url>Application:Cisco/PlacedCalls</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="1" category="0">
      <name>電話帳</name>
      <url>http://local.example.com/directory.xml</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="2" category="0">
      <name>Voicemail</name>
      <url>Application:Cisco/Voicemail</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="2" category="0">
      <name>メッセージ</name>
      <url>http://local.example.com/messages.xml</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
    <phoneService type="0" category="0">
      <name>サービス</name>
      <url>http://local.example.com/services.xml</url>
      <vendor></vendor>
      <version></version>
    </phoneService>
  </phoneServices>

  <informationURL>http://local.example.com/information.xml</informationURL>
  <servicesURL>http://local.example.com/services.xml</servicesURL>
  中略
</device>

サービス関係のメニューやメッセージはウェブサーバを利用する。そこで、phoneServicesはHTTPSかそうでないかを指定する。

provisioningは0,1,2を指定するが、0はphoneServicesの指定だけを有効にする場合。1はphoneServicesを無効にしてdirectoryURL, servicesURL, messagesURLの指定を有効にする。2はphoneServices, directoryURL, servicesURL, messagesURLの全てを有効にする。ただし、phoneServicesとそれ以外の設定が競合する場合の挙動が不明。

phoneServicesの中は項目としてphoneServiceを書く。phoneServiceのtypeは0,1,2を指定するが、0はサービスボタン(アプリケーションボタン)に割り当てる項目、1はディレクトリボタンに割り当てる項目、2はメッセージボタンに割り当てる項目。
カテゴリーは不明(がとらぼの中の人が理解していない)なので全て0を指定している。
nameは項目名で電話機のメニューに表示される。日本語も使用可能。
urlにはウェブサーバ上のメニューXMLやスクリプト等の場所を指定する。
venderとsersionは何を指定するものか不明且つ不要そうだが、phoneServiceを指定してこの項目を省略すると(少なくとも7961Gでは)設定ファイルの読み込みエラーになるので省略しない。(重要)

informationURLは電話機のインフォメーションボタンを推した場合に読み込まれる(表示する)ファイルのURLを指定する。これはphoneServicesでは指定できないみたい。(7961Gでは)
servicesURLは電話機のサービスボタンを押した場合に読み込まれる(表示する)ファイルのURLを指定する。phoneServicesでの指定と競合しそうだが、servicesURLとphoneServicesの両方が存在しないと何故かサービスボタンを押しても「設定されていません」の表示が出る(7961G SIP9-4-2SR3で)。両方指定するとPhoneServicesの指定が優先されるみたい。
上の設定例では指定していないが、directoryURLを指定すると標準のディレクトリボタンの「不在着信」「着信履歴」「発信履歴」が表示されなくなりdirectoryURLで指定したファイルの内容が表示される。
directoryURLを指定せずにphoneServicesを指定する場合はApplication:Cisco/MissedCalls (不在着信), Application:Cisco/ReceivedCalls (着信履歴), Application:Cisco/PlacedCalls (発信履歴)を指定しないとそれらが表示されなくなる。
逆に指定した場合は指定したnameが勝手に日本語表示になる。(挙動の詳細不明)

Cisco 7961G電話機のメニュー設定 3
上の設定例でディレクトリボタンを押した時の表示。4番に「電話帳」という項目が増えている(ように見える。実際には先の設定のとおりApplication:Cisco/hogeで不在・着信・発信履歴も指定している)。

Cisco 7961G電話機のメニュー設定 4
電話帳を開いた。設定は以下。

http://local.example.com/directory.xml
 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
<?xml version="1.0" encoding="UTF-8"?>
<CiscoIPPhoneDirectory>
    <Title>電話帳</Title>
    <Prompt>選択してください</Prompt>
    <DirectoryEntry>
      <Name>01伊藤博文</Name>
      <Telephone>0001</Telephone>
    </DirectoryEntry>
    <DirectoryEntry>
      <Name>02黒田清隆</Name>
      <Telephone>0002</Telephone>
    </DirectoryEntry>
    <DirectoryEntry>
      <Name>03山縣有朋</Name>
      <Telephone>0003</Telephone>
    </DirectoryEntry>
    <DirectoryEntry>
      <Name>04松方正義</Name>
      <Telephone>0004</Telephone>
    </DirectoryEntry>
中略
    <DirectoryEntry>
      <Name>32吉田茂</Name>
      <Telephone>0032</Telephone>
    </DirectoryEntry>
</CiscoIPPhoneDirectory>

CiscoIPPhoneDirectoryを使うと単純な電話リストが表示できる。ただし、最大で32項目(32名)しか記入できない。32項目を超えて書くと33人目以下が表示されないのではなくXML読み込みエラーになる。(ちょっと困った仕様)
なお、7961Gでは表示の上下移動(スクロール)が非常に遅いので僅か32項目でも端から端への移動はイライラする。あと、画面上に実質2項目(2名)しか表示されないのが不満。名前だけ表示で1名1行でいいのに何で2行使うのかしら?

中規模(普通規模)の電話帳にするなら50音でサブメニューを作成し、その下にCiscoIPPhoneDirectoryでリストを作成するとか、大規模な電話帳ならCGIでLDAP, データベース, CardDAVなどから検索したり小分けリストを表示するようにするのが良さそう。既にそういうのは作成されててググれば出てくるけど古すぎてそのままでは使えないのも多い。

Cisco 7961G電話機のメニュー設定 5
インフォメーションをボタンを押した。上の例の設定は以下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?xml version="1.0" encoding="UTF-8"?>
<CiscoIPPhoneTex>>
   <Title>インフォメーション</Title>
   <Prompt>確認したら[終了]を押してください</Prompt>
   <Text>昨日、近所の吉野家行ったんです。吉野家。
そしたらなんか人がめちゃくちゃいっぱいで座れないんです。
で、よく見たらなんか垂れ幕下がってて、150円引き、とか書いてあるんです。
もうね、アホかと。馬鹿かと。
お前らな、150円引き如きで普段来てない吉野家に来てんじゃねーよ、ボケが。</Text>
</CiscoIPPhoneText>

CiscoIPPhoneTextを使うと単純にテキストを表示するだけの画面を作成できる。
上の画像ではテキスト内で改行していないけど、設定のText内で改行したらそれは改行として有効。

上のXMLの1行目は日本語を含むテキストをUTF-8で保存する場合に書く。1行目を無しにする場合はShift-JISで保存する必要があるみたい。

Cisco 7961G電話機のメニュー設定 6
メッセージボタンを押した時の表示。下に「ボイスメール」と「メッセージ」が表示される。この記事ではこれだけ。

Cisco 7961G電話機のメニュー設定 7
上の設定例ではサービスボタン(アプリケーションボタン)を押すとサービス画面に「サービス」がもう一度表示される。それを選択すると上の画像。CiscoIPPhoneIconFileMenuを使うとアイコンを使ったメニュー画面を作成できる。

 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
<?xml version="1.0" encoding="UTF-8"?>
<CiscoIPPhoneIconFileMenu>
  <Title IconIndex="2">アイコンメニューのサンプル</Title>

  <IconItem>
    <Index>1</Index>
    <URL>http://local.example.com/images/alerm.png</URL>
  </IconItem>
  <IconItem>
    <Index>2</Index>
    <URL>http://local.example.com/images/clock.png</URL>
  </IconItem>
  <IconItem>
    <Index>3</Index>
    <URL>http://local.example.com/images/tenki.png</URL>
  </IconItem>
  <IconItem>
    <Index>4</Index>
    <URL>http://local.example.com/images/twitter.png</URL>
  </IconItem>

  <MenuItem>
    <Name>モーニングコール</Name>
    <IconIndex>1</IconIndex>
    <URL>http://local.example.com/apps/morningcall/morning.php</URL>
  </MenuItem>
  <MenuItem>
    <Name>時報</Name>
    <IconIndex>2</IconIndex>
    <URL>http://local.example.com/apps/clock.php</URL>
  </MenuItem>
  <MenuItem>
    <Name>天気予報</Name>
    <IconIndex>3</IconIndex>
    <URL>http://local.example.com/apps/wheather.php</URL>
  </MenuItem>
  <MenuItem>
    <Name>twitter</Name>
    <IconIndex>4</IconIndex>
    <URL>http://local.example.com/apps/twitter/timeline.php</URL>
  </MenuItem>
 </CiscoIPPhoneIconFileMenu>

アイコンは電話機に登録されているものを使うことも可能だが、数が極端に少ないのと使い途に困るのしかないのでウェブサーバに20x20ドット程度のPNGで作成したファイルを置いてそれを使う方が良さそう。
IconItemとMenuItemが対になって1つの項目を構成する。

このサービス画面関係の良いところはボタンを押す度に毎回ウェブサーバから最新のファイルを取って表示してくれるところ。電話機をリセットせずにコンテンツを更新できるのでとても使い物になる。

この記事では一番簡単な例しか紹介していないけど、豊富にXMLのオブジェクトが用意されているのでいろいろやれそうな気にはさせてくれる。詳しくはCisco公式のドキュメント「CiscoIPPhone XML Objects

関連記事:
Up