Nature Remoに存在しないボタンを登録する

我が家の照明は、リモコンで操作できる。 なので、Nature Remoからももちろん操作できるのだが、リモコンにあるボタンはON/OFFを切り替えるボタンしかない。 そのため、明示的にONにしたり、OFFにしたりすることはできない。 しかし、同じメーカーの他の照明リモコンを見てみるとONのボタンとOFFのボタンが存在している。 これは推測だが、おそらくプロトコル上、実装上存在しているが、廉価なモデルのリモコンのため省略されていると考えられる。 そこで、Nature RemoのAPIを駆使し、物理的に存在しないが、プロトコル上、実装上存在していると考えられるONボタンとOFFボタンを調査し、Nature Remoから照明のONとOFFを操作できるようにする。



f:id:miettal:20190112150510j:plain
MARUZEN ELECTRIC CO., LTD. MD3

Nature RemoのIPアドレスを調べる

IPアドレスがわからないと、Local APIを叩けないので調べる。

まず、Nature Remoと同じネットワーク(LAN)につなぐ。

つぎに、mDNSでサービスタイプから、インスタンス名を引く。

$ dns-sd -B _remo._tcp
Browsing for _remo._tcp
DATE: ---Sat 12 Jan 2019---
13:33:50.261 ...STARTING...
Timestamp A/R Flags if Domain Service Type Instance Name
13:33:50.413 Add 3 5 local. _remo._tcp. Remo-4A8BDD
13:33:50.413 Add 2 5 local. _remo._tcp. Remo-9086AB

リビングルームとダイニングルームのNature Remoが見つけられる。

最後に、mDNSでインスタンス名からIPv4アドレスを引く。

$ dns-sd -G v4 Remo-4A8BDD.local 
DATE: ---Sat 12 Jan 2019---
13:40:19.941  ...STARTING...
Timestamp     A/R    Flags if Hostname                               Address                                      
TTL
13:40:19.942  Add        2  5 Remo-4A8BDD.local.                     192.168.0.18                                 120

これでリビングルームのNature RemoのIPアドレスがわかった。

受信した信号を見る

Nature Remoに対して、照明リモコンのON/OFFボタンを押して、赤外線信号を送信する。

Nature Remo Local APIのmessage APIで、Nature Remoが受信した信号を見る。

$ curl -s -X GET 'http://192.168.0.4/messages' -H 'X-Requested-With: curl'
{"format":"us","freq":37,"data":[4675,2627,564,959,572,1850,563,1863,562,958,564,1860,571,1849,566,956,575,949,564,959,571,1849,574,1850,575,952,571,1850,570,1854,572,1849,564,961,571,1847,568,1859,568,951,566,955,573,951,565,955,564,965,562,1854,576,948,567,956,565,957,572,950,571,951,571,953,570,950,572,945,572,16480,4670,2633,565,959,562,1860,572,1848,574,952,571,1849,573,1851,573,949,573,950,564,956,575,1849,576,1850,562,959,575,1848,572,1853,562,1857,566,959,572,1848,567,1859,570,951,571,953,563,956,565,959,570,951,567,1858,571,949,573,951,564,957,572,949,575,949,564,955,574,948,574,944,566,16484,4682,2624,571,951,564,1859,564,1858,572,952,571,1849,569,1855,573,951,571,949,566,960,562,1857,577,1849,570,951,565,1861,569,1850,574,1849,576,946,575,1849,573,1850,571,953,565,955,573,950,574,947,575,946,574,1852,570,953,570,949,566,959,563,956,573,952,563,959,564,960,569,943,574]}

data配列の各要素は、赤外線ONの期間、OFFの期間、ONの期間、OFFの期間、、、、を表している。 厳密には、これは38kHzの変調をデコードしたあとの結果である。実際にはONの期間は38kHzの変調信号になっている。

プロトコルの詳細は書きを参照されたい。

elm-chan.org

そして、この結果を、ぱっと見た感じ、

NECフォーマット
T=560us
リーダーコード: ON:4T, OFF:8T,
ビット0: ON: 1T, 1.7T
ビット1: ON: 1T, 3.4T

であることがわかる。

プログラムに噛ませて赤外線信号を16進4バイトのデータにデコードする。

$ cat decode.py
import sys
import json

obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)

bit_array = [int(not x < 1100) for x in obj['data'] if 900 < x < 2000]

