チラシのうら

レゴとか、工作とか。

IRKitってすばらしい! その2

注意

過去の記憶を遡って記載しています。20150624記

何はともあれ、ドキュメント

を確認します。
といっても、全てがIRKitのサイトに書いてある(しかも日本語!)ので、大して時間はかかりません。
15分もあれば、一通り目を通すことができます。
具体的には、IRKit-Device-APIです。

ハックステップ概要

任意のリモコンコマンドを発行するまでのハックステップは、ざっくり下記の通り。

  1. 機器発見 : IRKitをネットワーク上で発見する。
  2. 学習 : IRKitにリモコンコマンドを学習させる。
  3. GET data : 学習した結果(コマンドデータ)をIRKitから取得する。
  4. POST data : 取得したコマンドデータをIRKitへ送る。
  5. 発行 : IRKitが2.の赤外線コマンドを発行する。

順を追って記録に残していきます。

ハックステップ詳細

1. 機器発見

IRKitをおうちのネットワークに繋いだ状態からスタートします。
IRKitのAPIIPアドレスがわかれば即座に叩けるので、まずは、IPアドレスを取得したいです。

この方法は世の中には幾つかありますが、IRKitでは、Appleさん謹製のBonjourという機器発見プロトコルを使って見つけられるそうです。

最近めちゃくちゃ動作の遅いMacMiniのターミナルから、Bonjour!と挨拶してみました。

手順書通りで確かに取得できました。

% dns-sd -B _irkit._tcp  
(中略)  
Instance Name 23:12:55.768 Add 2 4  
 local. _irkit._tcp. irkitd2a4  
^C  
  
% dns-sd -G v4 irkitd2a4.local    
(中略)  
Hostname         Address  
irkitd2a4.local. 10.0.1.2  

この例ですと、IPアドレスとして、 10.0.1.2がとれています。

2. 学習

IRKitは常に学習Readyとなっていますので、IRKitに向かってリモコンを向けて、リモコンのボタンを押すだけです。
簡単。

IRKitのLEDが点滅したら、(たぶん)学習出来ています。 f:id:tetunori_lego:20150625061718j:plain
おうちではカウンターの下に貼り付けてます。

3. 学習データのGET

それでは、2.で学習させたリモコンコードを読み出してみたいと思います。
やることは単純です。(手段はともかく)1.で取得したIPアドレス/messagesに対してGET発行するだけです。

GET from http://10.0.1.2/messages

すると、以下のような値(★1)が返ってきます。後でコピペするだけなので、データを理解する必要はありません。

{"format":"raw","freq":38,"data":[18031,(中略), 4400,1190]}

リモコン学習データがとれたので、いよいよ、発行してみます。

4. IRKitへデータを送る

これも簡単です。GETと同じ口に★1のデータをPOSTするだけです。

POST to http://10.0.1.2/messages ★1

5. リモコンコマンド発行(発光)

これで、めでたくIRKitからリモコンコマンドが発行され、おうちの中の何かが動いたと思います。

ツールを作る。

コマンドラインからばっかりだと、データをコピペするのも面倒になってくるので、ツールを作ります。
こだわりはないので、一番速く実現出来そうな、html/jsで書いてみます。 f:id:tetunori_lego:20150624075724j:plain
chromeブラウザでは動作確認済み。

単純なプログラムですが、家中の機器をブラウザから制御できるのは、新感覚。 実にスマートホームっぽいです。

これを使って、リモコンコードデータベースも出来上がったので、いよいよスマホアプリに実装してみようかと思います。

その他ノウハウ

  • 得られたリモコンコードは、毎回少しずつ違っている事がある。でも、どれも動く。
  • 長いデータだな、と思って良く見ると、同じコードの繰り返し(3回位)だったりする。繰り返し部は削除して、最初の部分だけにしても、動作した。
  • 窓の近く、お昼過ぎにコウコウと太陽の光が注ぐと、IRKitから発行しても届かない(?)場合がある。

コードはこちら

index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>IRKit JavaScript Test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
</head>

<body>
<br>
<br>

<textarea name="log_textarea" cols="50" rows="5"></textarea>
<br>
<br>

<div id="Rows" ></div>

<!--div id="test" >
   <input type="text" readonly name="command_label_1">
   <input type="button" disabled name="btGet_1" value="GET" onclick="onClickedGet( 1 );">
   <input type="button" name="btPost_1" value="POST" onclick="onClickedPost( 1 );">
   <input type="text" name="gotten_data_1">
   <br>
   <br>

   <input type="text" readonly name="command_label_2">
   <input type="button" disabled name="btGet_2" value="GET" onclick="onClickedGet( 2 );">
   <input type="button" name="btPost_2" value="POST" onclick="onClickedPost( 2 );">
   <input type="text" name="gotten_data_2">
   <br>
   <br>

   <input type="text" name="command_label_3">
   <input type="button" name="btGet_3" value="GET" onclick="onClickedGet( 3 );">
   <br>
   <br>
