Welcome to telecotele.com » Projects

赤外線リモコンの信号を見る

身近にある赤外線リモコンの信号を見ます。

tags: house

はじめに

38kHzくらいで変調された、身近にある赤外線リモコンの信号を見ます1

丁寧な暮らし行きにしようと思ったら、長くなってProjects行きになりました (KUMDYU)

赤外線リモコンの仕様

赤外線リモコンの仕様については、多くの解説をWebや書籍から得られます。 特にWeb上では下記のページがわかりやすいでしょう。

赤外線リモコンの通信フォーマット
http://elm-chan.org/docs/ir_format.html

自分の理解のため簡単にまとめておくと、赤外線リモコンの仕様は、

  • (搬送波となる赤外線の)波長は950nmくらい
    • 入手しやすい赤外線LEDとしては波長850nmと940nmのタイプがあるようで、940nmのほうを使えば良さそう
  • (副)搬送波はだいたい38kHz
  • NECフォーマット、家電製品協会(家製協)フォーマットなどがある
    • NECフォーマットは固定長。「識別コード16bits + データ8bits + データの反転8bits」で実質のデータは8bits分
    • 家製協フォーマットは可変長
    • (家製協フォーマットは、赤外線送信ライブラリによってはPanasonicフォーマットと呼ばれている気がする)
  • だいたい「リーダー(スタートビット相当)・データ部分・トレーラー(ストップビット相当)」で構成される
    • トレーラーについては無いフォーマットもある
    • 少なくともNECフォーマット、家製協フォーマットにはありそう。1T分の時間ONしてしばらくOFF
  • データ部分はPPM (Pulse Position Modulation)
  • 8bit単位で1バイトを構成
  • バイト単位で(だいたい)LSB Firstで送る
    • 家製協フォーマットにおける「カスタマーコードのパリティ (4bits) + データ (4bits)」(P0 P1 P2 P3 D0 D1 D2 D3)もMSB Firstの表現にするとD3 D2 D1 D0 P3 P2 P1 P0になる

です。 規格認証があるわけでもなく(たぶん)、絶対にこの仕様どおりしないとダメ、もし破ったら島流し!というのは無さそうです。 たとえば一見NECフォーマットっぽいけど「反転データ」部分もデータとして使っている(データを16bits分として使っている)こともある2ようで、この辺は実装によると思います。

副搬送波はだいたい38kHzということで、では「だいたい」じゃないものは?というと、たとえば36.7kHzで反応する機器3はあるらしいです。 とはいえこれくらいなら38kHzで変調して送っても受け入れてくれるんじゃないかという気がします。 逆に38kHz用の受光モジュールしか無い状態で36.7kHzの信号を見たい場合は? 一例としてPNA4602M(38kHz用の受光モジュール)の場合、次に示す特性を見ると中心周波数の場合よりも感度は落ちますが近距離なら受信できそうですね。 ちなみに波長は(あくまでこのモジュールの場合は)850nmではダメで、やはり940nmあたりを使う必要がある。

PNA4602Mの特性(抜粋。データシートより) PNA4602Mの特性(抜粋。データシートより)

なお、副搬送波のデューティー比については “25%” や “33%” とするだったり、 (トランジスタでスイッチングを行う場合は)トランジスタがオフする際の遅延時間を考慮してMCUからの出力は33%としているがLEDを駆動させる時点では “50%” になることを期待している(そのためFETを使うなどして遅延時間を考慮しない場合はMCU出力の時点から50%にする)4だったり、 いややっぱり本当にLED自体を “33%” で駆動させないとダメかも?5だったり、 もっと小さい “10%” でも良いから代わりにLEDに流す電流を増やして距離が伸びることを期待6だったりよく分かりません。とはいえ基本は50%にしたいはずで、昔は受光モジュール側も50%じゃないと受け入れてくれなかった? さらにトランジスタを使った構成ばかりだったので33%にしていた、いつしかこれが定説化しどんな状況でも33%が使われるようになり、やがて受光モジュールの性能向上により小さいデューティー比でもOKになった……とか?

今回は「赤外線リモコンの信号を見る」のため送信についてはあまり触れませんが、自分の方針としては「できるだけLEDに電流を流したい、(バッテリー駆動はたぶんしないので)消費電力はなんとかなる、でも定格を超えるのは怖い……」により、「(パルスではない常時点灯の)順電流定格を気持ち超えるくらいの電流で、デューティー比10%から始める、それで不満なら25%、33%、50%と増やす」でいこうと思います。 LEDを駆動させる際は遅延時間のことは考えたくないのでFETを使うつもりです。

見る

見ます。

まず、受光モジュール「GP1UXC41QS」と下記ページの情報を基に「Rawデータ」を取得します。

Arduinoで家にある赤外線リモコン全部解析 #Arduino - Qiita
https://qiita.com/awawaInu/items/25c6e17fcc2e655d5d42

ここで「Rawデータ」は(38kHzの副搬送波から復調された)リモコンの信号そのもので、次のようなフォーマットで表します。

Raw: (199)[3396, 1628, 452, 360, 476, 1224, ... , 452]

これは先頭部分からリーダー(スタートビット相当)信号を受信した様子を示しており、「0-origin indexで偶数なら信号がONしている時間 [us]」「奇数ならOFFしている時間 [us]」を表しています。 この例は「3396 [us] ONで、1628 [us] OFFで、452 [us] ONで…、最後 452 [us] ON(で以降ずっとOFFになる)」です。

以降では身近にある赤外線リモコンの信号について、Rawデータや別途デコードしバイト列に直した結果を載せながら述べていきます。 なお、バイト列はパリティの検算をしやすくするためLSB First(受信した信号の並びのまま)の状態で表現します。

SHARP テレビ

