Arduino Leonardo(Pro Micro)を使って赤外線リモコンをマルチメディアキーボードにする

Using Arduino Leonardo (Pro Micro) to turn an infrared remote control into a multimedia keyboard
無線キーボードではなく、学習リモコンで操作できるようにしておけば、家庭内にある様々な家電と操作を一元化できるのでマルチメディア用途に使っているのであれば、なかなか便利です。ネットショップではリモパソという商品名で1000円ほどで買うこともできますが、自作すれば、リモパソにはないキー操作も柔軟にカスタマイズできます。

一番手軽なのはArduino Leonardo(Pro Micro)に、赤外線レシーバーを接続し、信号をキーボード入力に変換するプログラムを書き込むことですが、標準のライブラリーでは基本的なキーしか制御できず、音量調整やブラウザ操作などの拡張キーは使えません。

その問題を解決する方法の一つとして「Arduino HID Project」というライブラリーを導入する方法です。このプログラムでは拡張されたHIDディスクリプタが定義されており、標準キーボードライブラリーにはないキー入力もできます。

ライブラリーを導入するにはArduino IDEのライブラリー管理より「HID-Project」をインストールするだけです。
追加で利用できるキーは「Consumer」クラスで管理されており、「Consumer.begin()」を「setup()」にて宣言させます。例えば消音キーの入力を実行したいのであれば「Consumer.write(MEDIA_VOL_MUTE);」を指定します。

また、スリープや電源ボタンは「System」クラスにまとめられており、「System.begin()」に続いて「System.write(SYSTEM_SLEEP)」のように指定します。

赤外線信号受信についてですが定番のArduinoライブラリー「IRremote」は、Ver 3.0になってから仕様が変わり、従来のプログラミングは非推奨となっています。以下は最新版による実装例ですが、「results.value」と「IrReceiver.decodedIRData.decodedRawData」の結果が異なることもあるようです。
irremote.c

// IRrecv irrecv(RECV_PIN); のようなグローバルでの宣言は不要になっている

void setup()
{
    IrReceiver.begin(RECV_PIN, DISABLE_LED_FEEDBACK);
}

void loop()
{
    if (IrReceiver.decode()) {
        Serial.println(IrReceiver.decodedIRData.decodedRawData, DEC);
        IrReceiver.resume();
    }
 }
以上を踏まえたうえでのArduinoスケッチ例がこちらです。赤外線の数値は手元にあったパナソニックのブルーレイレコーダーのリモコンの値なので、お手持ちのリモコンの信号に合わせて値を変更してください。
irremote.ino
#include "HID-Project.h"
#include <IRremote.h>
#define RECV_PIN 7
#define LED_PIN 10

#define POWER 2369585328
#define SOURCE 2231697536
#define VUP 2686451840
#define VDOWN 2703294592
#define VMUTE 2989621376
#define UP 897908912
#define RIGHT 948437168
#define DOWN 914751664
#define LEFT 931594416
#define ENTER 847380656
#define HOME 647430576
#define OPTION 813695152
#define PREV 4182311088
#define NEXT 4199153840
#define B1 2685403312
#define B2 2702246064
#define B3 2719088816
#define B4 2735931568
#define B5 2752774320
#define B6 2769617072
#define B7 2786459824
#define B8 2803302576
#define B9 2820145328
#define B0 2836988080
#define PROG 3495952560
#define BACK 830537904
#define STOP 2952790192
#define PLAY 3121217712
#define PAUSE 3053846704

#define USE_SERIAL 0

void setup()
{
#if USE_SERIAL
    Serial.begin(115200);
#endif
    IrReceiver.begin(RECV_PIN, DISABLE_LED_FEEDBACK);
    pinMode(LED_PIN, OUTPUT);
    Keyboard.begin();
    Consumer.begin();
    System.begin();
}

void loop()
{
    if (IrReceiver.decode()) {
#if USE_SERIAL
        Serial.println(IrReceiver.decodedIRData.decodedRawData, DEC);
#endif
        
        digitalWrite(LED_PIN,1);    
        delay(100); 
        digitalWrite(LED_PIN,0); 

        switch(IrReceiver.decodedIRData.decodedRawData){
        case POWER: System.write(SYSTEM_SLEEP); break;

        case VUP: Consumer.write(MEDIA_VOL_UP); break;
        case VDOWN: Consumer.write(MEDIA_VOL_DOWN); break;
        case VMUTE: Consumer.write(MEDIA_VOL_MUTE); break;

        case UP: Keyboard.write(KEY_UP_ARROW); break;
        case DOWN: Keyboard.write(KEY_DOWN_ARROW); break;
        case LEFT: Keyboard.write(KEY_LEFT_ARROW); break;
        case RIGHT: Keyboard.write(KEY_RIGHT_ARROW); break;

        case ENTER: Keyboard.write(KEY_RETURN); break;
        case HOME: Keyboard.write(KEY_ESC); break;
        case OPTION: Keyboard.write(KEY_LEFT_GUI); break;
        case BACK: Consumer.write(CONSUMER_BROWSER_BACK); break;

        case PREV: Consumer.write(MEDIA_PREV); break;
        case NEXT: Consumer.write(MEDIA_NEXT); break;
        case STOP: Consumer.write(MEDIA_STOP); break;
        case PLAY: Consumer.write(MEDIA_PLAY_PAUSE); break;
        case PAUSE: Consumer.write(MEDIA_PAUSE); break;
        case PROG: Keyboard.write(KEY_BACKSPACE); break;

        case B1: Keyboard.write('1'); break;
        case B2: Keyboard.write('2'); break;
        case B3: Keyboard.write('3'); break;
        case B4: Keyboard.write('4'); break;
        case B5: Keyboard.write('5'); break;
        case B6: Keyboard.write('6'); break;
        case B7: Keyboard.write('7'); break;
        case B8: Keyboard.write('8'); break;
        case B9: Keyboard.write('9'); break;
        case B0: Keyboard.write('0'); break;
        }

        IrReceiver.resume();
    }
 }
2021/07/26