赤外線リモコン受信モジュール (110円) をRaspberry Piに取り付けて、赤外線パターンを取得・復号できるようにしました。天井照明リモコンの点滅パターンをこれで取得して、ESP32に組み込んで、HomeKitから点灯・消灯できました。
これまでのあらすじ
前回、HomeKitからパナソニックのエアコンをコントロールするスマート赤外線リモコンが完成しました。
エアコンをコントロールするスマートリモコンとして、Nature Remoを使っていたのですが、これをDIYしたことでほぼ使わなくなってしまいました。唯一使用している機能が、赤外線リモコンの生データをローカルAPIで取得する機能です。
Nature Remoにリモコンを向けてボタンを押すと、Nature Remoがパターンを取得してくれます。そのパターンはhttpアクセスで知ることができます。パターン取得機能のためだけにNature Remoを使うのは勿体無いので、今回はこれをDIYします。赤外線リモコン受信モジュールをRaspberry Piに取り付けて、赤外線パターンを取得することにしました。
赤外線リモコン受信モジュール
使用した赤外線リモコン受信モジュールは、秋月電子で110円で売られているPL-IRM0101-3という製品です。
これ1個を、3本のワイヤでRaspberry Piに取り付けるだけで、赤外線パターンが得られます。この部品のことは、赤外線リモコン自作ページでよく見かけていたので、以前から知ってました。発売日が2004年だそうですので、18年も続くロングセラーです。秋月電子のサイトには、他にも半額くらいで類似の製品がいくつかありますので、そちらでも良かったかもしれません。
サイトには電源が5Vと書いてありましたが、リンクされていたデータシートによると3Vにも対応しているようです。ただ古いロットの製品(Rev B/1)は5V限定だったようです。Raspberry PiのGPIOは3Vなので、現行のRev B/2が必要です。
Raspberry Piに取り付ける
PL-IRM0101-3のピンは3本で、左から、(1)信号、(2)GND、(3)Vccです。
これらの1, 2, 3番ピンをRaspberry PiのGPIOの 7, 9, 1番ピンに接続しました。
温度湿度センサの時と同様に、フラットケーブルになったジャンパ線を割いて使用しました。そして受信モジュールを、Raspberry Piケースにテープで止めしました。
生データ取得プログラム
GPIOピンの7番はGPIO 4です。データシートによると、受信モジュールは通常は1で、赤外線信号があると0になるようです。下図の上段がモジュールが受け取る赤外線強度、下段がモジュールの出力です。
GPIOをreadしたところ、やはり通常は1で、赤外線が照射されると0になりました。そこで、
- GPIOが10秒間1のままならば終了する
- GPIOが1ms以上0になったら以下の測定を開始する
- GPIOが変化するたびにその間隔をマイクロ秒単位で記録する
- GPIOが20ms以上変化しなくなるまで3を繰り返す
- 結果を表示する
というプログラムを、Raspberry Pi上のPython3で作成しました。以下です。
#!/usr/bin/python3
import RPi.GPIO as GPIO
import time
import sys
PIN=4
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN,GPIO.IN)
raw=[]
print("Waiting for IR signal (for 10sec)...")
time_now=time.time()
time_start=time_now
while (time_now - time_start) < 10 :
time_now=time.time()
if GPIO.input(PIN)==0:
time.sleep(0.001) #1ms delay
if GPIO.input(PIN)==0: #still 0
break
if (time_now - time_start) >= 10 :
print("Time out.")
sys.exit()
time_start=time_now
gpio_last=0
while (time_now - time_start) < 0.02 :
time_now=time.time()
gpio_now=GPIO.input(PIN)
if(gpio_last != gpio_now):
raw.append(round((time_now - time_start)*1000000))
time_start=time_now
gpio_last=gpio_now
print(raw)
天井照明リモコンパターンを取得する
簡単な例として、毎回登場している天井照明のリモコンを試します。これのon/offボタンのパターンを取得してみます。上記のプログラムを動かすと(irreceive.pyという名前をつけました)、
$ ./irreceive.py Waiting for IR signal (for 10sec)... [6929, 4539, 371, 1316, 369, 494, 342, 1345, 344, 514, 368, 1319, 369, 492, 345, 1342, 345, 518, 367, 490, 366, 1324, 371, 485, 371, 490, 370, 1318, 345, 1343, 371, 1314, 372, 1323, 345]
という結果が得られました。グラフにすると以下のようです。横軸が時間で縦軸が赤外線出力です。開始のパルスは長めですし、0, 1に相当するパルス幅も広く、一般的なフォーマットとは少し違う特殊なリモコンのようです。
ESP32で作るDIYスマートリモコンに組み込む
ESP32で、エアコン用のスマートリモコンを作りましたが、
今ここで得られた生データを送出する機能を、このESP32に追加して、天井照明もコントロールするように設定します。
エアコンのリモコンとして動作していたプログラムに、この天井照明のパターンを送出する部分を以下のように追加しました。赤外線点滅の生データを送出するためには、IRsendクラスのインスタンス(下記プログラムではirsend)を作って、これのsendRawというメソッドを使えば良いようです。このメソッドでon/offの生データを以下のように送ります。
#include <Arduino.h>
#include <ArduinoOTA.h>
//IR Remote
#include <IRremoteESP8266.h>
const uint16_t kIrLed = 4; //GPIO for IR LED. Recommended: 4.
const char SUBTOPIC[] = "mqttthing/irOffice/set/#";
(略)
IRsend irsend(kIrLed); //for sending raw IR data
//ceiling light on/off pattern
const uint16_t kCeilingOnOff[35]= {
6929, 4539, 371, 1316, 369, 494, 342, 1345, 344, 514, 368, 1319, 369, 492, 345, 1342, 345, 518, 367, 490, 366, 1324, 371, 485, 371, 490, 370, 1318, 345, 1343, 371, 1314, 372, 1323, 345
};
void setup() {
(略)
}
//MQTT: subtopic call back
void onMessageReceived(const String& topic, const String& message) {
String command = topic.substring(topic.lastIndexOf("/") + 1);
if (command.equals("Active")) {
(略)
}else if(command.equals("CeilingOnOff")){
if(message.equalsIgnoreCase("true")) irsend.sendRaw(kCeilingOnOff, 35, 38);
}
}
//MQTT: connection callback
void onConnectionEstablished() {
ArduinoOTA.setHostname("irOffice");
ArduinoOTA.setPasswordHash("xxxxxxxxxxxxxxx");
ArduinoOTA.begin();
client->subscribe(SUBTOPIC, onMessageReceived); //set callback function
}
(略)
void loop() {
ArduinoOTA.handle();
client->loop();
}
これで、mqttthing/irOffice/set/CeilingOnOffにtrueというメッセージが送られると、この生データを送出します。
一方、HomebridgeのMqttthingの設定部分には、以下のように追記して、このMQTTメッセージに対応するスイッチを作成しました。
{
"type": "switch",
"name": "Ceiling Toggle",
"topics": {
"setOn": "mqttthing/irOffice/set/CeilingOnOff"
},
"turnOffAfterms": 300,
"accessory": "mqttthing"
}
この結果、iPhone, Macのホーム.appに、以下のように赤外線信号を送出するスイッチが追加されました。turnOffAfterms (turn off after ms) を300msに設定したので、通常はoffの状態で、
クリックすると0.3秒だけonの状態になり、またoffに戻ります。
これをクリックするたびに、上記の赤外線パターンが送出され、天井照明はon/off状態を交互に繰り返します。
デコード機能
前後しますが、上述のPythonプログラムに、赤外線パターンのデコード機能を追加しました。上記のプログラムの末尾に、以下を追加します。
T=400.0
isOn=False
evaluateNext=False
count=0
aByte=0
for x in raw:
isOn = not isOn
width=round(x/T)
if(width > 3) and (isOn == False):
count=0
aByte=0
print()
if(width == 1) and (isOn == True):
evaluateNext=True
elif(evaluateNext):
evaluateNext=False
if(width == 1):
aByte = aByte >> 1
count += 1
elif(width == 3):
aByte = (aByte >> 1) + 0x80
count += 1
if(count >= 8):
print(format(aByte,'02X'),end='')
aByte=0
count=0
print()
かなり手抜きです。Tで、短いパルス幅を指定しておきます。T幅の赤外線Onパルスが見つかったら、その次のOff幅を測定して、Tならば0、3Tならば1としています。また、それぞれのバイトのLSBから順番に送信されていると仮定してます。NECと家製協のフォーマットがこの方式なので、汎用性は高いです。
例えば、上記の天井照明リモコン (これは独自フォーマットですが0, 1 がほぼ1T, 3Tです) ならば、
$ ./irreceive.py 55F2
となります(生データのprint文はコメントアウトしました)。エアコン用スマートリモコンで使用したパナソニックのエアコンならば、
$ ./irreceive.py 0220E00400000006 0220E00400412C80AF0000066000008000068E
と表示されます。 (これは22度暖房のパターンです)
まとめ
秋月電子などで一般的に売られている赤外線リモコン受信モジュールを、Raspberry Piに取り付けて、赤外線を取得しデコードもできるようにしました。これを用いて、天井照明のリモコンのon/offパターンを測定し、ESP32から送出するようにして、HomeKitから使えるようにしました。この手順で、HomeKit対応スマート学習リモコンをDIYできます。
コメント