🌌

普通の赤外線リモコンをマクロ対応学習リモコンにしてみた

2021/03/22に公開
1

はじめに

今回は学習リモコンではない普通の赤外線リモコンを Atom Lite 経由で、マクロ対応のリモコンとして使えるようにしてみたいと思います。

ソース類は

https://github.com/toyo-toyo/AtomLite_IR_Recv_2_Ble_Gamepad

に公開しています。

前回の記事

https://zenn.dev/toyotoyo/articles/dab070a42478a9

前回の記事では 赤外線用の学習リモコンを利用し Atom Lite 経由で Bluetooth リモコンの操作を行う内容でした。
今回の記事と関連することがかなり多いので、興味がある方は確認してみてください。

必要なもの

  • ATOM Lite 968 円 (2021-03-22現在)
  • M5Stack用赤外線送受信ユニット 308 円 (2021-03-22現在)

https://www.switch-science.com/catalog/6262/

https://www.switch-science.com/catalog/5699/

作ることになった経緯

この章は読み飛ばしても問題ありません。

実装方法だけ知りたい方は
赤外線リモコンを受信し信号を確認
から確認してください。

学習リモコンの仕様を勘違い

これは私が完全に悪いのですが、購入したソニーの学習リモコン(RM-PLZ430D)

https://www.amazon.co.jp/gp/product/B0040N9MZM/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

は全てのボタンがマクロ登録出来るものと勘違いしていました。

実際にはマクロ登録できるボタンは固定化されており「A-Dの4つのボタン+5種類のリモコン切替ボタン」の計9つだけマクロ登録できるみたいでした。

私がやりたかった内容はリモコンを切り替えて使うのではなく、切替操作をしなくても同じボタンで色々な機器の操作を同時に行いたいということでした。
なので今回は赤外線リモコンでさえあれば余ったリモコンであったとしても、マクロ実行で操作出来るようにしてみたいと思います。

赤外線リモコンを受信し信号を確認

Atom Lite で赤外線リモコンの赤外線信号を確認してみます。

AtomLite_IR_Recv.ino
#include <M5Atom.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>

const uint16_t kIrLed = 26;
const uint16_t kRecvPin = 32;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 50;

IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
IRsend irsend(kIrLed);

decode_results results;  // Somewhere to store the results

uint32_t value;
  
void setup() {
  M5.begin(true, false, true);
  irrecv.enableIRIn();
  irsend.begin();
}

void loop() {
  M5.update();
  if (irrecv.decode(&results)) {
    Serial.print(resultToHumanReadableBasic(&results));
    Serial.print(resultToSourceCode(&results));
    value = results.value;
    Serial.println(value);
    delay(500);
  }
  delay(50);
}

上記コードを Arduino IDE で Atom Lite に書き込みします。
赤外線送受信ユニットに向けてリモコンボタンを押下し、シリアルモニタでボタンごとにでる赤外線信号を確認してください。

マクロ登録の一例

試しに私の家にあるパナソニックのテレビを操作してみたいと思います。


左:テレビ用リモコン、右:ディスプレイ用リモコン

テレビの HDMI1 にはAVアンプが繋がっています。
テレビは入力切替ボタンを押下した後にチャンネル 2 を押下すると HDMI1 に切り替わる仕様になっています。

例としてディスプレイ用リモコンの DCR 押下すると、テレビの入力を HDMI1 に切り替えるようにしてみたいと思います。
なので「ディスプレイ用リモコンのDCR」「テレビ用リモコンの入力切替」「テレビ用リモコンの2ch」の 3 つの赤外線信号を確認してみます。

