ARCHETYP

ARCHETYP的スマートオフィス 〜来客システム編〜

あけましておめでとうございます。3児のパパエンジニアの笹垣です。

引き続き2019年も技術系の情報を中心にアーキタイプの取り組みを発信していきたいと思いますので、本年もどうぞよろしくお願いいたします。

早速ですが、今回は昨年書かせていただいた『ARCHETYP的スマートオフィス』の続編として、Google Home(Mini)と来客システムの連携についてご紹介したいと思います。

はじめに

弊社にお越しいただいたことがある方は御存知かと思いますが、弊社オフィスのエントランスにはアポイントや配達の受付業務を行っている、来客システム(iPad)が大体9時〜19時で常駐しております。

reception

来客システム自体は「会社名・目的・担当者を選択し呼び出す」というシンプルな操作になっており、「呼び出す」をタップするとそれぞれの会社のSlackに担当者へのメンション付きで通知が行く仕組みになっているのですが、Slackだと気付きにくいという声が多く、「であればGoogle Homeに喋らせたらどうか」ということで今回のプロジェクトがスタートしました。
(弊社にはAmazon Echoもありますが、Amazon Echoに喋らせるには何かしらこちらからの発言が必要なため、Google Home一択となりました)

やったこと

Google Homeに喋らせるといっても、単純にGoogle Homeだけでは実現できないため、”喋らせる”という部分をRaspberry Piを使って実装しますが、前回初期設定を行っているため、今回はgoogle-home-notifierを使い実際に喋るところまでを順を追って説明します。

必要なパッケージのインストール

google-home-notifierを使用するには、node.js、npmが必要になります。
node.jsはソースからのインストールも可能ですが、今後のことを考慮しnode.jsのバージョン管理がしたかったので、nodebrewを使うことにしました。

まずはパッケージリストの更新から。

$ apt-get update
取得:1 http://archive.raspberrypi.org/debian stretch InRelease [25.3 kB]
取得:2 http://raspbian.raspberrypi.org/raspbian stretch InRelease [15.0 kB]
取得:3 http://archive.raspberrypi.org/debian stretch/main armhf Packages [200 kB]
取得:4 http://raspbian.raspberrypi.org/raspbian stretch/main armhf Packages [11.7 MB]
取得:5 http://archive.raspberrypi.org/debian stretch/ui armhf Packages [40.3 kB]
11.9 MB を 2分 56秒 で取得しました (67.6 kB/s)
パッケージリストを読み込んでいます... 完了

更新が終わったら、nodebrewをインストールします。

$ curl -L git.io/nodebrew | perl - setup
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
100 24634  100 24634    0     0   8781      0  0:00:02  0:00:02 --:--:--  8781
Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

インストールが終わったら、環境変数PATHへの設定を追加します。

$ vi ~/.bashrc
…
export PATH=$HOME/.nodebrew/current/bin:$PATH

$ source ~/.bashrc

設定を反映し、以下の表示が確認できたらインストール完了です。

$ which nodebrew
/root/.nodebrew/current/bin/nodebrew

続いてnode.js、npmをインストールします。
※今回は最新版をインストールします。

$ nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v11.4.0/node-v11.4.0-linux-armv7l.tar.gz
######################################################################## 100.0%
Installed successfully

使用するnodeのバージョンを指定し、

$ nodebrew use v11.4.0
use v11.4.0

以下の表示が確認できたらインストール完了です。

$ node -v
v11.4.0

$ npm -v
6.4.1

最後に、残りのパッケージをインストールします。
必要なパッケージはGitHub – noelportugal/google-home-notifierに記載があるものになります。

$ apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

ここまでで、最低限必要なパッケージのインストールは完了です。

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

google-home-notifierをインストールします。

$ cd /home
$ mkdir www
$ cd www

$ git clone https://github.com/noelportugal/google-home-notifier
Cloning into 'google-home-notifier'...
remote: Enumerating objects: 155, done.
remote: Total 155 (delta 0), reused 0 (delta 0), pack-reused 155
Receiving objects: 100% (155/155), 25.57 KiB | 0 bytes/s, done.
Resolving deltas: 100% (85/85), done.

$ cd google-home-notifier
$ npm install

サンプルソースのカスタマイズ

