2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Alexaからスマートホーム家電を時間差をつけて制御する (その2) 〜 Slack経由で家電のONタイマーを設定する.

Last updated at Posted at 2019-02-16

やりたいこと

自宅のスマートホーム化計画を進めていますが、Alexaからスマート家電を操作する際の自由度が思いのほか低いなと感じました. 例えば、スマートライトであるHueの単純なON/OFFはアレクサから操作できるが、起床ルーチン (6:00にセットすると5:45からライトがだんだん明るくなる、など) はAlexaから設定できない、など. 私が具体的にやりたかったのは、例えば、

  1. Amazon Echoに「アレクサ、明日の朝7:00に起こして」とお願いする.
  2. Philips Hueを6:45から7:00にかけて徐々に明るくする.
  3. Nature Remo経由で、冷房/暖房を6:30にONにする.
  4. Amazon Echoのアラームを7:00に設定する.

というもの. 起床時間に対して前もって各家電をONにする、というのが主な目的です. このうち、4. 以外は実現の目処が立ったので作業ログを残します (Alexaカスタムスキル経由でのアラーム設定は現状許可されていないようです). ちなみに、Alexaの定型ルーチンでも似たようなことができるはずですが、以下のような制約が出ると考え、採用しませんでした

  • 声 (アレクサ、〜時に起こして) で時刻を設定することができない (Alexa App経由で時刻を変更する必要がある).
  • Hueの起床ルーチンを設定できない (指定の時刻になったらいきなり明るくなる).
  • 起床時間のXX分前から冷房/暖房をつける、という設定ができない. Alexa Appで起床時刻のXX分前から定型アクションを開始し、冷房/暖房をつけた後、定型アクションをXX分待機させ、その後Hueライトをつける、とすれば似たような挙動にはなるが、起床時刻のXX分前の時刻を計算して設定する必要があり、面倒.

作るものの全体像

20190201_SmartHome_WakeUpRoutine-4.png

これの宅内サーバの部分を作ります. (その1はこちら)

HueライトのAPI初期設定

参考

LAN内のHue BridgeのIPアドレスを取得する.

ブラウザで https://discovery.meethue.com にアクセスすると、IPアドレス情報を含むJSONが得られる.

APIをいじってみるためにCLIP API Debuggerにアクセスする.

ブラウザで https://[上で取得したIP]/debug/clip.html にアクセスする.

スクリーンショット 2019-02-01 18.28.51.png

ユーザを作成する.

  • URL:/apiMessage Body:{"devicetype":"[your-device-name]"}、を入力してPOSTする. すると、"description": "link button not pressed"でエラーが返ってくる.
  • 素直に、Hue Bridgeのボタンをポチッと押して、もう一度同じようにPUTしてみましょう.
  • すると"username": "XXXXXXXXXXXXXXXXX"と、API利用時に必要なusernameが返ってきます.

API commandの例

