IRKitとHTML(jquery + bootstrap)でカスタムテレビリモコンを作ってみる(その壱)
Webサーバの準備
JavaScriptとHTMLを使ってIRKitを操作するWebUIを作ってみようと思う。
ローカルHTMLでもいいが、できればLAN内のWebサーバに配置したい。
PCを常時起動しておくのは省エネじゃないので、NAS上に構築できないか調べてみる。
NASはRockDiskNext。rootでログインしていろいろカスタマイズできるいい感じのNAS。
telnetでログインしてpsで見てみるとlighttpdが動いている。
[root@xxxxxx]# ps axuw lighttpd 1242 0.0 0.5 7044 1312 ? S Oct18 9:25 /usr/sbin/lighttpd -f /etc/nas/lighttpd.conf
設定ファイルはlighttpd.confのはずなのでfindしてみると/etc/nas/lighttpd.confが見つかった。
内容見てみるとdocument rootは/var/www/nasになっている。
ためしに/var/www/nas/test.htmlを作って、ブラウザからアクセスしてみると問題なく表示できた。
Webサーバはこれでよさそう。
まずはローカルのHTMLでWeb UIを作って、できあがったらNAS上の配置する作戦でいこうと思う。
IRKitの動作確認
AppStoreにあるIRKit標準のシンプルリモコンでIRKitの動作を確認する。
シンプリリモコンアプリに表示される手順通りに実行して、問題なくIRKitと接続できた。
ためしにBDレコーダのリモコンの学習させて、操作してみた。
IPアドレスの固定
次にHTTP RESTをつかってIRKitを操作してみるが、その前にIRKitのアドレスを調べる。
やりかたはIRKitの公式サイトに書いてある。Bonjourを使って検索する。
http://getirkit.com
$ dns-sd -B _irkit._tcp Browsing for _irkit._tcp DATE: ---Sat 29 Nov 2014--- 23:07:45.773 ...STARTING... Timestamp A/R Flags if Domain Service Type Instance Name 23:07:47.550 Add 2 4 local. _irkit._tcp. irkitXXXX $ dns-sd -G v4 irkitXXXX.local DATE: ---Sat 29 Nov 2014--- 23:08:30.352 ...STARTING... Timestamp A/R Flags if Hostname Address TTL 23:08:30.971 Add 2 4 irkitXXXX.local. 192.168.0.2 15
その後、アドレスが変更されないようにルータのDHCPサーバ設定をする。
IRKitのMACに割り当てるIPアドレスをさっき調べたものに固定しておく形。
コマンドラインから実行
curlを使ってコマンドラインからREST URLを叩いてIRKitが操作できることを確認する。
まずは赤外線信号をキャプチャ。GET /messagesで最後に受診した赤外線信号情報を取得できる。
$ curl -i "http://192.168.0.2/messages" HTTP/1.0 200 OK Access-Control-Allow-Origin: * Server: IRKit/2.0.2.0.xxxxxxxx Content-Type: text/plain {"format":"raw","freq":38,"data":[6881,3341,904,815,904,2537,904,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,2537,904,815,904,815,904,815,904,815,904,815,904,815,904,2537,904,2537,904,815,904,2537,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,2537,904,815,904,2537,904,2537,904,815,904,815,904,815,904,815,904,2537,904,815,904,815,904,815,904,815,904,2537,935,65535,0,65535,0,17421,6881,3341,904,904,904,2537,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,2537,904,904,904,904,904,787,904,787,904,787,904,787,904,2537,904,2537,904,904,904,2537,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,787,935,787,935,2537,904,904,904,2537,904,2537,904,815,904,815,904,815,904,815,904,2537,904,904,904,904,904,904,904,904,904,2537,904]}Masashi-no-MacBook-Air:~ shizuku$
キャプチャした信号を送信。さっき GET /messagesで受診したコードをPOSTで送る。
$ curl -i "http://192.168.0.2/messages" -d '{"format":"raw","freq":38,"data":[6881,3341,904,815,904,2537,904,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,815,968,2537,904,815,904,815,904,815,904,815,904,815,904,815,904,2537,904,2537,904,815,904,2537,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,815,904,2537,904,815,904,2537,904,2537,904,815,904,815,904,815,904,815,904,2537,904,815,904,815,904,815,904,815,904,2537,935,65535,0,65535,0,17421,6881,3341,904,904,904,2537,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,2537,904,904,904,904,904,787,904,787,904,787,904,787,904,2537,904,2537,904,904,904,2537,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,787,935,787,935,2537,904,904,904,2537,904,2537,904,815,904,815,904,815,904,815,904,2537,904,904,904,904,904,904,904,904,904,2537,904]}' HTTP/1.0 200 OK Access-Control-Allow-Origin: * Server: IRKit/2.0.2.0.xxxxxxxx Content-Type: text/plain
AJAXから実行
HTML + JavaScriptをつかってREST URLを叩いてIRKitが操作できることを確認してみる。
mashさんのサンプルがあったので、これをベースにカスタマイズしていくことにする。
http://jsdo.it/mash/IRKit-jQuery-Sample
TVのリモコン信号を調査
TVのリモコンが壊れているのキャプチャができない。。。ググって赤外線の送信パターンを入手する。
http://www.256byte.com/2006/10/post_2.html
これをIRKit用のコードに変換してあげる必要がある。
IRKItのデータは赤外線のONとOFFの時間を2MHz単位でカウントした値になっている。
アクオスの赤外線のONとOFFの時間下記の通りらしい。
点灯・消灯時間は以下の表の通りです。 点灯時間 消灯時間 リーダー信号 3,500μ秒 1,600μ秒 データ 0 460μ秒 360μ秒 データ 1 460μ秒 1,200μ秒 ストップ信号 460μ秒 70,000μ秒
2MHzは1クロックあたり0.5マイクロ秒なので、
3500マイクロは、7000クロック。
1600マクロ秒は、3200クロック。
460 マイクロ秒は、920クロック。
360マイクロ秒は、720クロック。
1200マイクロ秒は、2400クロック。
...
例えば、音量は下記のコード。
音量 + 55 5A F1 48 28 8F
これをIRKitが解釈できるコードに変換する。
まず2進数にして、その後の1を920,2400に、0を920,720に変換する
あと前後にリーダ信号とストップ信号が必要なので、下記のようになる。
7000,3200,920,720,920,2400,920,720,920,2400,920,720,920,2400,920,720,920,2400,920,720,920,2400,920,720,920,2400,920,2400,920,720,920,2400,920,720,920,2400,920,2400,920,2400,920,2400,920,720,920,720,920,720,920,2400,920,720,920,2400,920,720,920,720,920,2400,920,720,920,720,920,720,920,720,920,720,920,2400,920,720,920,2400,920,720,920,720,920,720,920,2400,920,720,920,720,920,720,920,2400,920,2400,920,2400,920,2400,920,140000
コード変換が面倒なので生成ツールを作った。言語はなんでもよかったんだけどJavaが一番慣れてるので。
/** * 16進数表記の赤外線コードをIRKit用のコードに変換する * @author shizuku * */ public class IRKitCodeGenerator { public final int LEADER_ON_USEC = 3500; //リーダ信号の点灯時間 public final int LEADER_OFF_USEC = 1600;//リーダ信号の消灯時間 public final int ZERO_ON_USEC = 460; //0信号の点灯時間 public final int ZERO_OFF_USEC = 360; //0信号の消灯時間 public final int ONE_ON_USEC = 460; //1信号の点灯時間 public final int ONE_OFF_USEC = 1200; //1信号の消灯時間 public final int STOP_ON_USEC = 460; //STOP信号の点灯時間 public final int STOP_OFF_USEC = 70000; //STOP信号の消灯時間 /** * 赤外線の点灯/消灯時間(マイクロ秒)からIRKitのコードを生成する * @param on_usec * @param off_usec * @return */ private String getCode(int on_usec, int off_usec){ StringBuffer sb = new StringBuffer(); int clock_num = on_usec * 2; sb.append(Integer.toString(clock_num)); sb.append(","); clock_num = off_usec * 2; sb.append(Integer.toString(clock_num)); return sb.toString(); } /** * 16進数表記の赤外線データコードからIRKit用のコードを生成する * @param code * @return */ public String getDataCode(byte code){ StringBuffer sb = new StringBuffer(); for(int i=0; i<8; i++){ byte mask = (byte) (0x01 << (8-(i+1))); if((code & mask) == 0){ sb.append(getCode(ZERO_ON_USEC, ZERO_OFF_USEC)); sb.append(","); }else{ sb.append(getCode(ONE_ON_USEC, ONE_OFF_USEC)); sb.append(","); } } return sb.toString(); } /** * 16進数表記の赤外線コード列からIRKit用のコードを生成する * @param codeString * @return */ public String getIRKitCode(String[] codeString){ StringBuffer sb = new StringBuffer(); sb.append(getCode(LEADER_ON_USEC, LEADER_OFF_USEC)); sb.append(","); for(int i=0; i<codeString.length; i++){ int num = Integer.parseInt(codeString[i], 16); sb.append(getDataCode((byte)num)); } sb.append(getCode(STOP_ON_USEC, STOP_OFF_USEC)); return sb.toString(); } public static void main(String args[]) throws Exception{ IRKitCodeGenerator gen = new IRKitCodeGenerator(); String result = gen.getIRKitCode(args); System.out.println(result); } }