概要
スマートLEDライトはすでに製品として沢山ありますが,すでにある天井LEDライトをスマート化できないかと思い,取り組んだ際のログです.もちろんスマートリモコンは販売されていますが,少し値が張りますしね.. ライブラリもあるので簡単にできると思いきや,対象としたPanasonic製のLEDライトはデフォルトのAPIに対応しておらず,信号を解析した上で実装する羽目になりました.
環境
- Mac OS 10.12.6
- Arduino IDE 1.8.3
- ライブラリ: IRremote 2.2.3
- ボード: Arduino Uno (Elements14製)
- Panasonic製 LEDライト
もう少し古いIDEから使ってはいましたが,現在の環境を掲載しておきます.
導入
- Arduino IDE起動後,[スケッチ]-[ライブラリをインクルード]-[ライブラリを管理]ダイアログを開く
- IRremoteを選択してインストール
- ArduinoのデフォルトライブラリにIRremote.cppというファイルやIRrecvというクラスがあるため,このままではエラーが発生します.そのためArduino.appの
Contents/Java/libraries/Robot_IR_remote
をlibrariesフォルダの外に退避
パーツと接続
- 赤外線受信モジュール
- 三洋半導体製 SPS440-1
- 赤外線LED
- OSI5LA5113A (Vf 1.35-1.6V, 55mW@50mA)
赤外線受信モジュールはデータシートに書いてある通り,立てた時に3本足がある方の,左からGND(0V),OUT(出力),VCC(電源)です.以下のように接続します.
受信機 | Arduino Uno |
---|---|
3 GND | GND |
4 OUT | D11 |
5 VCC | +5V |
赤外線LEDは100Ω介し,AnodeをD3に,CathodeをGNDに接続しています1.
テスト1-問題確認
赤外線信号のデコードはIRremoteのスケッチ例IRrecvDumpを使って,解釈できればデコード結果が出ます.なおスケッチ例は[ファイル]-[スケッチ例]-[IRremote]-[IRrecvDump]から開けます.
例えば(確かLGの)テレビリモコンのON/OFFボタンを押すとDecoded NEC: 20DF10EF
のようなログがでるわけです.これをIRsendDemoで sendNEC(0x20DF10EF, 32)
のようにすればテレビが点きます.
しかし同じことをLEDライトのリモコンで実施したところ全く動作しませんでした.
テスト2-生信号受信
IRremoteのスケッチ例 IRrecvDump を参考に以下のコードでテストしました.
# include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn();
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
for ( i=0 ; i<results.rawlen ; i++ ){
Serial.print(results.rawbuf[i]);
Serial.print(",");
}
Serial.println();
irrecv.resume();
}
delay(100);
}
そもそも赤外線リモコン信号は次のような形式でやりとりされています.
赤外線2が出ている時間をMark,出ていない時間をSpaceとし,MarkとSpace1対で一つのデータを表します.Mark<Spaceであれば "1",Mark〜Spaceであれば "0" のビットとなり,データ列の前に比較的長い時間のMarkとSpace(Header)があります.
ここでresults.rawbuf
にはHeader開始前のSpaceを[0]としてMark,Spaceそれぞれの時間が入っていくので,Headerは配列の[1],[2],データは[3]以降です.時間は50us単位になっています(IRremote.cppより).
シリアルモニタを開きながらLEDライトのリモコンの点灯ボタンを押すと次のようなデータとなりました.
F6B92168
1956,72,32,11,6,11,6,11,24,10,24,10,7,11,24,10,7,10,7,10,7,11,24,10,7,10,7,10,25,10,7,10,24,10,8,9,25,10,7,10,7,10,25,9,8,10,7,10,8,9,8,9,25,9,9,9,24,10,25,9,9,9,25,9,8,9,8,10,8,9,8,9,25,9,8,10,8,9,25,9,8,10,8,9,
ここから各時間はおよそ
Mark (us) | Space (us) | |
---|---|---|
Header | 72 (3600) | 32 (1600) |
Data 0 | 10 (500) | 8 (400) |
Data 1 | 10 (500) | 24 (1200) |
のようになり,データ列は
0011 0100 0100 1010 1001 0000 1011 0100 0010 0100
となります.
他のボタンで試した結果
点灯: 0011 0100 0100 1010 1001 0000 1011 0100 0010 0100
消灯: 0011 0100 0100 1010 1001 0000 1111 0100 0110 0100
となり,初めの24bitは共通で,後の16bitについても,
(1011 0100)xor(1001 0000) = 0010 0100
(1111 0100)xor(1001 0000) = 0110 0100
となることから,前8bitを1001 0000
とのxor取ったものが後8bitでした.
赤外線信号の送信
結果的には,取得したデータ列0x344a90b424
を送信すればOKです.送信にはIRsendクラスを使います.使い方は ir_<メーカ名>.cpp ファイルを参考にできます.
# include <IRremote.h>
# define T_HDR_M 3600
# define T_HDR_S 1600
# define T_BIT_M 500
# define T_ONE_S 1200
# define T_ZERO_S 400
IRsend irsend;
void sendIr(unsigned long data, int nbits)
{
irsend.enableIROut(38); //38kHzでの送信設定
// Header
irsend.mark(T_HDR_M);
irsend.space(T_HDR_S);
// Data
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
if (data & mask) {
irsend.mark(T_BIT_M);
irsend.space(T_ONE_S);
} else {
irsend.mark(T_BIT_M);
irsend.space(T_ZERO_S);
}
}
// Footer
irsend.mark(T_BIT_M);
irsend.space(0);
}
void setup()
{
Serial.begin(9600);
sendIr(0x344a90b424UL, 40);
}
電源を入れると電気が点くはずです
(元のソースから切り貼りしているのでうまくいかなければコメントください..)
後記
これの後の話として,安価にIoTできるESP32で同じことを実施しようとしたのですが,純正バージョンでは送信側(IRsend)が対応していないため,別バージョンを探すことに.またいざできても電圧が5Vではなく3.3Vによる弊害が色々と出て難儀しました.ニーズあればまた記事書きます.