ディスプレイ用リモコンのDCR
Protocol  : NEC
Code      : 0x40BF916E (32 Bits)
uint16_t rawData[71] = {8926, 4512,  532, 594,  528, 1718,  530, 594,  528, 594,  530, 594,  554, 570,  528, 596,  528, 596,  528, 1720,  530, 596,  528, 1720,  528, 1720,  530, 1720,  530, 1718,  530, 1720,  528, 1720,  530, 1720,  530, 596,  528, 596,  528, 1720,  530, 594,  528, 596,  528, 596,  528, 1720,  528, 596,  528, 1720,  528, 1720,  528, 598,  526, 1722,  530, 1720,  530, 1720,  528, 596,  528, 39552,  8928, 2288,  554};  // NEC 40BF916E
uint32_t address = 0x2;
uint32_t command = 0x89;
uint64_t data = 0x40BF916E;
1086296430

上記の例だと NEC のプロトコル信号を持ったリモコンということになります。
待ち受けに使うので一番下の数値 1086296430 を使います。

テレビ用リモコンの入力切替
Protocol  : PANASONIC
Code      : 0x40040100A0A1 (48 Bits)
uint16_t rawData[99] = {3480, 1762,  422, 450,  420, 1322,  422, 450,  422, 450,  420, 452,  420, 450,  420, 452,  422, 450,  422, 448,  422, 450,  422, 450,  420, 450,  422, 450,  420, 1324,  420, 452,  422, 450,  422, 450,  420, 452,  420, 452,  420, 452,  422, 450,  422, 450,  420, 450,  420, 1324,  422, 450,  420, 450,  422, 450,  420, 450,  420, 452,  422, 450,  422, 448,  396, 476,  420, 1322,  422, 450,  418, 1326,  420, 450,  420, 452,  422, 450,  422, 450,  422, 448,  422, 1322,  420, 452,  422, 1322,  420, 450,  420, 452,  420, 452,  420, 450,  420, 1322,  422};  // PANASONIC 40040100A0A1
uint32_t address = 0x4004;
uint32_t command = 0x100A0A1;
uint64_t data = 0x40040100A0A1;
16818337

上記の例だと PANASONIC のプロトコル信号を持ったリモコンということになります。
PANASONIC の場合は address command が分かれば送信できます。

テレビ用リモコンの2ch
Protocol  : PANASONIC
Code      : 0x400401908213 (48 Bits)
uint16_t rawData[99] = {3454, 1790,  418, 454,  418, 1326,  418, 454,  396, 476,  394, 476,  418, 454,  394, 478,  418, 454,  418, 454,  418, 452,  394, 478,  394, 478,  394, 478,  418, 1326,  394, 478,  418, 454,  416, 454,  418, 452,  396, 476,  394, 478,  394, 476,  418, 454,  418, 454,  418, 1326,  394, 1350,  420, 452,  418, 454,  394, 1350,  394, 478,  394, 476,  394, 478,  394, 476,  394, 1350,  418, 454,  418, 452,  394, 478,  394, 478,  418, 454,  420, 1324,  394, 478,  418, 454,  418, 452,  394, 476,  418, 1326,  420, 454,  418, 454,  418, 1326,  394, 1350,  418};  // PANASONIC 400401908213
uint32_t address = 0x4004;
uint32_t command = 0x1908213;
uint64_t data = 0x400401908213;
26247699

上記も PANASONIC のプロトコル信号を持ったリモコンということになります。

赤外線受信した内容で他の赤外線信号を送信

Atom Lite で赤外線リモコンのボタンを判断し、 受信した信号以外の信号を送信するように、switch 文を追記します。

先ほど調べたディスプレイ用リモコンの DCR ボタン押下すると、テレビの入力を HDMI1 に切り替えるようにしてみたいと思います。

AtomLite_IR_Recv_2_IR_Send.ino
#include <M5Atom.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>

const uint16_t kIrLed = 26;
const uint16_t kRecvPin = 32;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 50;

IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
IRsend irsend(kIrLed);

decode_results results;  // Somewhere to store the results

uint32_t value;
  
void setup() {
  M5.begin(true, false, true);
  irrecv.enableIRIn();
  irsend.begin();
}