</div-->

<script src="./js/irkit_test.js"></script>
</body>

</html>

irkit_test.js

var gCurrentRowNum = 0;
var gArrayRowCmdName = new Array(20);
var gArrayRowData = new Array(20);

initialize();

function initialize(){
  output_textarea("initialize is called!");
  var elm = document.getElementById( "Rows" );
  elm.innerHTML = '';
  addRow();
};

function output_textarea( text ){
  var objTextarea = document.getElementsByName('log_textarea')[0];
  objTextarea.value += text;
  objTextarea.value += "\n";
}


function onClickedGet( currentIndex ){
  output_textarea( "onClickedGet is called." );
  output_textarea( "currentIndex is " + currentIndex );
  
  if( document.getElementsByName('command_label_' + currentIndex)[0].value == "" ){
    alert("Please Enter command name.");
    return;
  }
  
  if( currentIndex > 20 ){
    output_textarea( "Fully registrated..." );
    alert("Fully registrated... Please Reflesh by F5!" );
    return;
  }else{
    addRow();
  }
  
  preparePost( currentIndex );
  
  getIRData( currentIndex );
  
}

function onClickedPost( currentIndex ){
  output_textarea( "onClickedPost is called." );
  output_textarea( "currentIndex is " + currentIndex );
  
  sendIRData( currentIndex );
  
}

function addRow(){
  
  var i = 0;
  var numNextIndex = gCurrentRowNum + 1;
  var elm = document.getElementById( "Rows" );
  var obj = '<div id="Row_' + numNextIndex + '"><input type="text" name="command_label_' + numNextIndex + '">' + 
         '<input type="button" name="btGet_' + numNextIndex + 
         '" value="GET" onclick="onClickedGet( ' + numNextIndex + ' );"></div>' + 
         '<br>';
  
  for( i = 1; i < gCurrentRowNum + 1; i++ ){
    gArrayRowCmdName[i-1] = document.getElementsByName('command_label_' + i)[0].value;
    if( gCurrentRowNum != i ){
      gArrayRowData[i-1] = document.getElementsByName('command_data_' + i)[0].value;
    }
  }
  
  elm.innerHTML += obj;
  
  for( i = 1; i < gCurrentRowNum + 1; i++ ){
    document.getElementsByName('command_label_' + i)[0].value = gArrayRowCmdName[i-1];
    if( gCurrentRowNum != i ){
      document.getElementsByName('command_data_' + i)[0].value = gArrayRowData[i-1];
    }
  }
  
  gCurrentRowNum++;
  
}

function preparePost( currentIndex ){
  document.getElementsByName('command_label_' + currentIndex)[0].readOnly = true;
  document.getElementsByName('btGet_' + currentIndex)[0].disabled = true;
  
  var elm = document.getElementById( "Row_" + currentIndex );
  var obj = '<input type="button" name="btPost_' + currentIndex + 
         '" value="POST" onclick="onClickedPost( ' + currentIndex + ' );">';
  
  obj += '<input type="text" name="command_data_' + currentIndex + '">'
  
  elm.innerHTML += obj;
  document.getElementsByName('command_label_' + currentIndex)[0].value = gArrayRowCmdName[currentIndex-1];
  
}

/* Constants */
var HTTP_SCHEME_STRING = "http://";
var IRKIT_IP_ADDR = "10.0.1.2";
var API_CONTROL_PORT = "/messages";

function getIRKitURL()
{
  
  return HTTP_SCHEME_STRING + IRKIT_IP_ADDR + API_CONTROL_PORT;
  
}

function postWebAPI( webAPI_command, callback_func )
{
  var url = getIRKitURL();
  
  jQuery.ajax( url, { crossDomain: true, type: "POST", dataType: 'text', 
               data: webAPI_command ,
    success: function(result){
      output_textarea( "Post Success" );
    }
  });
 
}

function sendIRData( currentIndex )
{
  
  output_textarea( "sendIRData is called." );
  
  var data = document.getElementsByName('command_data_' + currentIndex)[0].value;
  
  var webAPI_command = JSON.stringify( data );
  postWebAPI( webAPI_command, sendIRDataCallback );
  
}

// getIRData
function getIRData( currentIndex )
{
  
  output_textarea( "getIRData is called." );
  output_textarea( "currentIndex is " + currentIndex );
  
  var url = getIRKitURL();
  
  jQuery.ajax( url, { crossDomain: true, type: "GET", dataType: 'text', success: function(text){
    output_textarea( text );
    document.getElementsByName('command_data_' + currentIndex)[0].value = text;
    output_textarea( "GET method success!" );
  }});
  
}

// unused....
function sendIRDataCallback( responseText )
{
  
  output_textarea("sendIRDataCallback is called.");
    output_textarea("responseText is " + responseText);
  
}