URL: Message Body: Method できること
/api/[your-username]/lights なし GET Hue light一覧を取得できる
/api/[your-username]/groups なし GET グループ一覧を取得できる
/api/[your-username]/lights/{light#}/state {"on":true} PUT 指定したライトをオンにする
/api/[your-username]/groups/{group#}/action {"on":false} PUT 指定したグループをオフにする
/api/[your-username]/groups/{group#}/action {"on":true, "transitiontime": 100, "bri": 254} PUT 指定したグループを1秒かけて明るさ254(最大)にする

最後の/groups/{group#}/action を使って、徐々にライトを明るくします. transitiontimeの単位は100 msecなので、15分かけて明るくしたい場合は9000と設定します.

Node.jsでAPIを叩く方法.

turnOnHueTargetGroup () {

  // Hue API.
  var hueApi = `http://${hueBridgeIp}/api/${username}/groups/${groupId}/action`

  axios
    .put(hueApi, {
      "on": true,
      "transitiontime":  Math.round(msecTransTime/100),
      "bri": this.brightness
    })
    .then(function (response) {
      console.info(
        `[INFO] Hue light API has been invoked at ${new Date()}.`
      )
    })
    .catch(e => {console.log(e)})
}

Nature RemoのAPI初期設定

参考

アクセストークンの生成

https://home.nature.global/からトークンを生成する.

登録された家電一覧を取得

curl -X GET "https://api.nature.global/1/appliances" -H "accept: application/json" -k --header "Authorization: Bearer ${your-token}" | jq .

以下のようなレスポンスが返ってくるはず.

[
  {
    "id": "xxxxxxxxxxxxxxx"
    "device": {
      "name": "リビングのRemo",
      "id": "xxxxxxxxxxxxxxx",
      "created_at": "2019-02-06T02:09:08Z",
      "updated_at": "2019-02-15T22:00:01Z",
      "mac_address": "xxxxxxxxxxxxxxx",
      "serial_number": "xxxxxxxxxxxxxxx",
      "firmware_version": "Remo-mini/1.0.87-g8b06f0e",
      "temperature_offset": 0,
      "humidity_offset": 0
    },
    "model": null,
    "type": "IR",
    "nickname": "エアコン停止用",
    "image": "ico_ac_1",
    "settings": null,
    "aircon": null,
    "signals": [
      {
        "id": "xxxxxxxxxxxxxxx",
        "name": "オフ",
        "image": "ico_off"
      }
    ]
  },
  { ... }
]

この中のsignals -> idがAPI経由で家電を操作するときに必要になります.

API経由で家電を操作

curl

curl -H 'Authorization: Bearer ${your-token}' -H "accept: application/json" -X POST "https://api.nature.global/1/signals/${your-signal-id}/send" -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded"

Node.js


turnOnDevice () {
  var headers = {
    'Authorization': `Bearer ${remoApiToken}`,
    'accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  };

  axios({
    method  : 'POST',
    url     : `https://api.nature.global/1/signals/${deviceOnSignalId}/send`,
    headers : headers,
  })
    .then(function (response) {
      console.info(
        `[INFO] Nature Remo API for the device has been invoked at ${new Date()}.`
      )
    })
    .catch(e => {console.log(e)})
}

Slackから時刻設定情報を取得する

参考

Slack API tokenの取得

https://api.slack.com/apps から作成する.

時刻設定情報が投稿されているChannelのIDを取得する.

https://api.slack.com/methods/channels.list/test から取得する.

Node.js


getSlackPosts () {
  axios
    .get(`${this.slackApiUrl}?token=${slackApiToken}&channel=${slackChannelId}&count=${slackPostCount}`)
    .then(function (response) {
      var messages = response.data.messages;
      for (var message of messages) {
        // 取得したポストの中で、最新の有効な設定 (時刻情報 or OFF) を探す.
        if (checkSettingValue(message.text).valid) {
          var latestPost = message;
          break;
        }
        else {
          continue;
        }
      }
    })
}

宅内サーバで家電のONタイマーを設定する.

コード概要 (Hueライトタイマー部分のみ抜粋)

大まかには、以下のような流れで処理が動きます.

  1. Slackから時刻設定情報を取得 (例えば6:30、OFFなど).
  2. transitiontime (設定時刻に対して何分前に家電をONにするか) を考慮して、HueのAPIを叩く時間を計算する. 例えばtransitiontimeが15分の場合、6:15が実際にAPIを叩く時間になる.
  3. node-scheduleのタイマーの設定を6:15にして登録する.

var axios = require('axios');
var schedule = require('node-schedule');
var ApiScheduler = require('./api-scheduler');
const setting = require('./setting.json');

class WakeUpRoutine extends ApiScheduler {
  constructor(setting) {
    // 各種設定の読み込み.
    ...
  }

  start () {
    // 各家電のタイマーを適当な設定で初期化.
    this.jobInvokeHue = 
      schedule.scheduleJob('0 0 0 1 1 0', function() {
      this.turnOnHueTargetGroup()
    }.bind(this));

    // 一旦タイマーをキャンセル.
    this.jobInvokeHue.cancel();

    // Slackの投稿をチェックするタイマーを設定. (下記 * * * * * は毎分確認)
    var jobCheckSlack = schedule.scheduleJob('* * * * *', function() {

      axios
        .get(`${this.slackApiUrl}?token=${this.slackApiToken}&channel=${this.slackChannelId}&count=${this.slackPostCount}`)
        .then(function (response) {
          var messages = response.data.messages;
          for (var message of messages) {
            if (this.checkSettingValue(message.text).valid) {
              var latestPost = message;
              break;
            }
            else {
              continue;
            }
          }

          ...
          // 有効な設定情報が得られた場合にタイマーを更新する.
          // HueライトのONタイマーを設定
          this.setInvokeTimer(
            'Hue',
            this.jobInvokeHue,
            targetTimeHue,
            this.msecTransTimeHue,
          );
        }.bind(this))
        .catch(e => {console.log(e)})
    }.bind(this))
  }
 
  turnOnHueTargetGroup () {
    // Hue API.
    var hueApi = `http://${this.hueBridgeIp}/api/${this.username}/groups/${this.groupId}/action`

    axios
      .put(hueApi, {
        "on": true,
        "transitiontime":  Math.round(this.msecTransTimeHue/100),
        "bri": this.brightness
      })
      .then(function (response) {
        console.info(
          `[INFO] Hue light API has been invoked at ${new Date()}.`
        )
      })
      .catch(e => {console.log(e)})
  }

  setInvokeTimer (name, timer, targetTime, transitionTime) {
    // 設定時間に対してtransitionTimeだけ早くタイマーを設定する.
    var [hour, minute] = this.calculateInvokeTime(targetTime, transitionTime)
    
    // タイマーを更新.
    timer.reschedule(`${minute} ${hour} * * *`)

    console.log(
      `[INFO] ${name} timer setting has been updated. New invoke time is ${hour}:${minute}.`
    )
  }
}

var scheduler = new WakeUpRoutine(setting)
scheduler.start()

コード全体

GitHub - wakeup-scheduler

コンソール出力

Slackの時刻設定情報 (投稿) が更新されたときと、実際にタイマーで設定された時間になってAPIが叩かれたときに通知が出ます.

$ node server.js
[INFO] New target time has been set to 06:30
[INFO] Hue timer setting has been updated. New invoke time is 06:15.
[INFO] New target time has been set to 19:00
[INFO] Hue timer setting has been updated. New invoke time is 18:45.
[INFO] Hue light API has been invoked at Sat Feb 16 2019 18:45:00 GMT+0900 (JST).
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?