Node-RED の WebSocket ノードを使って、WAN 側から Google Home を喋らせる
Node-Red サーバーで、node-red-contrib-cast ノードを使うと、簡単に Google Home で任意のメッセージを喋らせることができます。 ただし、Google Home は LAN 側にいるため Node-RED サーバーはローカルに立てる必要があり、外(WAN 側)から操作できません。
これを解決するのに、Heroku に立てた WebSocket サーバーとローカルに立てた Node-RED サーバーの WebSocket ノードを通信させることにしました。
システムの構成は下図のようになります。
動作を確認した環境
- Node-RED v0.20.5
- Node.js v12.14.0
- Heroku / Heroku CLI v7.38.1
- Google Home
- Google Home アプリケーション(iPhone)
WebSocket Server を Heroku 上に立てる
Using WebSockets on Heroku with Node.js を参考に、Heroku 上に WebSocket Server(とブラウザから入力を受け付けるフォームのための WebServer)を立てます。
プロジェクトのルートで npm を初期化します。
npm init -y
package.json
に以下を追記します。"engines": { "node": "12.x" }, "scripts": { "start": "node server.js" }
WebServer を立てるための Express と WebSocket Clinet Server の ws(といくつか modules)を追加します。
npm install --save express npm install --save ws bufferutil utf-8-validate
次の内容で、
server.js
を作成します。'use strict'; const express = require('express'); const { Server } = require('ws'); const PORT = process.env.PORT || 3000; const INDEX = '/index.html'; // WebServer を作成 const server = express() .use((req, res) => res.sendFile(INDEX, { root: __dirname })) .listen(PORT, () => console.log(`Listening on ${PORT}`)); // WebSocket Sever を作成 const wss = new Server({ server }); // message イベントでブラウザから受け取ったメッセージを WebSocket で通信しているクライアントに送信する wss.on('connection', (ws) => { console.log('Client connected'); ws.on('message', (message) => { sendAll(message); }); ws.on('close', () => console.log('Client disconnected')); }); const sendAll = (message) => { wss.clients.forEach((client) => { client.send(message); }); }
テキストボックスとボタンを配置した、
index.html
を作成します。<!DOCTYPE html> <html> <head> <script> const HOST = location.origin.replace(/^http/, 'ws') const ws = new WebSocket(HOST); ws.onmessage = (event) => { const el = document.getElementById('server-message'); el.innerHTML = 'Message: ' + event.data; }; </script> <title>WebSocket Server</title> </head> <body> <input type="text" id="text" value="" name="text"> <input type="submit" id="button" value="送信する"> <p id="server-message"></p> </body> <script> document.getElementById('button').addEventListener('click', ()=> { const text = document.getElementById('text').value; ws.send(text); }) </script> </html>
ローカルで動作確認します。
npm start
ブラウザで
http://localhost:3000
を開き、入力フォームにメッセージを入れて送信します。送信すると、「Message: 入力したメッセージ」が表示されます。また、開発者ツールのネットワークタブで、[WS] でフィルターすると、WebSocket 通信のキャプチャを確認できます。
Git を初期化し、
node_modules
以下を.gitignore
に追加します。git init echo '*node_modules' >> .gitignore
ディレクトリ次の内容でコミットを作り、Heroku に push します。
APP_NAME
は Heroku のアプリケーション名で、任意の値を設定します。git add . git commit -am "first commit" heroku create APP_NAME git push heroku master
Heroku 上にできたアプリケーションで、ローカルでやったのと同様に動作確認をします。
heroku open
このとき、開発者ツールのネットワークタブで、[WS] でフィルターし、キャプチャしている WebSocket 通信の [Name] を右クリック > [Copy] > [Copy link address] で WebSocket の通信先 URL をコピーしておきます。
Google Home の設定を行う
Google Home と接続したスマートフォンの Google Home アプリケーションを開き、設定画面から以下を行います。
- 言語設定を日本語にする
- 設定画面の最下部にある IP アドレスを確認する
Node-RED サーバーをローカルに立てる
Node-RED をローカルにインストールします。
npm install -g node-red
Node-RED を起動します。
node-red
http://127.0.0.1:1880/
にアクセスし、Node-RED の起動を確認します。
WebSocket ノードと Cast ノードを追加する
Node-RED の画面で、右上のハンバーガーメニューから[パレットの管理]をクリックします。
[ノードの追加]タブを選択し、「node-red-contrib-cast」を検索してインストールします。
左サイドメニューから、次のノードをエディタ上にドラッグ&ドロップします。
<dl> <dt>入力</dt><dd>WebSocket</dd> <dt>機能</dt><dd>キャスト</dd> </dl>
WebSocket ノードは次のように設定します。
項目 値 種類 接続 URL 開発者ツールのネットワークタブで確認した、WebSocket の通信先 URL 送信/受信 ペイロードを送信/受信 キャストノードは次のように設定します。
項目 値 IP Google Home の IP アドレス Port 8009 language ja WebSocket ノードとキャストノードをつなぎます。
- [デプロイ]ボタンでデプロイします。
動作を確認する
Heroku アプリケーションを開き、テキストボックスに喋らせたい内容を入力します。 [送信する]ボタンでクリックし、Google Home が入力した内容を喋ってくれれば成功です。