Image may be NSFW.
Clik here to view.
Clik here to view.

オーデリック LEDシーリングライト リモコン付き LED一体型 電球色~昼光色 調光・調色タイプ ~12畳 SH8237LDR
- 出版社/メーカー: オーデリック
- メディア: ホーム&キッチン
Image may be NSFW.
Clik here to view.

今回のネタは天井照明です。家にはLEDタイプのオーデリックの天井照明を全部の部屋に入れました。
アマゾンリンクの前の型ですが、多分リモコン制御に関しては変わらないと思います。
この天井照明は結構コストパフォーマンスに優れていると思います。12畳でリモコン付き、調光付きで実売が1万円切っていますから。家に入れたのは2015年3月ですので、4年以上安定稼働しています。またわざわざIoTにしなくても付属のリモコンに時計が付いていますので、指定時間に照明を消す/点けるができます。
さて、この天井照明をリモコンで制御するためにはリモコンコードを知らなくてはできませんが(※相変わらずリモコンコードの仕様は公開されていない)、、、とは言え秋月電子とかで売られている赤外線受光素子を用意すれば( http://akizukidenshi.com/catalog/g/gI-04659/ )、Arduinoを使って比較的容易にコードを読み取る事ができます。※受光についてはその内やります。
とりあえずこの天井照明はNECフォーマットとなっています。
一般的に家電に使われているリモコンフォーマットは、NECフォーマット、AEHAフォーマット、SONYフォーマットが有ります。これらのフォーマットの詳細については以下のページを読んで下さい。
ChaNさんのリモコンコードの解説ページ
http://elm-chan.org/docs/ir_format.html
ちょっと補足
キャリア:キャリアは使用する赤外線LEDで決まってしまいます。秋月で買える赤外線LED( http://akizukidenshi.com/catalog/g/gI-12612/ )は大概波長940μmです。要らないリモコンを分解して取り出しても構いません。半減角:15°(狭角)~60°(広角)や、LEDに流す電流で使い易さが変わってくるでしょう。
サブキャリア周波数:キャリアをパルス状にして出力する事で、ちまたに溢れている赤外線と、リモコンの赤外線を区別していますが、そのパルスの周波数です。一般的に38kHz前後です。
つまりリモコンコードのビット毎の0または1に対応するパターンに従って赤外線LEDをON/OFFさせれば良いことが判ります。この時ArduinoであればサブキャリアはanalogWrite、パルスの時間はdelayMicrosecondsを使えば実現できます。
/*************************************************************************/ /* NECタイプのデータ送信 */ /*************************************************************************/ void iRRemocon::txNEC(const unsigned char data[], unsigned int sz) { #define T_VALUE 555UL // 562UL #define PPM_ON 128 //170 #define PPM_OFF 255 analogWriteRange( 255 ); analogWriteFreq( 38 * 1000UL ); analogWrite(_IR_CONT,0); //frame ppm on analogWrite(_IR_CONT,PPM_ON); delayMicroseconds(T_VALUE * 16); //16T //frame ppm off analogWrite(_IR_CONT,PPM_OFF); delayMicroseconds(T_VALUE * 8); //8T for(int i = 0; i < sz; i++) { byte temp = data[i]; for(int j = 0; j < 8; j++) { if(temp & 0x01) { //frame ppm on analogWrite(_IR_CONT,PPM_ON); delayMicroseconds(T_VALUE * 1); //1T //frame ppm off analogWrite(_IR_CONT,PPM_OFF); delayMicroseconds(T_VALUE * 3); //3T } else { //frame ppm on analogWrite(_IR_CONT,PPM_ON); delayMicroseconds(T_VALUE * 1); //1T //frame ppm off analogWrite(_IR_CONT,PPM_OFF); delayMicroseconds(T_VALUE * 1); //1T } temp >>= 1; } } //stop bit //frame ppm on analogWrite(_IR_CONT,PPM_ON); delayMicroseconds(T_VALUE * 1); //1T //frame ppm off analogWrite(IR_CONT,0); }
ですがまぁ、折角エアコン制御を実現しているので、そこで使われている赤外線出力のインスタンスを利用する事とします。
インスタンスの使い方を知るために、三菱のエアコンのコードを見てみます。三菱のエアコンはAEHAフォーマットです。
MitsubishiHeatpumpIR.cpp
void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH) { 長いので抜粋 // 40 kHz PWM frequency IR.setFrequency(38); // The Mitsubishi data is repeated twice for (int j=0; j<2; j++) { // Header IR.mark(MITSUBISHI_AIRCON1_HDR_MARK); IR.space(MITSUBISHI_AIRCON1_HDR_SPACE); // Data for (unsigned int i=0; i<sizeof(MitsubishiTemplate); i++) { IR.sendIRbyte(MitsubishiTemplate[i], MITSUBISHI_AIRCON1_BIT_MARK, MITSUBISHI_AIRCON1_ZERO_SPACE, MITSUBISHI_AIRCON1_ONE_SPACE); } // Pause between the first and the second data burst // Also modify one byte for the second burst on MSY model. This does not affect the checksum of the second burst if (j == 0) { IR.mark(MITSUBISHI_AIRCON1_BIT_MARK); IR.space(MITSUBISHI_AIRCON1_MSG_SPACE); if (_mitsubishiModel == MITSUBISHI_MSY) { MitsubishiTemplate[14] = 0x24; } } } // End mark IR.mark(MITSUBISHI_AIRCON1_BIT_MARK); IR.space(0); }
MitsubishiHeatpumpIR.h
/* Mitsubishi MSZ FD-25 heatpump control (remote control P/N KM09D 0052376) */ #ifndef MitsubishiHeatpumpIR_h #define MitsubishiHeatpumpIR_h #include "HeatpumpIR.h" 長いので抜粋 // Mitsubishi MSZ FD-25 timing constants (remote control P/N KM09D 0052376) #define MITSUBISHI_AIRCON1_HDR_MARK 3500 #define MITSUBISHI_AIRCON1_HDR_SPACE 1700 #define MITSUBISHI_AIRCON1_BIT_MARK 430 #define MITSUBISHI_AIRCON1_ONE_SPACE 1250 #define MITSUBISHI_AIRCON1_ZERO_SPACE 390 #define MITSUBISHI_AIRCON1_MSG_SPACE 17500 class MitsubishiHeatpumpIR : public HeatpumpIR { protected: // Cannot create generic Mitsubishi heatpump instances MitsubishiHeatpumpIR(); uint8_t _mitsubishiModel; // Tells whether this is FD or EF (or other supported model...) public: void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); private: void sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingVCmd, uint8_t swingHCmd); }; #endif
定義のMITSUBISHI_AIRCON1_HDR_MARKは赤外線フレームのLeader部の8Tに、MITSUBISHI_AIRCON1_HDR_SPACEはLeader部の4Tに相当します。
MITSUBISHI_AIRCON1_BIT_MARKはパルスを出している時間、MITSUBISHI_AIRCON1_ONE_SPACEはビット1のパルスの無い時間、MITSUBISHI_AIRCON1_ZERO_SPACEはビット0のパルスの無い時間に相当します。
ChaNさんの解説と微妙に時間が合わないのは、調整が入っているのかもしれません。
上記を参考にオーデリックのライブラリを作成してみました。現時点ではZIPインストールをせず、プロジェクトディレクトリに保存しているので、includeパスに注意が必要です。
odelic.h
/****************************************************************************/ /* お家のオーデリック製LED照明をなんとかするヘッダー */ /* Copyright (C) 2014 hamayan All Rights Reserved. */ /****************************************************************************/ #ifndef odelic_h #define odelic_h #include <Arduino.h> #include <HeatpumpIR.h> extern "C" { // #include <mul_tsk.h> } /****************************************************************************/ /* なにかの定義 */ /****************************************************************************/ #define NEC_T_PERIOD 562UL // 562us #define NEC_REPEAT_PERIOD 120UL // 108ms #define ODELIC_CHANNEL_1 0 #define ODELIC_CHANNEL_2 1 #define ODELIC_CHANNEL_3 2 typedef struct /*オーデリックのフォーマットはNECタイプ*/ { unsigned char customerCode[2]; unsigned char data[2]; } ODELIC_CEILING_LIGHT_CODE; class odelic : public HeatpumpIR { private: uint8_t channel; uint32_t startTim; void send( IRSender& IR, uint8_t *code ); public: odelic( uint8_t ch = 0 ); void onOff( IRSender& IR, bool onoff ); void coldLight( IRSender& IR, int value ); void warmLight( IRSender& IR, int value ); char type( void ); }; #endif /*odelic_h*/ /****************************************************************************/ /* Copyright (C) 2014 hamayan All Rights Reserved. */ /****************************************************************************/
odelic.cpp
/*************************************************************************/ /* お家のオーデリック製LED照明をなんとかするソース */ /* designed by hamayan since 2015/05/28 */ /*************************************************************************/ #include "odelic.h" /*************************************************************************/ /* 大域変数宣言 */ /*************************************************************************/ /*調光を行う時は連続して2つのコードを送信する。つまり寒色と暖色の両方のLEDを制御している*/ /*また、輝度毎にコードが異なる。それ以外に3byte目と4byte目は反転の関係となる*/ static const unsigned char on[] = { 0x84, 0x51, 0x9a ,0x65 }; /*ch2: 0x84, 0x51, 0x9b,0x64*/ static const unsigned char off[] = { 0x84, 0x51, 0x08 ,0xf7 }; /*ch2: 0x84, 0x51, 0x09,0xf6*/ static const unsigned char cold[][4] = { { 0x84, 0x51, 0x6c ,0x93 }, /*10% ch2: 0x84, 0x51, 0x6d,0x92*/ { 0x84, 0x51, 0x6e ,0x91 }, /*20% ch2: 0x84, 0x51, 0x6f,0x90*/ { 0x84, 0x51, 0x70 ,0x8f }, /*30% ch2: 0x84, 0x51, 0x71,0x8e*/ { 0x84, 0x51, 0x72 ,0x8d }, /*40% ch2: 0x84, 0x51, 0x73,0x8c*/ { 0x84, 0x51, 0x74 ,0x8b }, /*50% ch2: 0x84, 0x51, 0x75,0x8a*/ { 0x84, 0x51, 0x76 ,0x89 }, /*60% ch2: 0x84, 0x51, 0x77,0x88*/ { 0x84, 0x51, 0x78 ,0x87 }, /*70% ch2: 0x84, 0x51, 0x79,0x86*/ { 0x84, 0x51, 0x7a ,0x85 }, /*80% ch2: 0x84, 0x51, 0x7b,0x84*/ { 0x84, 0x51, 0x7c ,0x83 }, /*90% ch2: 0x84, 0x51, 0x7d,0x82*/ { 0x84, 0x51, 0x7e ,0x81 }, /*100% ch2: 0x84, 0x51, 0x7f,0x80*/ }; static const unsigned char warm[][4] = { { 0x84, 0x51, 0x58 ,0xa7 }, /*10% ch2: 0x84, 0x51, 0x59,0xa6*/ { 0x84, 0x51, 0x5a ,0xa5 }, /*20% ch2: 0x84, 0x51, 0x5b,0xa4*/ { 0x84, 0x51, 0x5c ,0xa3 }, /*30% ch2: 0x84, 0x51, 0x5d,0xa2*/ { 0x84, 0x51, 0x5e ,0xa1 }, /*40% ch2: 0x84, 0x51, 0x5f,0xa0*/ { 0x84, 0x51, 0x60 ,0x9f }, /*50% ch2: 0x84, 0x51, 0x61,0x9e*/ { 0x84, 0x51, 0x62 ,0x9d }, /*60% ch2: 0x84, 0x51, 0x63,0x9c*/ { 0x84, 0x51, 0x64 ,0x9b }, /*70% ch2: 0x84, 0x51, 0x65,0x9a*/ { 0x84, 0x51, 0x66 ,0x99 }, /*80% ch2: 0x84, 0x51, 0x67,0x98*/ { 0x84, 0x51, 0x68 ,0x97 }, /*90% ch2: 0x84, 0x51, 0x69,0x96*/ { 0x84, 0x51, 0x6a ,0x95 }, /*100% ch2: 0x84, 0x51, 0x6b,0x94*/ }; /*************************************************************************/ /* プロトタイプ宣言 */ /*************************************************************************/ /*************************************************************************/ /* インスタンス */ /*************************************************************************/ odelic::odelic( uint8_t ch ) { channel = ch; startTim = millis(); } /*************************************************************************/ /* send */ /*************************************************************************/ void odelic::send( IRSender& IR, uint8_t *code ) { uint8_t tempUC[4]; memcpy( tempUC, code, sizeof(tempUC) ); tempUC[2] = tempUC[2] + channel; tempUC[3] = tempUC[3] - channel; // 40 kHz PWM frequency IR.setFrequency( 38 ); //リピートでメソッドが呼ばれた時、強制的に間隔を開ける while( (millis() - startTim) < NEC_REPEAT_PERIOD ) delay( 10 ); // start time startTim = millis(); // Header IR.mark( 16 * NEC_T_PERIOD ); //frame ppm on IR.space( 8 * NEC_T_PERIOD ); //frame ppm off // Data for( unsigned int i = 0; i < sizeof( tempUC ); i++ ) { IR.sendIRbyte( tempUC[i], NEC_T_PERIOD, NEC_T_PERIOD, 3 * NEC_T_PERIOD ); // data,562us,562us,1686us // pulse on period, pulse off period at ZERO, pulse off period at 1 } // End mark IR.mark( NEC_T_PERIOD ); IR.space( 0 ); } /*************************************************************************/ /* 引数valueは2以上で100以下の数字 */ /*************************************************************************/ void odelic::coldLight( IRSender& IR, int value ) { if( value >= 2 && value <= 100 ) { value--; value /= 10; send( IR, (uint8_t *)cold[ value ] ); } } /*************************************************************************/ /* 引数valueは2以上で100以下の数字 */ /*************************************************************************/ void odelic::warmLight( IRSender& IR, int value ) { if( value >= 2 && value <= 100 ) { value--; value /= 10; send( IR, (uint8_t *)warm[ value ] ); } } /*************************************************************************/ /* 引数valueは0または1またはそれ以上で100以下の数字 */ /*************************************************************************/ void odelic::onOff( IRSender& IR, bool onoff ) { if( onoff ) send( IR, (uint8_t *)on ); else send( IR, (uint8_t *)off ); } /*************************************************************************/ /* リモコンフォーマットを答える */ /*************************************************************************/ char odelic::type( void ) { return 'N'; /*NECのN!*/ } /*************************************************************************/ /* end of file */ /* designed by hamayan since 2015/05/28 */ /*************************************************************************/
スケッチ側はこんなんなります。
#include "odelic.h" #define IR_CONT 12 // Ir control IRSenderBitBang irSender( IR_CONT ); odelic *room1 = new odelic( ODELIC_CHANNEL_1 ); /*************************************************************************/ /* blynk virtual pin 2 function. */ /*************************************************************************/ BLYNK_WRITE( V2 ) { int value = param.asInt(); if( value ) { room1->onOff( irSender, true ); Blynk.virtualWrite( V4, 100 ); Blynk.virtualWrite( V5, 100 ); } else { room1->onOff( irSender, false ); Blynk.virtualWrite( V4, 0 ); Blynk.virtualWrite( V5, 0 ); } } /*************************************************************************/ /* blynk virtual pin 3 function. */ /*************************************************************************/ BLYNK_WRITE( V3 ) { room1->coldLight( irSender, 70 ); room1->warmLight( irSender, 70 ); Blynk.virtualWrite( V4, 70 ); Blynk.virtualWrite( V5, 70 ); } /*************************************************************************/ /* blynk virtual pin 4 function. */ /*************************************************************************/ BLYNK_WRITE( V4 ) { int value = param.asInt(); room1->warmLight( irSender, value ); } /*************************************************************************/ /* blynk virtual pin 5 function. */ /*************************************************************************/ BLYNK_WRITE( V5 ) { int value = param.asInt(); room1->coldLight( irSender, value ); }
オーデリックの天井照明は、隣り合う部屋でリモコンを使った時に間違って操作しないように、3チャネルまで設定できます。
Image may be NSFW.
Clik here to view.![ESP-WROOM-02開発ボード ESP-WROOM-02開発ボード]()
Clik here to view.

- 出版社/メーカー: スイッチサイエンス(Switch Science)
- メディア: おもちゃ&ホビー
Image may be NSFW.
Clik here to view.![オーデリック LEDシーリングライト リモコン付き LED一体型 電球色~昼光色 調光・調色タイプ ~14畳 SH8234LDR オーデリック LEDシーリングライト リモコン付き LED一体型 電球色~昼光色 調光・調色タイプ ~14畳 SH8234LDR]()
Clik here to view.

オーデリック LEDシーリングライト リモコン付き LED一体型 電球色~昼光色 調光・調色タイプ ~14畳 SH8234LDR
- 出版社/メーカー: オーデリック
- メディア: ホーム&キッチン