室内灯自動点灯システム

システムなんて言うほど大した物ではないが、先日室内灯の蛍光灯が切れたのを機会に、LEDシーリングライトに交換した(日立LEC-AH08U)。お安い割に明るさ調整や色も白から電球色まで変えられるです。

付属のリモコンでON/OFF出来るのだが、リモコンが小さく、さらにボタンも小さくて押しにくい感じ、暗い部屋に来ていざ点けようとするとマゴマゴ感が否めない。そこでせっかくのリモコン受信付きの室内灯ということで人感センサーで自動で点灯する仕組みを作ることにした。

計画内容

  • 基本的にリモコンは使用せず、光量や色合い設定の為だけとする。
  • Arduinoなどのワンボードマイコンを使用して学習リモコンの要領でIR LEDを発光させる
  • 人感センサーでONさせるがOFFはしない(トイレの人感センサーライトで散々経験しているが、人がじっとしていると消灯してしまうので)。OFFの仕組みは別に用意する(フォトレジスタに手をかざしてOFFにする仕様)。
  • センサとLEDを仕込んだ適当なケースを3Dプリンタで製作

学習リモコン仕様

  • Arduino Nano(安い互換品)を使用
  • 人感センサー:‎ARCELI00595
  • IR LED:uxcell IRLED
  • IR受光素子:HX1838(リモコンコード取得用)
  • フォトレジスタ uxcell GL5528

右が配線図。受光素子はブレッドボード環境で実験的にリモコンコードを読み込むために使用することとし、実際の装置には組み込まない(装置としての学習機能は無し)

学習リモコン配線図

リモコン信号の学習

Arduinoのライブラリとして、ライブラリマネージャから赤外線リモコンのためのIRremoteをインストールすると、サンプルで付いてくる「ReceiveDump」を使用すると、使用したいリモコン信号を取得することが出来る。Arduino開発環境からシリアルモニタを起動しておくと下記のようにリモコン受信データの詳細がレポートされる。下記の例は今回ターゲットとしているシーリングライトのリモコン信号(ON)の詳細。

Protocol=PULSE_DISTANCE Address=0x0 Command=0x0 Raw-Data=0x3DC2FB 88 bits LSB first

Raw result in internal ticks (50 us) - with leading gap
rawData[180]: 
・・・・・
Raw result in microseconds - with leading gap
rawData[180]: 
・・・・・
Result as internal ticks (50 us) array - compensated with MARK_EXCESS_MICROS=20
uint8_t rawTicks[179] = {65,33, 10,24, 9,7, 9,8, 8,9, 8,9, 8,8, 8,9, 8,9, 8,9, 8,8, 8,9, 8,9, 8,25, 8,9, 8,8, 8,9, 8,9, 8,9, 8,8, 9,8, 9,24, 9,24, 9,8, 9,8, 9,8, 8,8, 9,8, 9,8, 8,25, 9,8, 8,25, 8,9, 8,25, 9,24, 9,24, 9,25, 8,8, 9,24, 9,8, 9,25, 8,8, 9,8, 9,8, 8,9, 8,8, 9,8, 8,9, 8,9, 8,25, 8,25, 8,25, 9,24, 9,24, 9,25, 8,25, 8,25, 9,8, 9,8, 8,25, 8,9, 8,8, 9,8, 9,8, 8,9, 8,25, 8,25, 9,8, 8,25, 9,25, 8,25, 8,25, 8,25, 9,8, 8,25, 9,8, 8,9, 8,9, 8,8, 8,25, 9,25, 8,25, 8,9, 8,25, 8,25, 8,25, 8,25, 9,8, 8,9, 8};  // Protocol=PULSE_DISTANCE Address=0x0 Command=0x0 Raw-Data=0x3DC2FB 88 bits LSB first

Result as microseconds array - compensated with MARK_EXCESS_MICROS=20
uint16_t rawData[179] = {3230,1670, 480,1220, 430,370, 430,420, 380,470, 380,470, 380,420, 380,470, 380,470, 380,470, 380,420, 380,470, 380,470, 380,1270, 380,470, 380,420, 380,470, 380,470, 380,470, 380,420, 430,420, 430,1220, 430,1220, 430,420, 430,420, 430,420, 380,420, 430,420, 430,420, 380,1270, 430,420, 380,1270, 380,470, 380,1270, 430,1220, 430,1220, 430,1270, 380,420, 430,1220, 430,420, 430,1270, 380,420, 430,420, 430,420, 380,470, 380,420, 430,420, 380,470, 380,470, 380,1270, 380,1270, 380,1270, 430,1220, 430,1220, 430,1270, 380,1270, 380,1270, 430,420, 430,420, 380,1270, 380,470, 380,420, 430,420, 430,420, 380,470, 380,1270, 380,1270, 430,420, 380,1270, 430,1270, 380,1270, 380,1270, 380,1270, 430,420, 380,1270, 430,420, 380,470, 380,470, 380,420, 380,1270, 430,1270, 380,1270, 380,470, 380,1270, 380,1270, 380,1270, 380,1270, 430,420, 380,470, 380};  // Protocol=PULSE_DISTANCE Address=0x0 Command=0x0 Raw-Data=0x3DC2FB 88 bits LSB first