「LC-32H30」(リモコン型番GB177SA)というSHARP製テレビの信号を見ます。

  • 家製協フォーマットと思われる
  • T = 400[us] ~ 450[us]くらい
  • リーダー … 8T ON、4T OFF
  • データ … 48bits
  • トレーラー … 1T ON

ちなみに、ただのフォトダイオードを通して副搬送波そのものを含む信号も見てみました。 ただ、副搬送波は38kHzっぽい7こと、またデューティー比は50%には見えないような……かと言って45%か?40%か?と問われると具体的な判別できませんが33%寄りな気がする……というくらいしか分かりませんでした。 他のリモコンも見てこれはデューティー比が50%と言えるかも……というものもありましたが、やっぱりよく分からないのでもう見ません。

電源ON/OFF

普通にボタンを押すと、「55 5A F1 48 68 8Bの送信 + 4.5[ms]ほどsleep + また55 5A F1 48 68 8Bの送信」という構成でした。 また、ボタンを押し続けると「55 5A F1 48 68 8Bの送信 + 4.5[ms]ほどsleep」が2,3回繰り返されます。 特にリピート信号や再送フラグのようなものは付いていないようです。

Rawデータはこんな感じです
# 普通に押したとき
Raw: (199)[3396, 1628, 452, 360, 476, 1224, 452, 356, 476, 1224, 452, 360, 472, 1224, 452, 360, 476, 1224, 452, 356, 480, 1220, 452, 360, 476, 1224, 452, 1220, 452, 360, 476, 1224, 452, 356, 480, 1220, 452, 1224, 452, 1224, 452, 1224, 452, 360, 476, 356, 476, 356, 476, 1224, 452, 360, 476, 1224, 452, 356, 476, 360, 476, 1224, 452, 356, 476, 360, 472, 360, 476, 356, 476, 1224, 456, 1220, 452, 360, 472, 1228, 452, 356, 476, 356, 476, 360, 476, 1220, 456, 356, 476, 356, 476, 360, 476, 1224, 452, 356, 476, 1224, 452, 1224, 452, 4584, 3396, 1624, 452, 360, 480, 1220, 452, 360, 476, 1220, 452, 360, 476, 1224, 448, 360, 480, 1220, 452, 360, 476, 1220, 452, 360, 476, 1224, 452, 1196, 476, 360, 476, 1220, 452, 360, 476, 1220, 456, 1220, 452, 1220, 452, 1220, 452, 360, 476, 364, 472, 360, 480, 1220, 452, 360, 476, 1220, 452, 360, 476, 360, 480, 1220, 452, 360, 476, 360, 476, 360, 476, 360, 476, 1224, 452, 1220, 452, 360, 476, 1220, 452, 360, 476, 360, 476, 364, 476, 1220, 452, 360, 476, 360, 476, 360, 476, 1220, 452, 364, 472, 1224, 452, 1220, 452]

# 長押し
Raw: (399)[3400, 1628, 448, 388, 448, 1224, 448, 388, 452, 1220, 452, 384, 452, 1224, 448, 388, 448, 1224, 452, 384, 452, 1220, 452, 384, 452, 1220, 456, 1220, 452, 384, 452, 1220, 452, 384, 452, 1224, 452, 1220, 448, 1224, 452, 1220, 452, 384, 452, 388, 448, 388, 448, 1224, 452, 384, 452, 1220, 452, 384, 456, 380, 452, 1224, 448, 388, 452, 384, 452, 384, 452, 384, 452, 1220, 452, 1224, 448, 388, 448, 1224, 452, 384, 452, 388, 448, 384, 452, 1220, 452, 388, 452, 384, 452, 384, 452, 1220, 452, 384, 452, 1224, 448, 1220, 456, 4576, 3396, 1628, 448, 388, 452, 1220, 452, 384, 452, 1220, 452, 388, 452, 1220, 452, 384, 452, 1216, 456, 384, 452, 1220, 452, 384, 452, 1224, 452, 1220, 452, 384, 452, 1220, 452, 384, 452, 1224, 448, 1224, 452, 1220, 452, 1220, 452, 384, 452, 388, 448, 388, 448, 1224, 452, 384, 452, 1220, 452, 384, 452, 388, 448, 1224, 452, 384, 452, 384, 452, 384, 452, 384, 452, 1220, 452, 1224, 452, 384, 452, 1220, 452, 384, 456, 380, 452, 384, 452, 1224, 452, 384, 452, 384, 452, 384, 452, 1220, 452, 388, 452, 1220, 448, 1224, 452, 4576, 3396, 1624, 452, 388, 452, 1220, 452, 384, 452, 1220, 452, 384, 452, 1224, 452, 384, 452, 1220, 452, 384, 452, 1224, 448, 384, 452, 1224, 452, 1220, 452, 384, 452, 1220, 452, 388, 448, 1224, 448, 1220, 456, 1220, 452, 1220, 452, 388, 448, 388, 452, 384, 452, 1220, 452, 384, 452, 1220, 452, 384, 452, 388, 448, 1224, 452, 384, 452, 384, 452, 384, 452, 384, 452, 1224, 448, 1224, 452, 380, 456, 1220, 452, 384, 452, 384, 452, 384, 452, 1224, 452, 384, 452, 384, 452, 384, 452, 1220, 452, 388, 448, 1224, 452, 1220, 452, 4576, 3396, 1632, 448, 384, 452, 1224, 452, 380, 452, 1224, 452, 384, 448, 1228, 448, 384, 452, 1224, 452, 384, 448, 1228, 448, 384, 452, 1224, 448, 1228, 452, 380, 452, 1224, 452, 380, 452, 1224, 452, 1224, 452, 1228, 448, 1224, 452, 384, 448, 384, 452, 380, 452, 1224, 452, 384, 452, 1224, 448, 384, 452, 384, 448, 1228, 448, 384, 452, 384, 448, 384, 452, 380, 452, 1224, 452, 1224, 452, 380, 452, 1224, 452, 384, 448, 384, 452, 380, 452, 1224, 452, 384, 452, 380, 452, 384, 448, 1224, 452, 384, 452, 1224, 452, 1224, 452]

