Node.js
GoogleHome

Google Homeに声をかけずに天気を言わせる

Google Homeが半額になったのでポチっていじってみました。
毎朝天気を確認し忘れて家を出ようとした時に雨でバタバタすることが結構あるので、天気を教えてくれたら嬉しいなーと思いつつしゃべりかけるのは面倒なので、Google Homeから話してくれるようにしてみました。

Google Homeアプリから設定できないか確認

ショートカットという任意の言葉に対して任意の行動をさせる機能はあったものの、自動で発言させるような機能はなかったので自力で作ることに。。

Dark Sky APIを使って天気情報を取得する

  1. Dark Sky API のアカウントを作る
  2. アカウント画面 からSecret Keyを確認
  3. http://www.geocoding.jp/ から任意の緯度・経度を取得
  4. 2.と3.を使ってAPIを叩いてみる
$ curl https://api.darksky.net/forecast/#{Secret Key}/#{緯度},#{経度}?lang=ja&units=si

値が返ってきたらとりあえず成功!

天気つぶやきスクリプト作成

package.json作成

$ mkdir google-home
$ cd google-home
$ npm init

google-home-notifierをインストール

$ npm install google-home-notifier

スクリプトを作成

weather-notifier.js
const googlehome = require('google-home-notifier');
const request = require('request');
const darkSkyUrl = 'https://api.darksky.net/forecast/${Secert Key}/#{緯度},#{経度}?lang=ja&units=si';

const options = {
  url: darkSkyUrl,
  method: 'GET',
  headers: {'Content-Type': 'application/json'},
  json: true
};

const getDate = (unixTime) => {
    date = unixTime ? new Date(unixTime*1000) : new Date();
    return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`;
};

const getTemperatureData = hourly => {
  const today = getDate();
  const temps = hourly.filter(hourlyData => {
    const date = getDate(hourlyData.time);
    return today === date;
  }).map(hourlyData => {
    return hourlyData.temperature;
  });
  const maxTemp = Math.max.apply(null, temps);
  const minTemp = Math.min.apply(null, temps);
  return { max: Math.round(maxTemp), min: Math.round(minTemp) };
};

const createMessage = body => {
  const currently = body.currently;
  const weather = currently.summary;
  const precipProbability = Math.round(currently.precipProbability*100);

  const tempDate = getTemperatureData(body.hourly.data);
  const maxTemp = tempDate.max;
  const minTemp = tempDate.min;

  const message = `おはようございます。今日の天気は${weather}、最高気温は${maxTemp}度、最低気温は${minTemp}度、降水確率は${precipProbability}%です。今日も1日頑張りましょう!`;
  return message;
};

const notify = message => {
  googlehome.device("Google-Home", 'ja');
  googlehome.notify(message, res => {
    console.log(message);
  });
};

request(options, (error, response, body) => {
  const message = createMessage(body);
  notify(message);
});

node weather-notifier.js で動けばOK!

launchdでcronを設定

家はmacなのでlaunchdでcronを設定します。
今回は8:30~9:00の間5分おきに天気を教えてくれるように設定しました。

/Library/LaunchAgents/weather.norifier.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>weather.notifier</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/node</string>
      <string>/Users/#{user_name}/google-home/weather-notifier.js</string>
    </array>
    <key>StartCalendarInterval</key>
    <array>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>30</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>35</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>40</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>45</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>50</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>55</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>12345</integer>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
    </array>
  </dict>
</plist>

作成完了したら上記plistをloadします

$ sudo launchctl load /Library/LaunchAgents/weather.norifier.plist

所感

かなり力技なのでもうちょっといい感じに実現できる方法ご存知の方は教えて頂けると嬉しいです。