🐶

ペットのための暖房システムをつくったよ

2022/11/03に公開
2

犬を飼っているのですが、寒い日は電気毛布で暖をとっています。
ちょっとした組み合わせで自動化できそうです。
室内温度と連動させて電気毛布をオンオフするよう作ってみました。

やったこと

今回は、nature remoとwifiタップの組み合わせで行いました。

  1. 1時間毎に以下を実施する
  2. nature remoから温度を取得する
  3. 温度からタップを制御
  • 温度が10度未満なら、wifiタップを通電する
  • 温度が10度以上なら、wifiタップを切る
  1. wifiタップには、電気毛布が接続されている

機材一覧

no 部品名 個数 備考
1 ラズベリーパイ 1 今回は、4Bを使用
2 Nature Remo 1 オフィシャルサイト
3 WiFiスマートプラグ Meross 1 Amazon

環境

開発環境

  • ラズベリーパイ
    • Linux 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux
  • Python
    • Python 3.9.2 (default, Feb 28 2021, 17:03:44)

ラズベリーパイの設定

特になし

モジュールのインストール

pip

Pythonに関するモジュールをインストールします。

$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install requests

作業パス

作業は、下記のパスで行います。(自動実行時に使用)

(env) $ pwd
/home/pi/nukunuku

手順

以下を記載します。

  • 温度の取得
  • スマートプラグの制御
  • 自動実行

温度の取得

Nature Remo Cloud APIを使用することで、Nature Remoの持つセンサー情報を取得できます。

以下が公式資料となります。

https://developer.nature.global/

https://swagger.nature.global/

Tokenの取得

下記のページから、APIを利用するのに必要なTokenを取得します。

https://home.nature.global/

デバイス情報を取得

上記で取得したTokenを{token}の部分に指定し、下記のコマンドを実行します。

$ curl -X GET "https://api.nature.global/1/devices" -H "Authorization: Bearer {token}" | jq .

正常に実施されている場合、保有しているNature Remoの情報が取得できます。

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1104  100  1104    0     0    769      0  0:00:01  0:00:01 --:--:--   769
[
  {
    "name": "mini2", <= 1台目のremo
    略
  },
  {
    "name": "Remo", <= 2台目のremo
    略
    "newest_events": {
      "hu": {
        "val": 51,  <= 湿度センサー
        "created_at": "2022-10-28T09:48:25Z"
      },
      "il": {
        "val": 2,  <= 照度センサー
        "created_at": "2022-10-28T13:16:41Z"
      },
      "mo": {
        "val": 1,  <= モーションセンサー
        "created_at": "2022-10-28T13:47:17Z"
      },
      "te": {
        "val": 18.4, <= 温度センサー
        "created_at": "2022-10-28T13:26:03Z"
      }
    }
  }
]

私の家には、2つのremoがあるため、複数表示されます。
今回、ほしいデータは、温度センサーのデータとなります。

Pythonコードから取得

上記の例の場合、name ->"Remo"の"te" -> valの値を取得します。

remo.py
import requests
import json

# REMO
REMO_TOKEN = "token" # <-自分の環境に合わせる
REMO_NAME = 'Remo' # <-自分の環境に合わせる

def get_tempture():
    headers = {
        'Authorization': f'Bearer {REMO_TOKEN}',
    }
    response = requests.get('https://api.nature.global/1/devices', headers=headers)

    jsonData = response.json()
    for data in jsonData:
        if data['name'] == REMO_NAME:
            return int(data['newest_events']['te']['val'])
    return (-1)


if __name__ == '__main__':
    temp = get_tempture()
    print(temp)
(env) $ python remo.py
18

これで室内の温度を取得することができました。

スマートプラグの制御

Merossスマートプラグは、IFTTTの対応が終了します。
そのため、スマホからMerossスマートプラグへのパケットを覗いて、制御することにしました。

パケットの解析

下記の記事を参考に実施しました。(パケットキャプチャツール:Charlesを使用)

https://qiita.com/narikei/items/4d32e0050343b0c2bd65

https://zenn.dev/ttskch/articles/95cfa30390241c

↑の記事の作業中に1点詰まりました。(解決はしていない)

Merossのスマートプラグは、7台所有しているのですが、
そのうち2台制御することができませんでした。

以下は推測です。

no HTTP経由で制御 パケットキャプチャ 備考
1/2 NG OK 2019年ぐらいに購入?
3 OK OK 2021年に購入
4/5/6/7 OK OK 2022年に購入

購入時期によって、制御できるものと制御できないものがあるように思えます。

HTTP経由で制御のNGは、レスポンスとしてエラーが返ってくるわけでなく、
TCPのセッションを張るところでこけているため、messageIdやsignなどのパラメータが間違っているというわけではないようです。
そもそも公開されていない仕様なので、早々に見切りをつけましょう。

PythonコードからACタップの制御

ACのON/OFFをします。

meross.py
import requests
import json
import time