試した限りでは、ボタンを短く押しても最低2回はデータを送るようです。 電源ON/OFFは重要と考えて?到達性を上げているのでしょう。 (単にリモコンのボタンが劣化していて自分の環境では2回分 “おささってしまう” だけだったらどうしよう。)

数字ボタン

「1~12」のボタンは、順に

55 5A F1 48 72 4C
55 5A F1 48 F2 44
55 5A F1 48 0A 43
55 5A F1 48 8A 4B
55 5A F1 48 4A 47
55 5A F1 48 CA 4F
55 5A F1 48 2A 41
55 5A F1 48 AA 49
55 5A F1 48 6A 45
55 5A F1 48 EA 4D
55 5A F1 48 1A 42
55 5A F1 48 9A 4A

でした。 少なくともSHARPのテレビは製品の世代が変わっても赤外線リモコンの信号は共通のようで、同じような情報をWeb上から取得できます。 それと今回観測したデータを比較すると一致しており、うまく観測できていそうです。

ほか

ほかのボタンは……多すぎるので割愛します。 全部は見ない、山菜だって根こそぎ取るなって言うじゃないですか。

なお、リモコンに無いボタンでも直接コマンドを送れば機能することもあるようです。 たとえば、次に示すページでは「必ず電源ON」「必ず電源OFF」のコマンドを調査し発見しています(すごい)。

赤外線リモコンのON/OFF専用コードを発見する #ESP32 - Qiita
https://qiita.com/yomori/items/c9a2b2047759d677e07b

実際このコマンドを試してみると、「LC-32H30」でもちゃんと機能していました。

三菱 エアコン

「MSZ-JXV3620」8(リモコン型番YU191)の信号を見ます。

  • 家製協フォーマットと思われる
  • T = 400[us] ~ 450[us]くらい
  • リーダー … 8T ON、4T OFF
  • データ … (主に)144bits
  • トレーラー … 1T ON

データが長い。 このデータには運転モードや設定温度などエアコンを制御するための情報が含まれており、たとえば設定温度だけ変える場合でも毎回フルのデータが送られます。 差分更新にした場合、もし信号を送ったつもりになっていて実際は届いていなかったときに、リモコン側とエアコン本体側で設定温度や運転モードがズレていたというのは嫌ですからね。

今回試した範囲では、リモコンのボタンを押すと複数回データが送られるようです。 「運転開始・終了」「運転切り替え」など重要?なボタンでは

  1. C4 D3 64 80 00 (40bits)を送信
  2. 13msほどsleep
  3. メインデータ (144bits)を送信
  4. 18msほどsleep
  5. 謎のデータ (144bits)を送信

という構成のようで、それ以外のボタンでも

  1. C4 D3 64 80 00 (40bits)を送信
  2. 13msほどsleep
  3. メインデータ (144bits)を送信

となっていました。

C4 D3 64 80 00については謎です。エアコン側の受信モジュールをSleepから起こしている? 「謎のデータ」についても謎で、Web上で似たデータについて調べると「(メインデータと)同一」だったり「(メインデータの)ビットオーダーが反転したもの」だったりすることが多いようですが、今回は当てはまりませんでした。 (この送信については後日試す予定で本当に合っているかは未検証ですが)おそらく「メインデータ」さえ送ればエアコンを制御できるんじゃないか、ということでここではそこにだけ注目します。

データの例としてはこんな感じです。 (以下すべて「風向自動、風左右(エアコン右側に障害物あり設定)、風上下左自動、風上下右自動、ほか設定無し」の状態)

# 運転開始、冷房20度
C4 D3 64 80 00 04 18 20 69 00 7A 00 00 00 18 00 00 BA

# 温度を20.5度に変更
C4 D3 64 80 00 04 18 28 69 03 7A 00 00 00 18 00 00 B4

# ねむり開始(28度)
C4 D3 64 80 00 04 18 30 69 03 7A 00 00 00 1A 00 00 A6

# ねむり解除(20.5度に戻る)
C4 D3 64 80 00 04 18 28 69 03 7A 00 00 00 18 00 00 B4

# 運転終了
C4 D3 64 80 00 00 18 28 69 00 7A 00 00 00 18 00 00 B2

データの構造ついては解析されている方がいて、ほぼ判明しています。 特に下記のページを参考にして、

自分の理解のためデコーダを作ってみると、次のような感じになります。

3decode.py
import sys

def validate_fields(fields):
    for i in range(5, 16+1):
        count = [0] * 8
        for b in filter(lambda x: x[1] == i, fields):
            for j in range(b[3]): count[b[2] + j] += 1
        if count != [1, 1, 1, 1, 1, 1, 1, 1]: return False
    return True

def onoff(x):
    return ["OFF", "ON"][x]

def parse_clock(clock):
    return f'{clock//6:02d}:{(clock%6)*10:02d}'

