帰宅したらGoogleHomeから好きな音声で「おかえり」って言ってもらいます

GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいますの記事を読んだときにこう思った。
帰宅したらGoogleHomeに自発的に「おかえり」や「お疲れ様」って言ってもらいたい。
しかも自分の好きな音声で。
今回は、RaspberryPiを利用して作ってみました。

必要なもの

  • RaspberryPi(照度センサーを使います)
  • GoogleHome

流れ

  1. RaspberryPiで帰宅を検知
  2. google-home-notifier.jsを使ってGoogleHomeに音声ファイルを再生させる

RaspberryPiで帰宅を検知

ワンルームに住んでいるので、RaspberryPiで部屋の照明の状態を監視することで帰宅を検知できないか考えました。
以下の条件にすべて当てはまれば、帰宅したとみなします。
1. 照明がONになった
2. 照明がONになった時間帯が18:00 ~ 24:00の間
3. 照明がOFFからONに変わるまで6時間以上たっている

回路を組む

RaspberryPiで照明の状態を監視するために、照度センサーを組み込みます。
当方、電子工作初心者ですが、下記のサイトを参考に回路を組んでみました。
RaspberryPiで照度計をつくろう

照度を取得する処理はnode.jsで実装します。

照度の値を取得する

下記のサイトを参考にnode.jsで照度を取得しました。
Raspberry Piで取得したセンサーデータをリアルタイムに可視化する(センサー編)

app.js
const SPI = require('pi-spi');
const spi = SPI.initialize("/dev/spidev0.0");
const MCP3002 = Buffer([0x78, 0]); // チャンネルは1にセット

// 毎秒照明の値を監視
setInterval(() => {
  spi.transfer(MCP3002, MCP3002.length, (err,data) => {
    if (err) {
        console.error(e);
    } else {
      let value = ((data[0]<<8) + data[1]) & 0x03FF
      console.log(value);
    }
  });
}, 1000);

照度を取得できているか確認するため実行してみます。

$ node app.js

521 // 照明がONの状態
508
512
505
510
499 // 照明をOFFにした
473
475
132
45
22
0
501 // 照明をONにした
509

今回は、照度が500を超えていれば、照明がONになっているとします。

帰宅検知

以下の条件にすべて当てはまれば、帰宅したとみなします。
1. 照明がONになった
2. 照明がONになった時間帯が18:00 ~ 24:00の間
3. 照明がOFFからONに変わるまで6時間以上たっている

app.js
const moment = require('moment');
let previousStatus = ''; // 照明の状態
let previousTime = '';   // 照明の状態が変わった時間

let value = ((data[0]<<8) + data[1]) & 0x03FF
if (value >= 500 && previousStatus === 'off') {
    // 照明がon
    previousStatus = 'on';
    const changeTime = moment();
    const durationMinutes = changeTime.diff(previousTime, 'minutes');
    if (changeTime >= moment({H:18, m:0, s:0}) && changeTime <= moment({H:23, m:59, s:59}) && durationMinutes >= 300) {
      console.log('帰宅!');
    }
    previousTime = changeTime;
} else if (value < 500 && previousStatus === 'on') {
    // 照明がoff
    previousStatus = 'off';
    previousTime = changeTime;
}

google-home-notifier.jsを使ってGoogleHomeに音声ファイルを再生させる

google-home-notifier.js

Chromecast Client向けのプロトコルを利用して、GoogleHomeにしゃべらせることができるとのこと。
好きなテキストをGoogleHomeに喋らせることができるようですが、音声ファイルを喋らせるメソッドもあることを発見。

google-home-notifier.js
var play = function(mp3_url, callback) {
  if (!deviceAddress){
    browser.start();
    browser.on('serviceUp', function(service) {
      console.log('Device "%s" at %s:%d', service.name, service.addresses[0], service.port);
      if (service.name.includes(device.replace(' ', '-'))){
        deviceAddress = service.addresses[0];
        getPlayUrl(mp3_url, deviceAddress, function(res) {
          callback(res);
        });
      }
      browser.stop();
    });
  }else {
    getPlayUrl(mp3_url, deviceAddress, function(res) {
      callback(res);
    });
  }
};

GoogleHomeに接続するための設定をするにあたり、gooogle-home-notifier.jsに手を加えます。

gooogle-home-notifier.js
// 第2引数からGoogleHomeのIPアドレスを指定できるようにします。
var device = function(name, address, lang = 'en') { // 第2引数にaddressを追加
    device = name;
    deviceAddress = address; // ここを追加
    language = lang;
    return this;
};

帰宅を検知すると、playメソッドを呼び出します。

app.js
const googleHomeNotifier = require('google-home-notifier');
googleHomeNotifier.device('GoogleHome','192.168.x.x', 'ja');
googleHomeNotifier.accent('ja');

// 帰宅を検知したらGoogleHomeから音声を再生する
googleHome.play('http://192.168.x.x:8080/audio/test.mp3', (notifyRes) => {
  console.log(notifyRes);
}

今回はラズパイ上にmp3ファイルを保持するため、音声ファイルを返すAPIをexpressでサクッと実装します。

音声ファイルを返すAPI

api.js
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');

const app = express();
const serverPort = 8080;
const urlencodedParser = bodyParser.urlencoded({ extended: false });

// CORSを許可
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

/**
 * 音声ファイルを取得
 */
app.get('/googlehome/:audioName', (req, res) => {
  const audioName = req.params.audioName;
  if (!audio) {
    res.status(400).send('Invalid Parameters.');
  }

  const file = fs.readFileSync(__dirname + '/public/audio/' + audioName, 'binary');
  res.setHeader('Content-Length', file.length);
  res.write(file, 'binary');
  res.end();
});

app.listen(serverPort, () => {
  console.log(`Start api-server. Port is ${serverPort}`);
})

RaspberryPi上でプログラムを常駐させる

// 照度を監視
forever start --spinSleepTime 7000 -m 1000 google-home/app/index.js

// 音声ファイルを返すAPI
forever start --spinSleepTime 7000 -m 1000 google-home/api-server/index.js

全ソースコードはこちらをご参考ください。

できたもの

最後に

帰宅後、前より寂しい気持ちになった(´・ω・`)

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.