LoginSignup
5
4

More than 5 years have passed since last update.

NatureRemoでテレビをマクロ操作しようとした話

Last updated at Posted at 2019-01-15

はじめに

この半年ほど、TVデバイス向けのアプリ開発をしていました。
開発にあたっては当然リモコンで操作をするわけですが、
設定変更やテストをするにあたって、リモコンからの入力をPCから、
さらにはマクロ化できないかと思い試行した結果をまとめました。

NatureRemo

TVを操作するには赤外線を送出するデバイスが必要です。
Obnizあたりで作成を試みたのですが、InfraredLEDが信号を出してくれなかったので
敢え無く挫折...
結局市販のNatureRemoを使用することになりました。

*なお今回は廉価版のNatureRemoMiniを使用しています。

NatureRemoはAPIを公開しており、
https://developer.nature.global/

普通に使う分にはCloud API(http://swagger.nature.global/)
を利用してsignalsをPostすればOKです

<参考>
https://qiita.com/sohsatoh/items/b710ab3fa05e77ab2b0a

ところが、cloudAPIにはLimitationがあるため

サーバは 5分以内に30回 以上のリクエストを受けるとその後ステータスコード 429 を返す。

マクロに使うには適さなそうです。
(障害もあるし)

ということでもう一つのAPI
LocalAPI(http://local.swagger.nature.global/ )を使います

IRKit

LocalAPIには

GET messages
POST messages

の二つのAPIがあります。
パッとこれだけ置かれているので使い方がわからなかったのですが、

実装の元であるIRKitに書いてありました。
http://getirkit.com/

Localからテレビに信号を送る流れは以下のようになります。

  1. NatureRemoのIPを調べる
    公式サイトを参考にIPを調べます
    https://nature.global/jp/faq/043

  2. リモコンボタンのデータを調べる
    messagesAPI(GET)を叩いて、すかさずリモコンの任意のボタンを押します。
    terminalに送信データが表示されるのでメモります。

  3. データ送信
    messagesAPI(POST)に送信データをつけて叩きます。

マクロ化する

マクロ化するために、ボタンとテレビ信号の対応表を作ります。
NatureRemoにリモコンを登録している場合は、前述のcloudAPIで

/1/appliances

を叩くと
こんな感じでデバイスごとのボタン一覧を返してくれます

appliances.json
  "type": "TV",
  "nickname": "TV_1",
  "image": "ico_tv",
  "settings": null,
  "aircon": null,
  "signals": [],
  "tv": {
    "buttons": [{
      "name": "power",
      "image": "ico_io",
      "label": "power"
    }, {
      "name": "select-input-src",
      "image": "ico_input",
      "label": "source"
    }, {
      "name": "tv-schedule",
      "image": "ico_tv_guide",
      "label": "schedule"
    }, {
      "name": "mute",
      "image": "ico_mute",
      "label": "mute"
    }, {
      "name": "ch-1",
      "image": "ico_number_1",
      "label": "1"
    }, {
      "name": "ch-2",
      "image": "ico_number_2",
      "label": "2"
    }
  }
//続く...

このデータに信号データも入っていてくれれば話は早いのですが、
存在しないようなのでLoaclAPIで一つ一つデータを調べ...

tv_1.json
{
"power":{"format":"us","freq":36,"data":[3450,1800,392,486,394,1359,394,481,386,488,384,486,386,487,392,478,395,481,394,478,392,481,393,480,390,482,385,486,386,1366,391,480,393,481,391,482,395,475,387,487,394,477,386,487,392,478,397,477,394,1359,397,474,395,478,394,477,397,476,398,478,395,476,393,481,392,476,395,1358,395,482,388,1365,399,1354,399,1357,394,1356,394,485,417,461,394,1358,397,478,396,1359,391,1356,395,1357,393,1360,397,477,396,1357,396,65535,0,9272,3458,1795,399,483,394,1367,409,461,392,478,393,479,396,479,393,476,396,478,394,476,396,478,394,482,392,477,398,476,393,1354,396,482,391,480,393,479,394,478,393,476,396,479,393,481,393,480,394,477,393,1356,396,477,396,478,394,476,399,477,392,476,399,476,397,477,394,477,395,1357,393,486,396,1360,385,1365,395,1357,393,1355,395,486,395,481,388,1369,396,479,384,1364,394,1361,384,1364,395,1361,387,487,385,1363,395,65535,0,9279,3456,1801,391,478,394,1358,393,481,390,480,394,478,394,477,395,479,396,480,391,476,396,479,395,475,395,479,394,480,384,1367,393,483,395,483,396,483,396,482,394,484,388,491,396,483,386,495,394,482,397,1363,394,473,399,476,386,488,393,479,392,479,395,475,398,475,397,480,392,1370,380,481,391,1359,394,1356,394,1361,399,1356,391,477,395,478,397,1352,398,477,396,1355,397,1356,398,1355,396,1356,394,483,389,1357,396]},
"ch-1":{"format":"us","freq":36,"data":[3450,1802,396,478,394,1355,394,488,392,483,396,484,395,484,392,486,393,484,392,488,393,484,385,494,385,494,382,500,389,1360,396,479,394,476,394,482,392,481,391,478,385,489,394,477,394,482,389,481,392,1361,383,1367,392,479,393,481,391,1361,392,483,396,484,385,491,388,493,392,486,393,484,395,484,393,487,392,1363,392,482,390,1361,392,482,390,1356,387,489,392,480,395,1357,384,1369,393,481,395,1354,396,1357,393]},
"ch-2":{"format":"us","freq":36,"data":[3454,1797,386,492,386,1370,393,477,397,477,396,478,392,480,397,475,394,476,396,478,387,487,394,477,392,481,385,485,396,1356,394,482,392,476,394,481,393,477,397,476,394,482,391,478,394,480,393,476,398,1357,394,1357,391,488,391,486,392,1366,391,478,396,481,382,485,394,481,394,1354,399,477,385,489,383,485,387,1366,392,480,393,1358,394,483,388,491,394,485,395,484,394,1358,389,1364,399,477,392,1357,397,1354,394,65535,0,9734,3448,1806,395,475,395,1358,392,486,395,484,392,487,393,485,392,487,385,493,392,489,391,485,392,490,390,485,385,495,392,1359,398,477,389,484,394,476,394,483,382,485,396,479,385,491,382,485,386,491,389,1363,389,1357,387,489,383,485,394,1361,391,488,390,486,393,485,392,489,392,1365,392,478,394,478,396,474,394,1362,392,479,394,1354,387,487,384,486,399,476,395,478,392,1357,386,1371,386,487,384,1365,396,1357,394]},
続く...

buttonのnameをkeyにdataを紐付けたjsonを作ります。

あとはこんな感じでシナリオ書いて順々にsendするようにすればOKです
(適正なsend_spanがわからないので適当ですが)

send.js
var fs = require('fs');
var tv_1 = JSON.parse(fs.readFileSync('tv_1.json', {
    encoding: 'utf-8'
}));
var webclient = require("request");

const SEND_SPAN = 300;

const senario = ['power', 'cha-1', 'vol-up', 'vol-up', 'vol-up', 'vol-up', 'vol-up', 'vol-up', 'vol-up'];
doSenario(0, senario);

function doSenario(i = 0, list){
  if (list.length - 1 < i) return;
  sendData(list[i]);

  setTimeout(()=>{
    doSenario(i + 1, list);
  }, SEND_SPAN);
}

function sendData(key){
  const data = tv_1[key];
  console.log("データ", data);
  webclient.post({
    url: "http://hogehoge/messages",
    headers: {
      "content-type": "application/json",
      "X-Requested-With":'',
    },
    body: JSON.stringify(data)
  }, function (error, response, body){
    if(error){
     console.log("エラー", error);
    }
  });
}

まとめ

localAPIを使えばマクロ的にNatureRemoを操作することができました。

しかし、万が一シナリオ実行中に何らかの原因で一部信号が届かなかった場合、
その信号を無視してシナリオが実行されるため操作がめちゃくちゃになってしまいます。

NatureRemo単体ではテレビが現在どういったステータスなのかを把握することが
できないため、画像解析等のアプローチを試していきたいと思います。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4