byte_array = [sum([x<<i for (i, x) in enumerate(x)]) for x in zip(*[iter(bit_array)]*8)]
print(' '.join(["{:02x}".format(x) for x in byte_array]))

$ curl -s -X GET 'http://192.168.0.4/messages' -H 'X-Requested-With: curl' | python decode.py
36 76 83 00 36 76 83 00 36 76 83 00

これで、データがわかった。これをすべてのボタンに対して行い、ボタンに対応するデータの一覧を得る。

(ch1)

Button Data
豆球 36 76 48 00
オフタイマー60 36 76 80 00
オフタイマー30 36 76 82 00
ON/OFF 36 76 84 00
明るく 36 76 86 00
暗く 36 76 88 00

(ch2)

Button Data
豆球 36 76 47 00
オフタイマー60 36 76 8f 00
オフタイマー30 36 76 81 00
ON/OFF 36 76 83 00
明るく 36 76 85 00
暗く 36 76 87 00

これらの結果から、おそらく3バイト目が照明の各ボタンの操作に対応していると推察できる。 これから、この3バイト目を書き換えて、赤外線を送信し、ONとOFFに対応するデータを探す。

受信した信号を見る

プログラムに噛ませて16進4バイトのデータを赤外線信号にデコードする。 そして、Nature Remo Local APIのmessage APIで、照明に対して赤外線を送信する。

$ cat encode.py
import sys
import json

byte_array = [int(x, 16) for x in sys.stdin.read().split(' ')]

data = [4668,2636]
for x in byte_array:
    for i in range(8):
        b = (x>>i)&1
        if b == 1:
            data += [562, 1877]
        else:
            data += [562, 951]
data += [548, 16504]

obj = {
    'format': 'us',
    'freq': 37,
    'data': data,
}

obj_txt = json.dumps(obj)
sys.stdout.write(obj_txt)

$ echo "36 76 83 00" | python encode.py | curl -X POST 'http://192.168.0.4/messages' -H 'X-Requested-With: curl' -d @-

無事照明が点いた(消えていたのでON/OFFボタンで点灯した)。

3バイト目を書き換えてみて、動作するボタンと、動作内容の一覧を得る。

(ch1)

Button Data
ON 36 76 42 00
OFF 36 76 4a 00

(ch2)

Button Data
ON 36 76 41 00
OFF 36 76 49 00

41がON、49がOFFに対応していることがわかった。 これから、Nature Remo Cloud APIを使って、Nature Remoにボタンを登録する。

信号を登録する

まず、Nature Remo Global APIのアクセス用のトークンを生成し、取得する。以降トークンはXXXX(伏せ字)と表す。

Home

次に、Nature Remo Global APIののappliances APIで、機器の一覧を見る。

$ curl -s -X GET "https://api.nature.global/1/appliances" -H "Authorization: Bearer XXXX"  | python -mjson.tool

(snip)
    {
        "id": "YYYY",
        "device": {
            "name": "Living    Room",
            "id": "XXXX",
            (snip)
        },
        "model": null,
        "type": "IR",
        "nickname": "Living Room Light",
        "image": "ico_light",
        "settings": null,
        "aircon": null,
        "signals": [
            (snip)
        ]
    },
(snip)

機器のIDがわかる。以降機器のIDはYYYY(伏せ字)とする。

最後に、Nature Remo Global APIののsignals APIで、赤外線信号を登録する。

$ echo "36 76 41 00" | python encode.py | urlencode
 %7B%22format%22%3A%20%22us%22%2C%20%22freq%22%3A%2037%2C%20%22data%22...5D%7D
$ curl -s -X POST "https://api.nature.global/1/appliances/YYYY/signals" -H "Authorization: Bearer XXXX" -d "message=ZZZZ&image=ico_on&name=ON"

{"id":"XXXX","name":"ON","image":"ico_on"}

$ echo "36 76 49 00" | python encode.py | urlencode
%7B%22format%22%3A%20%22us%22%2C%20%22freq%22%3A%2037%2C%20%22data%22...5D%7D
$ curl -s -X POST "https://api.nature.global/1/appliances/YYYY/signals" -H "Authorization: Bearer XXXX" -d "message=ZZZZ&image=ico_off&name=OFF"
{"id":"XXXX","name":"OFF","image":"ico_off"}

無事、ONのボタンと、OFFのボタンが登録された。

f:id:miettal:20190112150706p:plain
Nature Remo App

ぱちぱちぱち