Androidの赤外線機能を使ってテレビを操作してみた

使わないでホコリを被っていたAndroid端末に赤外線機能が付いていたので、テレビリモコンとして使えないかイジイジしてみたお話です。

# 環境
端末名：HUAWEI honor8
テレビ：SHARP AQUOS LC-32H11

# ConsumerIrManager
赤外線機能を使うには `ConsumerIrManager` を使います。APIレベルは19。
https://developer.android.com/reference/android/hardware/ConsumerIrManager

`getSystemService` で `CONSUMER_IR_SERVICE` を指定する形です。

```kotlin

val consumerIrManager = getSystemService(Context.CONSUMER_IR_SERVICE) as ConsumerIrManager
```

# パーミッションの追加

`ConsumerIrManager` のメソッドをそのまま使おうとすると `java.lang.SecurityException: Requires TRANSMIT_IR permission` という例外が発生してしまうので、パーミッションを追加する必要があります。

```xml
<uses-permission android:name="android.permission.TRANSMIT_IR" />
```

`TRANSMIT_IR` というなかなか見慣れないパーミッションですが、これでOKでした。

# 赤外線機能が使えるのかどうかのチェック
今回は赤外線機能がある端末で検証しておりますが、赤外線機能が無い端末の場合に `ConsumerIrManager` のメソッドを使うと `java.lang.UnsupportedOperationException: IR emitter not available`
という例外が発生するため、そもそも赤外線機能があるのかどうかのチェックもすることができます。

```kotlin
if (consumerIrManager.hasIrEmitter()) {
  // ある場合
} else {
  // 無い場合
}
```

`hasIrEmitter()` メソッドで赤外線機能があるかどうかがわかるので、シンプルにそれを使えばOKでした。

# 赤外線を送信する
本題となる赤外線送信に関して。

`transmit` メソッドを使います。
https://developer.android.com/reference/android/hardware/ConsumerIrManager.html#transmit(int,%20int[])

引数は2つで `carrierFrequency` と `pattern` 。

### carrierFrequency
`carrierFrequency` は日本語に訳すと「キャリア周波数」らしいですが、正直さっぱり :sweat: 

リモコンの場合は、 http://www.256byte.com/remocon.htm のページによると
> 一部のリモコンを除いた大抵のリモコンでは38kHzが利用されています。

とのことで、実際に `38000` を指定したらOKでした。

### pattern
これは赤外線のパターンで、リモコンの場合各ボタンに対してパターンがある、という感じみたいです。

今回はSHARP製のテレビだったので色々と調べたところ、👇のリポジトリに各ボタンに対するパターンがまとまっておりまして、ここに記載のある値を拝借して使ってみたところOKでした。 :pray: 
https://github.com/misscrocodile/sharp-remote/blob/master/remoteControl/remoteControl.ino

# サンプルコード
以上のことを踏まえたサンプルコードは下記のような感じです。

```kotlin

enum class Pattern(val value: IntArray) {
    ON_OFF(
        arrayListOf(3350, 1700, 400, 400, 450, 1200, 450, 400, 450, 1250, 400, 400, 400, 1300, 400, 400, 400, 1250, 450, 400, 400, 1250, 400, 400, 450, 1250, 400, 1250, 400, 400, 450, 1250, 400, 400, 450, 1250, 400, 1250, 400, 1300, 400, 1250, 400, 400, 400, 400, 450, 400, 450, 1200, 450, 400, 400, 1300, 400, 400, 400, 400, 450, 1250, 400, 400, 450, 400, 400, 400, 450, 400, 450, 1250, 400, 1250, 400, 400, 450, 1250, 400, 400, 450, 400, 400, 400, 450, 1250, 400, 400, 450, 400, 400, 400, 450, 1250, 400, 400, 450, 1200, 450, 1250, 400).toIntArray()
    )
    // ... 他のパターン
}
```

```kotlin
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // ON/OFFボタン押下でON/OFFのパターンを送信
        findViewById<View>(R.id.button_on_off).setOnClickListener {
            val consumerIrManager =
                getSystemService(Context.CONSUMER_IR_SERVICE) as ConsumerIrManager
            if (consumerIrManager.hasIrEmitter()) {
                consumerIrManager.transmit(38000, Pattern.ON_OFF.value)
            } else {
                Toast.makeText(this, "赤外線未対応です。", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
```

# 実際の様子
非常にわかりにくく、ガッキーが写っていることに目が行っちゃいますが、ボタン押下でテレビのON/OFFが切り替わっている様子です。
![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/f575ab3d-3f24-d54c-6fde-4c1612bac3d2.gif)

# まとめ
とりあえず赤外線に関して全く理解しておりませんが、Androidからテレビの操作をすることができました。

`ConsumerIrManager` を使うことで、思いの外簡単に赤外線通信ができるので、例えばプッシュ通知を受け取ったタイミングで赤外線通信を行うなどの仕組みを作れば、IoT的なことも実現できそうだなと思いました。

# 参考Qiita
Android向け赤外線送信アプリ作成した時の備忘録
https://qiita.com/h-adachi/items/9d70d46904734ffced6a