uint16_t address = 0x0;
uint16_t command = 0x0;
uint32_t data = 0x3DC2FB;
・・・・・

この例ではプロトコルがPULSE_DISTANCEとなっており、サポートしているメーカーフォーマットでは無いっぽいため、rawDataとして直接送信する必要がある。ターミナルに出力された詳細データのrawDataはそのままCのソースに貼り付けられる形式となっている。

// 初期化
IrSender.begin(IR_SEND_PIN);
// 送信部
uint16_t rawData[179] = {
  3230,1720, 380,1270, 380,470, 380,420, 480,370, 430,420, 430,420,
  430,420, 380,420, 430,420, 430,420, 430,420, 380,470, 380,1270,
  380,470, 380,420, 430,420, 430,420, 430,420, 380,470, 380,420,
  430,1270, 380,1270, 430,420, 380,470, 380,420, 430,420, 430,420,
  430,420, 380,1270, 430,420, 380,1270, 430,420, 430,1220, 430,1270,
  380,1270, 380,1270, 430,420, 380,1270, 430,420, 430,1220, 430,420,
  430,420, 430,420, 380,470, 380,420, 430,420, 430,420, 380,470, 380,1270,
  430,1220, 430,1270, 380,1270, 380,1320, 380,1270, 380,1270, 380,1270,
  430,420, 430,420, 380,1320, 380,420, 380,470, 380,420, 430,420, 430,420じ,
  430,1270, 380,1270, 380,470, 380,1270, 380,1270, 430,1270, 380,1270,
  380,1320, 380,420, 430,1270, 380,420, 430,420, 380,470, 380,470, 380,1270,
  380,1270, 430,1270, 380,470, 380,1270, 380,1270, 380,1270, 430,1270,
  380,420, 430,420, 380
};
IrSender.sendRaw(rawData, sizeof(rawData) / sizeof(rawData[0]), 38);

Arduinoのプログラムでは人感センサーの出力に連動してON信号を送信、フォトレジスタのアナログ入力レベルが一定以下になったとき(手をかざすなど)にOFF信号を送信する仕組みとした。

フローチャート(draw.io)
START
START
初期化
初期化
Yes
Yes
No
No
readmode?
readmode?
受信モード初期化
受信モード初期化
送信モード初期化
送信モード初期化
Loop
Loop
Yes
Yes
No
No
readmode?
readmode?
Yes
Yes
受信データあり
受信データあり
受信データ
ターミナル出力
受信データ ターミナル出力
光センサ
光センサ
On
On
Off
Off
LIGHT Mode
LIGHT Mode
LIGHT OFF CMD
LIGHT Mode Off
LIGHT OFF CMD…
Off
Off
Off
Off
LIGHT Mode
LIGHT Mode
5000ms
5000ms
Yes
Yes
No
No
人感センサ
人感センサ
LED インジケータON
LED インジケータON
1500ms
1500ms
Yes
Yes
人感センサ
人感センサ
LIGHT ON CMD
LIGHT ON CMD
1000ms
1000ms
500ms
500ms
LED インジケータOFF
LED インジケータOFF
100ms
100ms
LIGHT Mode On
LIGHT Mode On
Text is not SVG – cannot display

←ソースコードと簡単な資料はこちら

完成した装置全貌

3Dプリンタでザックリ作ったボックスと内部配線。

ボックスの上部にリモコン発信用赤外線LEDとOFF感知用フォトレジストを埋め込んでます。

リモコンが小さすぎて操作しにくいなら、従来通り壁スイッチで良いじゃん!というのはごもっともなお話ですが、それに気づいたのが一通り完成して運用し始めてからでしたw
あと、最近の半導体不足でArduinoが純正品しか手に入らず比較的高価なため、安価なRaspberryPi Picoに移植するべく開発環境など準備中・・・てか次の投稿ネタに保存中。。