void loop() {
  M5.update();
  if (irrecv.decode(&results)) {
    Serial.print(resultToHumanReadableBasic(&results));
    Serial.print(resultToSourceCode(&results));
    value = results.value;
    Serial.println(value);
    delay(500);
    switch(value) {
      case 1086296430:
        Serial.println("DCR");
        // HDMI1に切替
        irsend.sendPanasonic(0x4004, 0x100A0A1);
        delay(100);
        irsend.sendPanasonic(0x4004, 0x1908213);
        break;
      default:
        Serial.println("他の値です");
    }
  }
  delay(50);
}

上記コードを Arduino IDE で Atom Lite に書き込みします。

テレビの電源を付けて MDMI1 以外のチャンネルに合わせます。
そして赤外線送受信ユニットをテレビに向けてディスプレイ用リモコンの DCR ボタンを押下してみます。
テレビが HDMI1 に切り替われば成功です。

赤外線信号の送信コマンド

赤外線のプロトコルにはいろいろなメーカーが登録されています。
IRsend クラスにはプロトコルごとに赤外線の送信関数が用意されているみたいですが微妙に使用方法が違っているみたいです。

https://lang-ship.com/reference/Arduino/libraries/IRremote/class_i_rsend.html

IRsendクラスの関数の一部抜粋
void 	sendApple (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, bool aIsRepeat=false)
void 	sendBoseWave (uint8_t aCommand, uint_fast8_t aNumberOfRepeats=NO_REPEATS)
void 	sendDISH (unsigned long data, int nbits)
void 	sendDenon (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, bool aSendSharp=false)
void 	sendDenon (unsigned long data, int nbits)
void 	sendDenonRaw (uint16_t aRawData, uint_fast8_t aNumberOfRepeats=0)
void 	sendJVC (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats)
void 	sendJVCMSB (unsigned long data, int nbits, bool repeat=false)
void 	sendJVCRaw (uint16_t aRawData, uint_fast8_t aNumberOfRepeats=0)
void 	sendKaseikyo (uint16_t aAddress, uint8_t aData, uint_fast8_t aNumberOfRepeats, uint16_t aVendorCode)
void 	sendLG (uint8_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aIsRepeat=false)
void 	sendLG (unsigned long data, int nbits)
void 	sendLGRaw (uint32_t aRawData, uint_fast8_t aNumberOfRepeats=0, bool aIsRepeat=false)
void 	sendLGRepeat ()
void 	sendLegoPowerFunctions (IRData *aIRSendData, bool aDoSend5Times=true)
void 	sendLegoPowerFunctions (uint16_t aRawData, bool aDoSend5Times=true)
void 	sendLegoPowerFunctions (uint16_t aRawData, uint8_t aChannel, bool aDoSend5Times=true)
void 	sendLegoPowerFunctions (uint8_t aChannel, uint8_t tCommand, uint8_t aMode, bool aDoSend5Times=true)
void 	sendMagiQuest (uint32_t wand_id, uint16_t magnitude)
void 	sendNEC (uint16_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, bool aIsRepeat=false)
void 	sendNECMSB (uint32_t data, uint8_t nbits, bool repeat=false)
void 	sendNECRaw (uint32_t aRawData, uint_fast8_t aNumberOfRepeats=0, bool aIsRepeat=false)
void 	sendNECRepeat ()
void 	sendPanasonic (uint16_t aAddress, uint32_t aData)
void 	sendPanasonic (uint16_t aAddress, uint8_t aData, uint_fast8_t aNumberOfRepeats)
void 	sendPronto (const __FlashStringHelper *str, uint_fast8_t aNumberOfRepeats=NO_REPEATS)
void 	sendPronto (const char *prontoHexString, uint_fast8_t aNumberOfRepeats=NO_REPEATS)
void 	sendPronto (const uint16_t *data, unsigned int length, uint_fast8_t aNumberOfRepeats=NO_REPEATS)
void 	sendRC5 (uint32_t data, uint8_t nbits)
void 	sendRC5 (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
void 	sendRC5ext (uint8_t addr, uint8_t cmd, boolean toggle)
void 	sendRC6 (uint32_t data, uint8_t nbits)
void 	sendRC6 (uint64_t data, uint8_t nbits)
void 	sendRC6 (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
void 	sendRaw (const uint16_t aBufferWithMicroseconds[], uint_fast8_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
void 	sendRaw (const uint8_t aBufferWithTicks[], uint_fast8_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
void 	sendRaw_P (const uint16_t aBufferWithMicroseconds[], uint_fast8_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
void 	sendRaw_P (const uint8_t aBufferWithTicks[], uint_fast8_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
void 	sendSAMSUNG (unsigned long data, int nbits)
void 	sendSamsung (uint16_t aAddress, uint16_t aCommand, uint_fast8_t aNumberOfRepeats, bool aIsRepeat=false)
void 	sendSamsungRepeat ()
void 	sendSharp (uint8_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats)
void 	sendSharp (unsigned int address, unsigned int command)
void 	sendSharpRaw (unsigned long data, int nbits)
void 	sendShuzu (uint16_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats)
void 	sendSony (uint16_t aAddress, uint8_t aCommand, uint_fast8_t aNumberOfRepeats, uint8_t numberOfBits=SIRCS_12_PROTOCOL)
void 	sendSony (unsigned long data, int nbits)
void 	sendWhynter (unsigned long data, int nbits)

プロトコルが UNKNOWN だった場合

プロトコルが UNKNOWN でよくわからない場合や、プロトコルが分かっていてもうまく赤外線信号が送信できない場合は sendRaw 関数を使いましょう。
赤外線信号で調べた rawData の値を使用します。
sendRaw の 2 番目の引数はrawDataの配列の数で、3 番目の引数は 38 固定で大丈夫です。

sendPanasonicではなくsendRawで実行する場合の例
#include <M5Atom.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>

const uint16_t kIrLed = 26;
const uint16_t kRecvPin = 32;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 50;

const uint16_t TvInputSwitch[99] = {3480, 1762,  422, 450,  420, 1322,  422, 450,  422, 450,  420, 452,  420, 450,  420, 452,  422, 450,  422, 448,  422, 450,  422, 450,  420, 450,  422, 450,  420, 1324,  420, 452,  422, 450,  422, 450,  420, 452,  420, 452,  420, 452,  422, 450,  422, 450,  420, 450,  420, 1324,  422, 450,  420, 450,  422, 450,  420, 450,  420, 452,  422, 450,  422, 448,  396, 476,  420, 1322,  422, 450,  418, 1326,  420, 450,  420, 452,  422, 450,  422, 450,  422, 448,  422, 1322,  420, 452,  422, 1322,  420, 450,  420, 452,  420, 452,  420, 450,  420, 1322,  422};  // PANASONIC 40040100A0A1
const uint16_t Tv2ch[99] = {3454, 1790,  418, 454,  418, 1326,  418, 454,  396, 476,  394, 476,  418, 454,  394, 478,  418, 454,  418, 454,  418, 452,  394, 478,  394, 478,  394, 478,  418, 1326,  394, 478,  418, 454,  416, 454,  418, 452,  396, 476,  394, 478,  394, 476,  418, 454,  418, 454,  418, 1326,  394, 1350,  420, 452,  418, 454,  394, 1350,  394, 478,  394, 476,  394, 478,  394, 476,  394, 1350,  418, 454,  418, 452,  394, 478,  394, 478,  418, 454,  420, 1324,  394, 478,  418, 454,  418, 452,  394, 476,  418, 1326,  420, 454,  418, 454,  418, 1326,  394, 1350,  418};  // PANASONIC 400401908213

IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
IRsend irsend(kIrLed);

decode_results results;  // Somewhere to store the results

uint32_t value;
  
void setup() {
  M5.begin(true, false, true);
  irrecv.enableIRIn();
  irsend.begin();
}

void loop() {
  M5.update();
  if (irrecv.decode(&results)) {
    Serial.print(resultToHumanReadableBasic(&results));
    Serial.print(resultToSourceCode(&results));
    value = results.value;
    Serial.println(value);
    delay(500);
    switch(value) {
      case 1086296430:
        Serial.println("DCR");
        // HDMI1に切替
        irsend.sendRaw(TvInputSwitch, 99, 38);
        delay(100);
        irsend.sendRaw(Tv2ch, 99, 38);
        break;
      default:
        Serial.println("他の値です");
    }
  }
  delay(50);
}

先ほどと同じようにディスプレイ用リモコンの DCR ボタンを押下すればテレビの HDMI1 に切り替わります。

おまけ

赤外線中継器

M5Stack用赤外線送受信ユニットだけだと赤外線の信号は 1m も飛ばない感じでした。
なので実際の利用には

https://www.amazon.co.jp/gp/product/B07897LDRN/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1

という製品も購入し、赤外線信号を中継させて機器の操作をすることにしています。

私の持っているスマートリモコンでは API が公開されていませんでしたが、少し調べたところ Nature Remo シリーズであればローカルでの API 実行もできるみたいなので、Nature Remo シリーズを持っている方はそれを利用するのもいいかもですね。

赤外線リモコンした内容でBluetoothや他の赤外線信号を送信

前回の記事でも扱った Bluetooth リモコンも合わせて使うことも可能です。
学習リモコンを買わなくても、余っている赤外線リモコンがあれば Bluetooth も操作可能になります。

まだまだカスタマイズの途中ですが、実際に仮運用させているプログラムも参考用に載せておきます。

AtomLite_IR_Recv_2_Ble_Gamepad_IR_Send.ino
#include <M5Atom.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>
#include <BleGamepad.h> 

const uint16_t kIrLed = 26;
const uint16_t kRecvPin = 32;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 50;

const uint16_t rawPcOn[71] = {9144, 4436,  656, 506,  630, 508,  628, 508,  628, 508,  626, 484,  652, 508,  628, 508,  628, 508,  624, 1616,  628, 1618,  626, 1590,  652, 1616,  628, 1616,  626, 1616,  626, 1592,  650, 1616,  628, 510,  624, 512,  624, 510,  626, 510,  626, 510,  624, 512,  626, 1592,  652, 508,  626, 1616,  628, 1616,  626, 1616,  626, 1616,  624, 1618,  628, 1614,  624, 512,  622, 1618,  630, 39904,  9146, 2196,  624};  // NEC FF02FD
const uint16_t rawPcOff[71] = {9128, 4438,  654, 506,  624, 512,  622, 512,  598, 536,  602, 534,  624, 510,  600, 536,  620, 514,  622, 1618,  598, 1616,  650, 1618,  628, 1614,  602, 1640,  600, 1644,  624, 1618,  600, 1612,  630, 1640,  626, 510,  624, 506,  606, 1638,  622, 1618,  626, 508,  600, 534,  600, 536,  600, 534,  598, 1644,  598, 1618,  624, 536,  598, 538,  598, 1616,  624, 1644,  622, 1620,  622, 39900,  9138, 2174,  652};  // NEC FF9867
const uint16_t rawDenonChromecast[99] = {3290, 1728,  394, 442,  370, 466,  370, 1300,  368, 468,  396, 1274,  370, 466,  368, 1302,  398, 438,  394, 444,  394, 1276,  398, 438,  368, 468,  370, 1298,  370, 1302,  392, 442,  370, 468,  368, 466,  394, 442,  372, 464,  392, 444,  370, 466,  368, 466,  398, 1272,  370, 468,  396, 1274,  372, 462,  392, 444,  394, 442,  394, 1276,  396, 1274,  370, 466,  368, 468,  372, 1296,  370, 466,  370, 1300,  370, 1300,  396, 440,  368, 1302,  394, 442,  368, 468,  370, 466,  392, 442,  370, 1300,  370, 1300,  370, 1300,  370, 466,  394, 1276,  392, 444,  394};  // DENON 2A4C028CB43A
const uint16_t rawDenonPc[99] = {3284, 1732,  370, 466,  370, 466,  368, 1302,  368, 466,  368, 1300,  370, 468,  370, 1300,  370, 468,  368, 466,  394, 1276,  370, 466,  370, 466,  370, 1300,  396, 1274,  396, 440,  370, 466,  370, 468,  392, 442,  368, 466,  370, 466,  370, 466,  368, 466,  368, 1300,  370, 468,  368, 1302,  368, 468,  392, 442,  368, 466,  370, 466,  368, 1302,  368, 1302,  370, 468,  368, 1302,  368, 468,  394, 1276,  392, 1276,  394, 442,  370, 1302,  394, 442,  370, 466,  368, 466,  370, 466,  368, 1302,  368, 1302,  370, 466,  370, 466,  368, 466,  370, 466,  368};  // DENON 2A4C0286B430
const uint16_t rawDenonBluray[99] = {3290, 1726,  372, 464,  396, 440,  372, 1298,  372, 464,  396, 1274,  372, 464,  370, 1298,  372, 464,  370, 466,  370, 1298,  372, 464,  370, 466,  372, 1298,  372, 1298,  372, 464,  372, 464,  370, 466,  394, 442,  370, 466,  370, 466,  370, 466,  394, 440,  394, 1276,  396, 440,  396, 1274,  372, 466,  394, 442,  370, 466,  372, 1298,  372, 464,  370, 466,  370, 464,  370, 1298,  396, 440,  396, 1274,  372, 1298,  372, 466,  392, 1276,  372, 464,  372, 464,  372, 464,  370, 466,  370, 1298,  372, 1298,  372, 1298,  370, 1300,  370, 1300,  396, 440,  370};  // DENON 2A4C0288B43E

const CRGB CRGB_BLE_CONNECTED(0x00, 0x00, 0xf0);
const CRGB CRGB_BLE_DISCONNECTED(0x00, 0xf0, 0x00);

IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
IRsend irsend(kIrLed);

decode_results results;

BleGamepad bleGamepad;
bool isBleConnected = false;
uint32_t value;
  
void setup() {
  M5.begin(true, false, true);
  M5.dis.drawpix(0, CRGB_BLE_DISCONNECTED);
  irrecv.enableIRIn();
  irsend.begin();
  bleGamepad.begin();
}

void loop() {
  M5.update();
  if (irrecv.decode(&results)) {
    Serial.print(resultToHumanReadableBasic(&results));
    Serial.print(resultToSourceCode(&results));
    value = results.value;
    Serial.println(value);
    switch(value) {
      case 1086269655:
        Serial.println("→");
        // Atom Lite 再起動
        esp_restart();
        value = 0;
        break;
      case 42002538:
        Serial.println("Denon+");
        delay(500);
        // TVの音量
        irsend.sendPanasonic(0x4004, 0x1000405);
        value = 0;
        break;
      case 42526818:
        Serial.println("Denon-");
        delay(500);
        // TVの音量
        irsend.sendPanasonic(0x4004, 0x1008485);
        value = 0;
        break;
      case 1086296430:
        Serial.println("DCR");
        delay(500);
        // TVの入力をHDMI1に切替
        irsend.sendPanasonic(0x4004, 0x100A0A1);
        delay(100);
        irsend.sendPanasonic(0x4004, 0x1908213);
        value = 0;
        break;
      case 1086303570:
        Serial.println("P.mode");
        delay(500);
        // PCの起動
        irsend.sendRaw(rawPcOn, 71, 38);
        delay(500);
        irsend.sendRaw(rawPcOff, 71, 38);
        // TVの入力をHDMI1に切替
        delay(100);
        irsend.sendPanasonic(0x4004, 0x100A0A1);
        delay(100);
        irsend.sendPanasonic(0x4004, 0x1908213);
        delay(100);
        // Denonの入力をPCに切替
        irsend.sendRaw(rawDenonPc, 99, 38);
        value = 0;
        break;
      case 1086271695:
        Serial.println("+");
        delay(500);
        // Denonの入力をPCに切替
        irsend.sendRaw(rawDenonPc, 99, 38);
        value = 0;
        break;
      case 1080726861:
        Serial.println("Blu-ray電源");
        delay(500);
        // TVの入力をHDMI1に切替
        irsend.sendPanasonic(0x4004, 0x100A0A1);
        delay(100);
        irsend.sendPanasonic(0x4004, 0x1908213);
        delay(100);
        // Denonの入力をBlu-rayに切替
        irsend.sendRaw(rawDenonBluray, 99, 38);
        value = 0;
        break;
      case 1086288525:
        Serial.println("-");
        delay(500);
        // Denonの入力をBlu-rayに切替
        irsend.sendRaw(rawDenonBluray, 99, 38);
        value = 0;
        break;
      case 1086320655:
        Serial.println("x");
        delay(500);
        // Denonの入力をChromecast with Google TVに切替
        irsend.sendRaw(rawDenonChromecast, 99, 38);
        value = 0;
        break;
    }
  }
  if(bleGamepad.isConnected()) {
    if (!isBleConnected) {
      M5.dis.drawpix(0, CRGB_BLE_CONNECTED);
      isBleConnected = true;
      Serial.println("Connected");
    }
    // Check if the IR code has been received.
    if (value != 0) {
      switch(value){
        case 1086319125:
          Serial.println("電源");
          sendButton(BUTTON_64);
          break;
        case 1086304335:
        case 650079:
          Serial.println("上");
          sendLeftThumb(0, -32767);
          break;
        case 1086321165:
        case 387935:
          Serial.println("下");
          sendLeftThumb(0, 32767);
          break;
        case 1086310965:
        case 912223:
          Serial.println("左");
          sendLeftThumb(-32767, 0);
          break;
        case 1086261495:
        case 256863:
          Serial.println("右");
          sendLeftThumb(32767, 0);
          break;
        case 1086294135:
        case 854879:
          Serial.println("決定");
          sendButton(BUTTON_1);
          break;
        case 1086286485:
        case 461663:
        case 101328:
          Serial.println("戻る");
          sendButton(BUTTON_2);
          break;
        case 1086298215:
          Serial.println("ホーム");
          sendButton(BUTTON_3);
          break;
        default:
          Serial.println("他の値です");
      }
      value = 0;
    }
  } else {
    if (isBleConnected) {
      M5.dis.drawpix(0, CRGB_BLE_DISCONNECTED);
      isBleConnected = false;
      Serial.println("Disconnected");
    }
  }
  delay(50);
}
void sendLeftThumb(int16_t x, int16_t y) {
  bleGamepad.setLeftThumb(x, y);
  delay(1);
  bleGamepad.setLeftThumb(0, 0);
}
void sendButton(uint8_t sendkey) {
  bleGamepad.press(sendkey);
  delay(1);
  bleGamepad.release(sendkey);
}

まとめ

これで当初の思っていた通り、リモコンの切替なしで色々な機器の操作が出来そうですね。
余っているリモコンだけでなく、元から使っているリモコンも同時に色々な機器を操作できるようになりますね。

もちろんここまで出来たら赤外線マクロや Bluetooth 信号もスマートスピーカーやスマートリモコン経由で音声操作も可能になりますね。

学習リモコンについては勘違いしていた部分もありましたが、購入してよかったと思っています。

まだ使い始めなので、とりあえずこれを使っての使用感など様子をみてみます。
又何か不満が出たら仕組みを変えるかもです(●´ω`●)

Discussion

にゃむにゃむ

とよとよ様
はじめまして、Shotgunと申します。
我が家もAV機器が多く、最近のBT機器で往生しております。
実は以前からSONYのコマンダーを愛用していまして、BTが増えて集約できずにいました。
とよとよ様の記事のおかげで目からうろこ!希望が出て、さっそくリンクから購入して
自分はかなりのど素人ですがとよとよ様の記事を参考にBT>IR変換に挑戦中です。
現在、sketchで書き込み挑戦中ですが、Compilation error: exit status 1と出てしまい、
書き込めず赤外線検証に進めず困っています。
何が原因でしょうか・・。よろしければ、ご指導いただければ助かります・・。