ESP32に赤外線LEDを取り付けて、スマート赤外線リモコンとして動作させます。今回は、シーリング照明をon/offする赤外線パターンを用意して、赤外線LEDを点滅させる簡単な構成です。さらに、MQTT経由でメッセージが来た時に発光するようにし、Homebridge/HomeKitに接続しました。これでiPhone/Macのホーム画面に照明として表示され、操作可能です。
Nature RemoのローカルAPI
Nature Remoの回で、Nature RemoのローカルAPIを使う方法を紹介しました。
この方法を使えば、Nature Remoから、任意の赤外線パターンを送出させることができます。例えば、以下のターミナルコマンドを打つと、ここの部屋の赤外線リモコン対応のシーリングライトがon/offします。
curl -XPOST "http://192.168.xxx.xxx/messages" -H "X-Requested-With: local" -d '{"format":"us","freq":40,"data":[7000,4760,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,560,280,1400,280,1400,280,1400,280,1400,280]}'
IPアドレス部分はNature Remoのアドレスです。Nature Remoがhttpサーバになっていて、そこに赤外線明滅パターンをjson形式で送れば、それを送出してくれる仕掛けです。dataというキーで指定した整数型配列の部分が明滅パターンです。単位はマイクロ秒で、この例ですと、
- 7000μs発光する
- 4760μs消灯する(この長いペアが開始の印です)
- 280μs発光する
- 560μs消灯する(このペアがビット0です)
- 280μs発光する
- 1400μs消灯する(このペアがビット1です)
- (省略)
- 280μs発光する
- 1400μs消灯する(最後のビットです。1です)
- 280μs発光する(これに続く長い消灯により終了を示します)
という手順を示してます。消灯時間を確定するために、発光期間で始まり、発光期間で終了します。なので、配列の要素数は必ず奇数個です。
この明滅パターンさえ用意できれば、任意の赤外線リモコン信号をNature Remoから送出できます。Natureのクラウドを利用しないので、クラウドサービスに障害があっても、サービスが中断されても大丈夫です。でも、赤外線パターンを送出するだけの簡単な機能なら、高価なNature Remoを買う必要もない気がします。DIYしましょう!
赤外線パターンの解析
Nature Remoの記事にも簡単に書きましたが、今回は図入りで説明します。対象としたシーリング照明は、Amazaonでかなり昔に購入した格安製品です(今は売られてません)。リモコンには6個のボタンがついています。上で紹介した点滅パターンは、リモコンの「切/入」ボタンを押した時のパターンです。Nature Remoの学習機能を使って、web apiで取得した結果を、280μsの整数倍に整形した数列です。時系列でグラフにすると以下のようになってます。
1が点灯、0が消灯です。最初に長めのon/offがあって、その後280μsのパルスが17個出ます。パルスの間隔は、パルス幅の2倍のものと、パルス幅の5倍のものがあります。間隔が狭い方を0、広い方を1だと考えると、図のように0101010101001111と読めます。ちょうど16ビットあります。各バイトのMSBから順番に送信されていると仮定すると、16進数で0x554Fです。
いろいろ試したところ、最初の1バイトはリモコンのチャンネルを切り替えると変化し、CH2が0x55, CH1が0xAAでした。次の1バイト(ここでは0x4F)が命令のようです。
リモコンにはこのほかに、常夜灯(暗い点灯)、明るく、暗くのボタンがあります。4個のボタンの命令バイトは、
- 0x4F: 「切/入」
- 0xDF:「常夜灯」
- 0x67:「明るく」
- 0xCD:「暗く」
でした。「切/入」はトグルなので、状態を把握できないので使いにくいです。リモコン電源ボタンがトグル式でも、隠しコマンドで、on/off専用コマンドが存在することもあるらしいです。このリモコンは、チャンネル指定が1バイト、コマンドが1バイトなので、256通りの命令が可能です。すべての命令をプログラムで試してみたのですが、onだけ、offだけのコマンドは残念ながら見つかりませんでした。
赤外線リモコンサーバを設計する
LAN経由でコマンドを受け取って、赤外線パターンを送出するサーバのようなものを作ります。今回の構成は以下です。
マイコンにはESP32を使います。WiFiがあって無線サーバに仕上げやすいですし、安価です。さらには赤外線リモコンのための回路も備わっているらしいです。Nature Remo(他の会社のスマートリモコンもそうですが)などがWeb API使っているのに対して、これから作るサーバはMQTTを使うことにします。オーバーヘッドが少ないし、HomebridgeのMqttthingプラグインからも利用できて便利です。MQTTブローカには、いつものようにRaspberry Piで動かしているMosquittoを使います。同じRaspberry PiでHomebridgeも動いてます。
ESP32には、「MQTTの特定のトピックにメッセージがやってきたら、プログラムで用意した赤外線パターンを送出する」という機能を実現したいと思います。
部品を集める
秋月電子のページを見ながらLEDとFETを選びました。
- 赤外線LED:赤外線リモコンで使われる波長は950nmらしいので、近い波長にしました。945nmです。標準電流は50mAです。
- MOS FET:一番普通そうなMOS FET。ドレイン電流は200mA流せるようです。赤外線LEDを十分点灯させられます。
ESP32が送料込み700円くらいに加えて、LED 10円、FET 20円、抵抗など部品代がかかっても1000円程度で作れます。
Arduino IDEにIRライブラリを入れる
Arduino IDEに赤外線リモコン用のライブラリを入れました。ライブラリマネージャで、irremoteという単語で検索したところ、IRRemoteESP8266というのが見つかりました。ESP8266という名前ですが、ESP32でも動くようです。これをインストールしました。
ライブラリをインストールすると、Arduino IDEのスケッチ例にIRremoteESP8266というメニュー項目が増えていました。これを参考に、簡単なプログラムを作ります。このライブラリは、いろいろなメーカーの赤外線パターンに対応しているようです。Panasonic, Daikin, Mitsubishiなどほとんどの製品が揃ってます。今後はそのような高度な機能も活用したいですが、今回は、一番簡単な、生の赤外線パターンを出すプログラムを作りました。
最初に、部屋のシーリング照明をon/offするパターンを5秒ごとに送出するプログラムを作りました。以下のようにとても簡単に作れます。
/*IRremoteESP8266:demonstrates sending IR codes with IRsend.*/ #include <Arduino.h> #include <IRremoteESP8266.h> #include <IRsend.h> const uint16_t kIrLed = 4; //GPIO pin. Recommended: 4 (D2). IRsend irsend=IRsend(kIrLed); // Set the GPIO to be used. uint16_t rawData[35] = { 7000,4760,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,560,280,1400,280,1400,280,1400,280,1400,280 }; void setup() { irsend.begin(); Serial.begin(115200); } void loop() { Serial.println("Sending a rawData."); irsend.sendRaw(rawData, 35, 38); //Send a raw data at 38kHz. delay(5000); }
回路を組む
赤外線LEDをドライブする回路を作っておきます。GPIOの出力そのままでは光量が少ないので、FETを介して赤外線LEDを点灯させます。以下の回路にしました。
MOS FETの2N7000は、onになるゲート電圧が標準2.1V, max 3Vらしいです。ESP32の3.3V出力でもonにできるように、高めに分圧してあります。onの時のゲート電圧は、ほぼ3.3Vのままになると思います。GPIO直結じゃなくて分圧したのは、過渡状態が良くなるらしいからです。セキュリティシステムでブザーを動かした時と同じ構成です。
LEDは、明るく点灯するように5V供給にしました。LEDの順方向電圧降下を測定したところ1.2Vでした。FETのonの時の順方向電圧は0.14Vくらいらしいので無視できます。保護抵抗を100Ωにしたので、FETがonの時には、40mA弱流れると思います。( 正確には(5-1.2-0.14) / 100 = 37mA と見積もってましたが、実測したらもう少し少なかったです)
ブレッドボードの配置図は以下です。
実際に配線した様子が以下です。この写真を撮った時は、デバッグのために可視光青色LEDを取り付けてます。
点灯消灯プログラムのテスト
回路が完成したので、上記で紹介したプログラムを走らせます。プログラムの内容は簡単です。sendRawという関数で、赤外線パターンを送出させてます。引数は信号パターンの配列、配列要素数、赤外線変調周波数(kHz)です。これを5秒ごとに繰り返してます。可視光LEDを付けると、5秒ごとに一瞬光っているのがわかります。光っている前後2秒を切り出したGIFアニメです。
赤外線LEDに変えると、部屋の照明が5秒ごとに消灯・点灯しました。とてもウザいのですが、動いて嬉しいです。
前述のように、この照明のリモコンには、on/offトグルスイッチしかありません。なのでこの信号パターンを送るたびに、点灯、または消灯します。トグル動作は、現在の状態が不明なので、家電制御としては使いにくいです。
MQTTから操作する
MQTTのメッセージで、赤外線信号を出すようにプログラムしました。ewpmqttclientを使います。詳しくはこちらをご覧ください。
今回は、irremote/ceilinglightというトピックに、何らかのメッセージが来たら、シーリング照明をトグルするパターンを出すというプログラムです。極力簡単にしました。クライアントIDも適当にランダムな文字列にしておきました。
setup()でMQTTクライアントの初期化をします。初期化が完了すると、onConnectionEstablished()という関数が呼ばれるので、その中でコールバック関数(特定のトピックを受信したら呼び出される関数)を指定します。ここでは、onMessageReceived()という名前にしました。この関数の中で赤外線を送出します。main()は、MQTTクライアントの処理を行うだけの仕事をしてます。
/* IRremoteESP8266 over MQTT */ #include <Arduino.h> #include <IRremoteESP8266.h> #include <IRsend.h> #include <espmqttclient.h> EspMQTTClient *client; //WiFi const char SSID[] = "XXXXXXXX"; //WiFi SSID const char PASS[] = "xxxxxxxx"; //WiFi password //MQTT char CLIENTID[] = "IRremote_3835782"; //something random const char MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address const short MQTTPORT = 1883; //Broker port const char MQTTUSER[] = "xxxx";//Can be omitted if not needed const char MQTTPASS[] = "XXXX";//Can be omitted if not needed const char SUBTOPIC[] = "irremote/ceilinglight"; const uint16_t kIrLed = 4; //GPIO pin. Recommended: 4 (D2). IRsend irsend=IRsend(kIrLed); // Set the GPIO to be used. // IR-data to toggle a ceiling light uint16_t rawData[35] = { 7000,4760,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,1400,280,560,280,560,280,1400,280,1400,280,1400,280,1400,280 }; void setup() { irsend.begin(); Serial.begin(115200); while (!Serial); // wait for serial port to connect. client = new EspMQTTClient(SSID,PASS,MQTTADD,MQTTUSER,MQTTPASS,CLIENTID,MQTTPORT); } void onMessageReceived(const String& msg) { Serial.println("a rawData capture from Nature Remo"); irsend.sendRaw(rawData, 35, 38); // Send a data at 38kHz. } void onConnectionEstablished() { Serial.println("MQTT connection established."); client->subscribe(SUBTOPIC, onMessageReceived); //set callback } void loop() { client->loop(); delay(100); }
どんなメッセージを受け取っても動作します。NULLでも良いです。例えば、ターミナルから、mosquitto_pubコマンドを使ってこのトピックに空白文字を送ってみます。
% mosquitto_pub -h 192.168.xxx.xxx -u xxxx -P XXXX-t irremote/ceilinglight -m ''
その結果、シーリング照明が消灯または点灯しました。これで、MQTTメッセージを使って赤外線パターンを送出できるようになりました。
Homebridgeで設定する
MQTTで動作するプログラムができたので、Homebridgeで設定して、HomeKitから使えるようにします。Homebridgeは、MQTTブローカと同じRaspberry Piの上で動いてます。
このHomebridgeにインストールされているMqttthingプラグインを使い、その設定をします。Mqttthingプラグインの設定画面から、スイッチアクセサリを一つ作って、ここで使ったirremote/ceilinglightトピックを指定します。Homebridgeのwebインタフェースで、以下のように設定します。
設定をテキストで確認すると以下のようになってます。HomebridgeとMQTTブローカが同じRaspberry Piで動いているので、アドレスはlocalhostです。デフォルトなので、設定では省略されてます。
{ "type": "lightbulb-OnOff", "name": "Ceiling Light", "username": "xxxx", "password": "XXXX", "topics": { "setOn": "irremote/ceilinglight" }, "accessory": "mqttthing" }
この設定で、iPhone/Macでon/offする操作を行うと、setOnで指定したトピックにtrue/falseという文字列を送ります。今回はtrueかfalseに関係なく、どちらの場合も設定した同じ赤外線パターンを送出します。
HomeKitから操作する
Homebridgeを再起動すると、iPhoneやMacのホーム.appに、今回設定した照明が現れました。Ceiling Lightという名前の照明です。
これをクリックすると、ESP32が赤外線パターンを送出します。天井の照明が、消灯または点灯します。画面の表示とシーリング照明のon/off状態は、どちらも操作するたびにトグルしているだけなので、不一致になる可能性もあります。
なので実際のシーリング照明のon/offには、隣の「あかり」と書かれたボタンを使ってます。こちらは、壁に取り付けたZigbeeスイッチをコントロールします。
まとめ
ESP32に赤外線LEDをつけて、MQTTメッセージで動作するスマートリモコンを作りました。今回はシーリングライトの電源トグル信号を送るだけの簡単な機能です。使用したライブラリIRremoteESP8266には、生の赤外線明滅パターンを送るだけではなく、各社家電製品のフォーマットに対応した機能もあります。これを使えば、エアコンなどの複雑な制御も実現できると考えてます。
コメント