MEROSS_IPADDR = "192.168.xx.xx" # <- 自身の環境に合わせる


def ac_onoff(onf):
    url = f"http://{MEROSS_IPADDR}/config"
    head = {"Content-Type": "application/json"}
    data = {
        "payload": {
            "togglex": {
                "onoff": onf,
                "channel": 0
            }
        },
        "header": {
            "messageId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # <- 自身の環境に合わせる(自身でパケット取得)
            "method": "SET",
            "from": f"http:\/\/{MEROSS_IPADDR}\/config",
            "payloadVersion": 1,
            "namespace": "Appliance.Control.ToggleX",
            "uuid": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # <- 自身の環境に合わせる(自身でパケット取得)
            "sign": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # <- 自身の環境に合わせる(自身でパケット取得)
            "triggerSrc": "iOSLocal",
            "timestamp": 9876543210 # <- 自身の環境に合わせる(自身でパケット取得)
        }
    }
    r = requests.post(url, headers=head, data=json.dumps(data))
    print(r)
    return


if __name__ == '__main__':
    ac_onoff(0)
    time.sleep(5)
    ac_onoff(1)
    time.sleep(1)
(env) $ python meross.py
# ac tap - off
# 5秒経過
# ac tap - on

電源のON/OFFができました。

自動実行

あとは、条件をいれて自動実行するだけです。

コード

nuku.py
import requests
import json
import syslog

# REMO
REMO_TOKEN = "token" # <-自分の環境に合わせる
REMO_NAME = 'Remo' # <-自分の環境に合わせる

# MEROSS
MEROSS_IPADDR = "192.168.xx.xx" # <- 自身の環境に合わせる
MEROSS_messageId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"# <- 自身の環境に合わせる(自身でパケット取得)
MEROSS_uuid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"# <- 自身の環境に合わせる(自身でパケット取得)
MEROSS_sign = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"# <- 自身の環境に合わせる(自身でパケット取得)
MEROSS_triggerSrc = "iOSLocal"
MEROSS_timestamp = 9876543210 # <- 自身の環境に合わせる(自身でパケット取得)

# SYTEM
TEMPTURE_TH = 10 # 温度閾値

def get_tempture():
    headers = {
        'Authorization': f'Bearer {REMO_TOKEN}',
    }
    response = requests.get('https://api.nature.global/1/devices', headers=headers)

    jsonData = response.json()
    for data in jsonData:
        if data['name'] == REMO_NAME:
            return int(data['newest_events']['te']['val'])
    return (-1)


def ac_onoff(onf):
    url = f"http://{MEROSS_IPADDR}/config"
    head = {"Content-Type": "application/json"}
    data = {
        "payload": {
            "togglex": {
                "onoff": onf,
                "channel": 0
            }
        },
        "header": {
            "messageId": MEROSS_messageId,
            "method": "SET",
            "from": f"http:\/\/{MEROSS_IPADDR}\/config",
            "payloadVersion": 1,
            "namespace": "Appliance.Control.ToggleX",
            "uuid": MEROSS_uuid,
            "sign": MEROSS_sign,
            "triggerSrc": "iOSLocal",
            "timestamp": MEROSS_timestamp
        }
    }
    r = requests.post(url, headers=head, data=json.dumps(data))
    print(r)
    print(r.text)
    syslog.syslog(syslog.LOG_INFO, r.text)
    r.close()
    return


if __name__ == '__main__':
    syslog.syslog("run - nukunuku")
    temp = get_tempture()
    syslog.syslog(syslog.LOG_INFO, f"temperature:{temp}")
    if temp > TEMPTURE_TH:
        ac_onoff(0)
    else:
        ac_onoff(1)

crontab

1時間に1回の実行のため、下記となります。

(env) $ crontab -l
0 * * * * /home/pi/nukunuku/env/bin/python /home/pi/nukunuku/nuku.py

さいごに

今回は、所有している製品の組み合わせで実現しました。
赤外線コンセントを使えば、そもそもコードも不要でよりシンプルに実現できそうです。
久しぶりに記事を書きましたね。

GitHubで編集を提案

Discussion

NotFoundsNotFounds

興味深い投稿楽しく拝読させていただきました。
ひとつ気になったのですが、スマートプラグなどを用いて電熱器などの電気用具を遠隔操作することは法に触れる可能性があるという認識です。(自分は法律の専門家ではないのであくまでも自分の認識です。)

経済産業省が公開している下記ガイドラインを読む限りは危険な部類になるかと思いますので一度ご確認していただいたほうが良いかなと思います。
https://www.meti.go.jp/product_safety/consumer/system/iot.html

また、過去に似たような記事を見かけたのでこちらも合わせて添付しておきます。
https://k-tai.watch.impress.co.jp/docs/interview/1390416.html

kotaprojkotaproj

コメントありがとうございます。

記事を読ませていただき、認識不足を痛感しました。
注意喚起をするために、記事内に追記しました。

別の方法で暖をとれるよう検討したいと思います。