if __name__ == '__main__':
    data = list(map(lambda x: int(x, 16), sys.argv[1].split(' ')))
    r_data = [None] * 18
    for i in range(18): r_data[i] = int(''.join(list(reversed(list(f'{data[i]:08b}')))),2)
    print(f'Reverse: {" ".join(map(lambda x: f"{x:02X}", r_data))}')

    if data[0] != 0xc4: data, r_data = r_data, data

    print("---")

    print(f'Customer Code: {data[0]:02X}{data[1]:02X}')
    parity = (data[0] >> 4) ^ (data[0] & 0b1111) ^ (data[1] >> 4) ^ (data[1] & 0b1111)
    print(f'Parity:  {data[2]>>4:01X} ({"OK" if data[2]>>4 == parity else "Fail"})')
    print(f'Padding: {data[2]&0b1111:01X}{data[3]:02X}{data[4]:02X} ({"OK" if ((data[2] & 0b1111)<<16 | data[3]<<8 | data[4]) == 0x48000 else "Fail"})')

    print("---")

    # ["Field Name", ByteIndex, BitOffset, BitLen, (formatter)]
    fields = [
        # byte 5
        ["pad50",   5, 3, 5],
        ["Power",   5, 2, 1, onoff],
        ["pad51",   5, 0, 2],
        # byte 6
        ["pad60",   6, 5, 3],
        ["Mode",    6, 2, 3, lambda x: ["UNKNOWN", "Heat","Dry","Cool","Auto","UNKNOWN","UNKNOWN","Fan"][x]],
        ["MoveEye", 6, 1, 1, onoff],
        ["pad61",   6, 0, 1],
        # byte 7
        ["Temp",    7, 4, 4, lambda x: f'{x+16}C'],
        ["HalfDeg", 7, 3, 1, lambda x: ["+0.0C", "+0.5C"][x]],
        ["pad70",   7, 0, 3],
        # byte 8
        ["DryMode", 8, 4, 4, lambda x: ["High", "UNKNOWN", "Middle", "UNKNOWN", "Low", "UNKNOWN", "Cool", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"][x]],
        ["WideVane",8, 0, 4, lambda x: ["UNKNOWN", "LeftMax", "Left", "Middle", "Right", "RightMax", "Wide", "UNKNOWN", "Auto", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"][x]],
        # byte 9
        ["Fan",     9, 5, 3],
        ["Vane",    9, 2, 3, lambda x: ["Auto", "Highest", "High", "Middle", "Low", "Lowest", "Swing", "AutoMove"][x]],
        ["VaneBit/beep?", 9, 1, 1],
        ["FanAuto/beep?", 9, 0, 1, onoff],
        # byte 10
        ["Clock",   10, 0, 8, parse_clock],
        # byte 11
        ["StopClock",   11, 0, 8, parse_clock],
        # byte 12
        ["StartClock",  12, 0, 8, parse_clock],
        # byte 13
        ["Timer",       13, 5, 3],
        ["WeeklyTimer", 13, 4, 1],
        ["pad130",      13, 2, 2],
        ["WindArea",    13, 0, 2, lambda x: ["LeftRight", "Left", "Center"][x]],
        # byte 14
        ["pad140",      14, 3, 5],
        ["EcoCool",     14, 2, 1, onoff],
        ["pad141",      14, 0, 2],
        # byte 15
        ["DirectIndirect", 15, 6, 2],
        ["AbsenseDetect",  15, 5, 1],
        ["pad150",         15, 3, 2],
        ["iSave10C",       15, 2, 1],
        ["pad151",         15, 0, 2],
        # byte 16
        ["pad160",   16, 7, 1],
        ["Natural",  16, 6, 1, onoff],
        ["pad161",   16, 5, 1],
        ["VaneLeft", 16, 2, 3],
        ["pad162",   16, 0, 2],
    ]

    if not validate_fields(fields):
        print('validate_fields failed')
        exit(1)

    for field in sorted(fields, key=lambda x: (x[1], x[2])):
        d = (r_data[field[1]] >> (8-field[2]-field[3])) & (2**field[3] - 1)
        if field[0].startswith("pad"):
            if d == 0: continue
            field.append(lambda x: "UNKNOWN")
        print(f'{field[0]}: 0b{d:0{field[3]}b}{"" if len(field) == 4 else " ("+field[4](d)+")"}')

    print("---")

    s = 0
    for d in r_data[0:-1]: s += d
    print(f'CheckSum: {data[17]:02X}/{r_data[17]:02X} ({"OK" if r_data[17] == s&0xff else "Fail"})')

MSB Firstで見るのが基本のようで、今回の例だとビットオーダーを逆転させる必要があります。 このデコーダの実行例はこんな感じです。

デコーダの実行例(冷房編)
# 運転開始、冷房20度
$ python3 3decode.py "C4 D3 64 80 00 04 18 20 69 00 7A 00 00 00 18 00 00 BA"
Reverse: 23 CB 26 01 00 20 18 04 96 00 5E 00 00 00 18 00 00 5D
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b011 (Cool)
HalfDeg: 0b0 (+0.0C)
Temp: 0b0100 (20C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0110 (Cool)
FanAuto/beep?: 0b0 (OFF)
VaneBit/beep?: 0b0
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: BA/5D (OK)

# 温度を20.5度に変更
$ python3 3decode.py "C4 D3 64 80 00 04 18 28 69 03 7A 00 00 00 18 00 00 B4"
Reverse: 23 CB 26 01 00 20 18 14 96 C0 5E 00 00 00 18 00 00 2D
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b011 (Cool)
HalfDeg: 0b1 (+0.5C) # 設定された
Temp: 0b0100 (20C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0110 (Cool)
FanAuto/beep?: 0b1 (ON) # この辺も変化したが、
VaneBit/beep?: 0b1      # 詳細は謎(最初からONでも良いでは?)
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: B4/2D (OK)

# ねむり開始(28度)
$ python3 3decode.py "C4 D3 64 80 00 04 18 30 69 03 7A 00 00 00 1A 00 00 A6"
Reverse: 23 CB 26 01 00 20 18 0C 96 C0 5E 00 00 00 58 00 00 65
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b011 (Cool)
HalfDeg: 0b0 (+0.0C) # 温度まわりが、
Temp: 0b1100 (28C)   # 変化した
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0110 (Cool)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
pad141: 0b01 (UNKNOWN) # 0b00ではなくなったので登場(ねむり関連?)
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: A6/65 (OK)

# ねむり解除(20.5度に戻る)
$ python3 3decode.py "C4 D3 64 80 00 04 18 28 69 03 7A 00 00 00 18 00 00 B4"
Reverse: 23 CB 26 01 00 20 18 14 96 C0 5E 00 00 00 18 00 00 2D
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b011 (Cool)
HalfDeg: 0b1 (+0.5C)
Temp: 0b0100 (20C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0110 (Cool)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: B4/2D (OK)

# 運転終了
$ python3 3decode.py "C4 D3 64 80 00 00 18 28 69 00 7A 00 00 00 18 00 00 B2"
Reverse: 23 CB 26 01 00 00 18 14 96 00 5E 00 00 00 18 00 00 4D
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b0 (OFF) # Power OFF
MoveEye: 0b0 (OFF)
Mode: 0b011 (Cool)
HalfDeg: 0b1 (+0.5C)
Temp: 0b0100 (20C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0110 (Cool)
FanAuto/beep?: 0b0 (OFF) # この辺も
VaneBit/beep?: 0b0       # OFFになった
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: B2/4D (OK)
デコーダの実行例(暖房編)
# 運転開始、暖房20度
$ python3 3decode.py "C4 D3 64 80 00 04 10 20 09 00 7A 00 00 00 18 00 00 E2"
Reverse: 23 CB 26 01 00 20 08 04 90 00 5E 00 00 00 18 00 00 47
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)
HalfDeg: 0b0 (+0.0C)
Temp: 0b0100 (20C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b0 (OFF)
VaneBit/beep?: 0b0
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: E2/47 (OK)

# 温度を19.5度に変更
$ python3 3decode.py "C4 D3 64 80 00 04 10 C8 09 03 7A 00 00 00 18 00 00 68"
Reverse: 23 CB 26 01 00 20 08 13 90 C0 5E 00 00 00 18 00 00 16
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)
HalfDeg: 0b1 (+0.5C)
Temp: 0b0011 (19C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: 68/16 (OK)

# ねむり開始(18度)
$ python3 3decode.py "C4 D3 64 80 00 04 10 40 09 03 7A 00 00 00 1A 00 00 A2"
Reverse: 23 CB 26 01 00 20 08 02 90 C0 5E 00 00 00 58 00 00 45
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)
HalfDeg: 0b0 (+0.0C)
Temp: 0b0010 (18C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
pad141: 0b01 (UNKNOWN)
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: A2/45 (OK)

# ねむり解除(19.5度に戻る)
$ python3 3decode.py "C4 D3 64 80 00 04 10 C8 09 03 7A 00 00 00 18 00 00 68"
Reverse: 23 CB 26 01 00 20 08 13 90 C0 5E 00 00 00 18 00 00 16
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b1 (ON)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)
HalfDeg: 0b1 (+0.5C)
Temp: 0b0011 (19C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: 68/16 (OK)

# 運転終了
$ python3 3decode.py "C4 D3 64 80 00 00 10 C8 09 00 7A 00 00 00 18 00 00 6C"
Reverse: 23 CB 26 01 00 00 08 13 90 00 5E 00 00 00 18 00 00 36
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b0 (OFF)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)
HalfDeg: 0b1 (+0.5C)
Temp: 0b0011 (19C)
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b0 (OFF)
VaneBit/beep?: 0b0
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
---
CheckSum: 6C/36 (OK)
# お掃除メカ発動
# (あえてビットオーダーを逆転させて入力してみる)
$ python3 3decode.py "23 CB 26 01 00 00 08 13 90 C0 5E 00 00 00 18 00 01 F7"
Reverse: C4 D3 64 80 00 00 10 C8 09 03 7A 00 00 00 18 00 80 EF
---
Customer Code: C4D3
Parity:  6 (OK)
Padding: 48000 (OK)
---
Power: 0b0 (OFF)
MoveEye: 0b0 (OFF)
Mode: 0b001 (Heat)   # この操作は暖房運転終了後に実施した
HalfDeg: 0b1 (+0.5C) # おそらく最後の操作状態が、
Temp: 0b0011 (19C)   #        引き継がれるものと思われる
WideVane: 0b1001 (UNKNOWN)
DryMode: 0b0000 (High)
FanAuto/beep?: 0b1 (ON)
VaneBit/beep?: 0b1
Vane: 0b000 (Auto)
Fan: 0b000
Clock: 0b01011110 (15:40)
StopClock: 0b00000000 (00:00)
StartClock: 0b00000000 (00:00)
WindArea: 0b00 (LeftRight)
WeeklyTimer: 0b0
Timer: 0b000
EcoCool: 0b0 (OFF)
pad140: 0b11000 (UNKNOWN)
iSave10C: 0b0
AbsenseDetect: 0b0
DirectIndirect: 0b00
VaneLeft: 0b000
Natural: 0b0 (OFF)
pad160: 0b1 (UNKNOWN) # ここが追加。これがお掃除メカのフラグ?
---
CheckSum: EF/F7 (OK)

データの構造が分からない箇所も少しあります。 温度設定くらいは正しそうなので、もし自分でデータを作って流す場合は純正リモコンが送っていた正しいはずのデータのうち特定のフィールド(温度など)とチェックサムだけ変えて流すとやりやすいんじゃないでしょうか。 Clockの情報もあるようですがその辺はとりあえず全部ゼロにしてみたり。 crankyoldgit/IRremoteESP8266などのライブラリではイチからデータを作ることも可能9ですが、setRaw()で正しいデータを与え、その後必要に応じてsetTemp()などをしていくイメージです。 ちょうど次のリンクと同様に行えばうまくいきそう……と思います。

エアコンリモコンのHomeKitアクセサリをDIYする (前編:赤外線送出) | DIY Smart Matter
https://diysmartmatter.com/archives/293

Panasonic 壁スイッチ

「とったらリモコン 遅れ消灯機能付 WTC56519W」(リモコン型番WTC56939)の信号を見ます。 ちなみに、同じ「とったらリモコン」でも遅れ消灯は無いただのON/OFFタイプ(WTC56219W)や、似た製品の「照明リモコン受信スイッチ」でも信号が同じは未確認です。

フォーマットなどの情報は次のとおり。

  • 家製協フォーマット
    • WTC56939の仕様書によれば「家電製品協会推奨フォーマット」と表現されている
  • T = 400[us] ~ 450[us]くらい
  • リーダー … 8T ON、4T OFF
  • データ … 48bits
  • トレーラー … 1T ON

データは次のとおりで、リモコンのボタンを押すとすべて30msほどのインターバルを挟んで2回同じデータが送信されます

# 切/入
34 4A 90 40 10 41

# 1分後消灯
34 4A 90 40 10 36

# 10分後消灯
34 4A 90 40 10 C9

# 30分後消灯
34 4A 90 40 10 27

# 60分後消灯
34 4A 90 40 10 AF

# 連続点灯(タイマー取り消し)
34 4A 90 40 10 8D

なお、「連続点灯」は強制ONに相当します。 では強制OFFは?リモコンのボタンには無いですが探したいですよね? ということでSHARPテレビのところで記載した「ON/OFF専用コード」の調査を参考に、データ構成推察すると……こんな感じと思われます。

カスタマーコードパリティコードパリティ
34 4A9 (0x3 ^ 0x4 ^ 0x4 ^ 0xA)0 40 10 41 (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0x4)
34 4A90 40 10 36 (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0x3)
34 4A90 40 10 C9 (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0xC)
34 4A90 40 10 27 (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0x2)
34 4A90 40 10 AF (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0xA)
34 4A90 40 10 8D (0x0 ^ 0x4 ^ 0x0 ^ 0x1 ^ 0x0 ^ 0x8)

コードを見ると末尾4bit分しか変わっていません。 これは容易に総当りできそうです。すでに6個は既知なので残り10個試すだけ。

送信についてはあまり扱わないつもりでしたが、気になったので試すとこのような挙動になっていました。

番号(カッコ内は既知)データ照明ON時の挙動照明OFF時の挙動
034 4A 90 40 10 05消灯する変化なし
134 4A 90 40 10 14変化なし(※)点灯する(※)
2(30分後消灯)34 4A 90 40 10 2730分後に消灯する点灯し30分後に消灯する
3(1分後消灯)34 4A 90 40 10 361分後に消灯する点灯し1分後に消灯する
4(切/入)34 4A 90 40 10 41消灯する点灯する
534 4A 90 40 10 50変化なし(※)点灯する(※)
634 4A 90 40 10 63変化なし(※)点灯する(※)
734 4A 90 40 10 72変化なし(※)変化なし(※)
8(連続点灯)34 4A 90 40 10 8D変化なし点灯する
934 4A 90 40 10 9C変化なし(※)点灯する(※)
10(60分後消灯)34 4A 90 40 10 AF60分後に消灯する点灯し60分後に消灯する
1134 4A 90 40 10 BE変化なし(※)変化なし(※)
12(10分後消灯)34 4A 90 40 10 C910分後に消灯する点灯し10分後に消灯する
1334 4A 90 40 10 D8変化なし(※)点灯する(※)
1434 4A 90 40 10 EB変化なし(※)点灯する(※)
1534 4A 90 40 10 FA変化なし(※)変化なし(※)

※: 一定時間後の挙動は未確認。もしかすると「xx分後消灯」のような挙動はあり得る。

番号0の34 4A 90 40 10 05が強制OFFに相当しそうですね。 少し前に「とったらリモコンではトグル動作しかない」と書いたのを直さないと……。

日立 照明

シーリングライト「LEC-AH1210PH」(リモコン型番IR-A07HRT)の信号を見ます。

  • 家製協フォーマットと思われる
  • T = 400[us] ~ 450[us]くらい
  • リーダー … 8T ON、4T OFF
  • データ … 88bits
  • トレーラー … 1T ON

データはこんな感じです。

# リラックス
80 08 0C 0A F5 00 FF 44 BB 4F B0

# 保安灯
80 08 0C 0A F5 00 FF 90 6F 43 BC

# 消灯
80 08 0C 0A F5 00 FF C0 3F 43 BC

若干データが長めなので、もしかするとエアコンのようにステート全部、たとえば調光や調色のデータなども含まれているのかも知れません。 が、個人的にはここまで分かれば満足なのでここで終わりです。

IRIS OHYAMA 照明

シーリングライト「CL8DL-5.0」(リモコン型番R5.0-DL)の信号を見ます。

この機器ではどうやら独自フォーマットを使っているようです。 ただ、何となく既知のフォーマットと似ており、仕様を推測すると……

  • T = 450[us] ~ 550[us]くらい
  • リーダー … 4T ON、2T OFF、11T ON、2T OFF
  • データ … 40bits
  • トレーラー … 1T ON

と思われます。 Rawデータはこんな感じです。

# ON/常夜灯/OFF
Raw: (85)[2076, 948, 5548, 964, 1556, 456, 1556, 452, 560, 460, 560, 460, 560, 464, 556, 464, 580, 440, 556, 464, 1556, 452, 560, 464, 560, 460, 560, 460, 560, 460, 560, 464, 580, 440, 1556, 456, 556, 464, 1556, 456, 556, 464, 556, 460, 560, 464, 560, 460, 580, 440, 560, 460, 560, 464, 556, 460, 560, 464, 556, 464, 556, 464, 560, 460, 580, 440, 560, 460, 560, 464, 1556, 452, 560, 464, 1556, 452, 1556, 452, 560, 464, 1556, 456, 1556, 452, 556, ]

# 明るく
Raw: (85)[2056, 948, 5552, 960, 1556, 456, 1556, 456, 556, 464, 560, 460, 560, 464, 556, 464, 580, 440, 560, 464, 1556, 452, 560, 464, 556, 464, 556, 464, 560, 460, 560, 464, 580, 440, 1556, 456, 556, 464, 556, 464, 560, 460, 560, 464, 556, 464, 560, 460, 1556, 456, 560, 460, 560, 464, 556, 464, 556, 464, 556, 464, 560, 460, 560, 464, 580, 440, 560, 460, 560, 460, 560, 464, 556, 464, 1556, 456, 1556, 456, 556, 464, 580, 444, 1552, 456, 556, ]

# 暗く
Raw: (85)[2056, 948, 5552, 960, 1560, 452, 1560, 452, 560, 464, 556, 464, 556, 464, 560, 464, 580, 440, 556, 464, 1556, 456, 560, 460, 564, 460, 556, 464, 556, 464, 560, 460, 580, 444, 1556, 456, 556, 464, 556, 464, 560, 460, 560, 464, 556, 464, 556, 464, 580, 440, 1560, 452, 560, 460, 560, 464, 556, 464, 556, 464, 560, 460, 560, 464, 580, 440, 556, 464, 560, 460, 560, 464, 556, 464, 1556, 456, 1556, 456, 556, 464, 1560, 452, 556, 464, 556, ]

# 白色
Raw: (85)[2056, 948, 5556, 956, 1556, 456, 1560, 452, 560, 464, 556, 464, 556, 464, 560, 460, 584, 440, 556, 464, 1556, 456, 560, 464, 556, 464, 556, 464, 560, 464, 556, 464, 580, 444, 1556, 452, 560, 464, 556, 464, 560, 460, 560, 464, 556, 464, 1556, 456, 580, 440, 560, 464, 556, 464, 560, 460, 560, 460, 560, 464, 556, 464, 560, 460, 580, 444, 556, 464, 556, 464, 556, 464, 560, 460, 1560, 456, 1556, 456, 1556, 456, 1556, 456, 1556, 456, 552, ]

# 暖色
Raw: (85)[2056, 948, 5552, 964, 1556, 456, 1556, 452, 560, 464, 556, 464, 556, 464, 560, 460, 584, 440, 556, 464, 1556, 456, 556, 464, 560, 460, 560, 464, 556, 464, 556, 464, 580, 440, 1560, 452, 560, 464, 556, 464, 556, 464, 560, 464, 1556, 452, 560, 464, 580, 440, 560, 460, 560, 464, 556, 464, 560, 460, 560, 460, 560, 464, 556, 464, 580, 440, 560, 460, 560, 464, 556, 464, 560, 460, 1560, 452, 560, 440, 576, 468, 1556, 456, 1556, 456, 552, ]

PPMではありそうで、0は「1T ON、1T OFF」、1は「3T ON、1T OFF」と推測します。 これを基にデコードしてみると……

# ON/常夜灯/OFF
--- IRIS DECODE ---
LEN 85
MAX 5548
MIN 440
LEADER 2076 948 5548 964
STOP 556
BIT LEN 40
DATA ===== C0 81 40 00 5B =====

# 明るく
--- IRIS DECODE ---
LEN 85
MAX 5552
MIN 440
LEADER 2056 948 5552 960
STOP 556
BIT LEN 40
DATA ===== C0 81 02 00 19 =====

# 暗く
--- IRIS DECODE ---
LEN 85
MAX 5552
MIN 440
LEADER 2056 948 5552 960
STOP 556
BIT LEN 40
DATA ===== C0 81 01 00 1A =====

# 白色
--- IRIS DECODE ---
LEN 85
MAX 5556
MIN 440
LEADER 2056 948 5556 956
STOP 552
BIT LEN 40
DATA ===== C0 81 04 00 1F =====

# 暖色
--- IRIS DECODE ---
LEN 85
MAX 5552
MIN 440
LEADER 2056 948 5552 964
STOP 552
BIT LEN 40
DATA ===== C0 81 08 00 13 =====

となりました。

おぼろげながら3バイト目にボタン番号のような浮かんできませんか?

ボタン番号 (HEX)番号 (BIN)
ON/常夜灯/OFF400100 0000
暖色080000 1000
白色040000 0100
明るく020000 0010
暗く010000 0001

特定のビットと機能が結びついているような、特に電源制御系は上位4bitにありそうな気がします。 末尾バイトはチェックサムと思われ、計算方法は自信ないですが3バイト目と0x1BとのXORを取るとそれっぽい……。

ただ、もしかしたら強制ONや強制OFFができるかも?と思い試してみましたが、うまくいきません。 点灯状態で3バイト目の上位4bitを0b0001にすると、一瞬 “ほわんほわん” するほかは特に変化なしです。 コマンドを探しきれていなかったりチェックサムが間違っていたりするかも知れないですし、そもそもそんな機能は無いのかも知れません。

なお、ほわんほわんは上位4bit目が1なら何でも良い、つまり0bxxx1なら同様の動きをします。 また「ON/常夜灯/OFF」の0b0100も上位2bit目が1なら他は何でも良く、「特定のビットと機能が結びついている」というのは合っていそうでした10

TOTO ウォシュレット

「TCF984#NW1」11(リモコン型番TCM4195)の信号を見ます。

これも独自フォーマットのようです。 NECフォーマットや家製協フォーマットに近く、仕様はこんな感じと思われます。

  • T = 500[us] ~ 600[us]くらい
  • リーダー … 12T ON、6T OFF
  • データ … 39bits
  • トレーラー … 1T ON

Rawデータはこんな感じです。

# フタ開閉
Raw: (163)[5956, 2944, 580, 520, 576, 1612, 608, 520, 576, 520, 576, 520, 580, 540, 580, 516, 580, 516, 580, 516, 580, 544, 580, 516, 580, 1612, 580, 544, 580, 516, 580, 516, 580, 516, 632, 492, 580, 512, 584, 516, 580, 516, 604, 520, 580, 516, 580, 516, 580, 544, 576, 520, 576, 520, 576, 520, 604, 1616, 576, 1616, 604, 1612, 580, 520, 580, 516, 600, 520, 604, 492, 580, 516, 580, 1640, 580, 1612, 580, 1640, 580, 516, 580, 38008, 5980, 2896, 604, 516, 580, 1612, 580, 520, 604, 516, 580, 516, 580, 516, 576, 548, 580, 516, 580, 516, 604, 492, 580, 544, 580, 1612, 580, 516, 604, 520, 580, 516, 580, 516, 580, 516, 632, 492, 604, 492, 604, 492, 576, 544, 580, 520, 576, 520, 576, 520, 576, 544, 580, 516, 584, 516, 604, 1612, 580, 1612, 580, 1640, 576, 520, 580, 516, 580, 520, 604, 516, 580, 516, 580, 1640, 580, 1612, 580, 1640, 580, 516, 580, ]

# 便座開閉
Raw: (163)[5984, 2920, 604, 488, 608, 1588, 632, 488, 608, 488, 612, 488, 604, 492, 632, 488, 608, 488, 608, 488, 608, 516, 608, 488, 608, 1584, 608, 516, 608, 488, 608, 488, 608, 488, 636, 488, 608, 488, 608, 488, 608, 488, 632, 492, 608, 488, 608, 488, 608, 1612, 604, 1588, 608, 1612, 604, 1588, 608, 516, 604, 1588, 604, 1612, 608, 488, 608, 1588, 632, 1584, 608, 1612, 608, 1584, 608, 488, 608, 1612, 608, 1584, 636, 488, 608, 31348, 5984, 2892, 632, 488, 608, 1584, 608, 492, 632, 488, 608, 488, 608, 488, 608, 516, 608, 488, 608, 488, 608, 488, 608, 516, 604, 1588, 608, 488, 632, 492, 604, 492, 604, 492, 604, 492, 632, 492, 604, 488, 608, 492, 608, 512, 608, 488, 608, 492, 604, 1612, 608, 1584, 608, 1612, 608, 1584, 608, 492, 632, 1584, 608, 1584, 632, 492, 608, 1584, 608, 1616, 600, 1588, 608, 1612, 604, 492, 604, 1616, 604, 1588, 604, 492, 632, ]

データが2回、30ms~40msほどの間隔を挟んで送られています。 データの表現方法はNECフォーマットや家製協フォーマットと同様で、バイト列に直すとこんな感じです。(40bitsで表現。実際のデータは39bitsなので末尾1bitは0で埋めている)

# フタ開閉
40 10 00 1C 1C

# 便座開閉
40 10 01 ED EC

末尾バイトはその前の2バイトのXOR(の先頭7bit分かも)、つまり「0x00 ^ 0x1C -> 0x1C」だったり「0x01 ^ 0xED -> 0xEC」だったりしそうです。 0x00とか0x01とのXOR取ってもほとんど意味ないので本当かは微妙ですが……次のページのように先行して調査していた方がいてその情報と比べると合っている気もします。

ところで、ウォシュレットの信号を見て嬉しいんでしょうか? まぁ……嬉しいこともあるかも知れません。 以前泊まったホテルでは、ハードウェア的にはリモコンからフタが開閉できると思われる(手で開閉するとモーターが入っていそうな抵抗を感じる)ものの、肝心なリモコンは簡易的なもので開閉ボタンが無い!ということがありました。 そんな場合でも、自前で開閉の信号を送れたら自分の手を汚さずに臭い物にフタをできるんじゃないでしょうか。 本当にできるか、そもそもそのホテルでは本当にハードウェア側は対応していたか?かはそのホテルが閉業してしまったため確認できません。

まとめ

身近にある赤外線リモコンの信号を見ました。

赤外線リモコンについては学習リモコンが市販されており、わざわざ自分で信号を見る必要性は薄いかも知れません。 ただ、今回見たおかげでフォーマットに対する理解を深められてよかった。 いまだったらPP4Cも受信できるかも知れない。

Footnotes

  1. 身近じゃなかったやつは見れなかったので(電子棚札の解析 ;-)#赤外線通信の受信

  2. 参考1: Apple Remote を調べる:放課後マイコンクラブ:SSブログ、参考2: AppleRemoteの送信コードの謎: new_western_elec

  3. 【ビルトインIH】A・Bシリーズの換気連動(赤外線)コードの切り換えについて。(動画説明あり) - IH調理器/IHクッキングヒーター - Panasonic

  4. 参考1: 飽和回復時間 - ikkei blog、参考2: 第2章 トランジスタをスイッチとして使う

  5. Carrier duty cycle issues for JVC devices · Arduino-IRremote/Arduino-IRremote · Discussion #1191

  6. Duty cycle of 38KHz IR carrier - Page 1

  7. 38kHzか?36.7kHzか?見分けたかったところですが、周期は1[us]ほどしか差がなく判別が難しい。

  8. 深夜でも、「ねむり」を設定していても、お掃除メカ動かすのやめっ……やめt……(いまでは自動掃除OFFにした)

  9. https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino

  10. 0b0101については「ON/常夜灯/OFF」側が優先されるようでした。

  11. 「取替機能部」らしい。ウォシュレット一体型でもこの部分だけ変えられるんですね。