Cloneしたファイルの中にある、サンプルソース(google-home-notifier/example.js)をベースにカスタマイズします。
カスタマイズと言っても、基本的にはほぼそのままの状態で動くため、Google Homeのデバイス名の変更と不要なものとしてGETの処理を削除したのみです。
※ファイル名は app.js としました。

app.jsvar express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
var serverPort = 8091; // default port
var language = 'ja';
var deviceName = 'Google Homeのデバイス名を入れる';

var urlencodedParser = bodyParser.urlencoded({ extended: false });


app.post('/google-home-notifier', urlencodedParser, function (req, res) {
  
  if (!req.body) return res.sendStatus(400)
  console.log(req.body);
  
  var text = req.body.text;
  
  googlehome.device(deviceName, language); 

  if (text) {
    try {
      if (text.startsWith('http')){
        var mp3_url = text;
        googlehome.play(mp3_url, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
        });
      } else {
        googlehome.notify(text, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will say: ' + text + '\n');
        });
      }
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('Please POST "text=Hello+Google+Home"');
  }
})

app.listen(serverPort, function () {
  ngrok.connect(serverPort, function (err, url) {
    console.log('Endpoints:');
    console.log('    ' + url + '/google-home-notifier');
    console.log('POST example:');
    console.log('curl -X POST -d "text=Test Google Home" ' + url + '/google-home-notifier');
  });
});

※ソース内に、Google Homeのデバイス名を設定する必要がありますが、デバイス名がわからない場合はこちらを参考にGoogle Homeアプリから確認してください。

google-home-notifierの実行

カスタマイズが終わったら、google-home-notifierを実行しGoogle Homeがちゃんと喋るかを確認します。

まずはngrokを起動します。
ngrokとは、localhostで動いているサーバーをLANの外からアクセスできるようにできる便利なツールで、主に開発用途として使うことが多いのですが、今回はとりあえず動くものを早めに作りたかったのでこちらを使用しました。
(ネットワーク周りをどうするかは今後検討します…)

$ ./ngrok http 8091

// この情報はあとで使います
ngrok by @inconshreveable                                                                                                             (Ctrl+C to quit)

Session Status                online
Session Expires               7 hours, 59 minutes
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://xxxxxxxx.ngrok.io -> localhost:8091
Forwarding                    https://xxxxxxxx.ngrok.io -> localhost:8091

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

続いて、新たにターミナルウィンドウを立ち上げ、Raspberry PiにSSHログインしさきほどカスタマイズしたソースを実行します。

$ cd /home/www/google-home-notifier
$ node app.js

最後に、ngrok起動時に表示されるURLに対してPOSTします。

$ curl -X POST -d "text=Test Google Home" https://xxxxxxxx.ngrok.io/google-home-notifier

すると、Google Homeが「Test Google Home ♪」と喋ります。

来客システムとのつなぎ込み

Google Homeが正常に喋ったら実際に来客システムから任意の言葉をPOSTし、指定した言葉を喋らせるようにします。
来客システム側のプログラムのSlackへの通知を行った後にRaspberry Pi(google-home-notifier)に対してPOSTする処理を追加します。

$POST_DATA = array(
  'text' => $this->company_name . 'に'  . $this->ghome_message
);
// $this->company_name には選択した会社名が入ります。
// $this->ghome_messageには選択した目的とアポイントの場合は担当者の名前が入ります。
$curl=curl_init('https://xxxxxxxx.ngrok.io/google-home-notifier');
curl_setopt($curl,CURLOPT_POST, TRUE);
curl_setopt($curl,CURLOPT_POSTFIELDS, http_build_query($POST_DATA));
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl,CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl,CURLOPT_FOLLOWLOCATION, TRUE);

$output= curl_exec($curl);

実際の動作がこちらです。

以上で来客システムとの連携は完了です! あとは、上記設定だけだと、Raspberry Piからログアウトするとプログラムが停止してしまったり、ngrokの有効期限切れにより通信ができない状態になってしまうため、プログラムの自動起動&永続化、ngrokがタイムアウトしないようにする作業が必要です。
また、Google Homeのデフォルトの声は機械的で違和感があったので、VoiceText Web APIを使って声を変えていますが、「アーキタイプ」の発音がおかしいのでより自然な発音になるように模索したいと思います。

それではまた!