• IoT

ランニングコストゼロで作るスマートホームコントロール(ラズパイとNode.jsとFirebaseと私)

左:ラズパイとセンサー、右GoogleHome

「違うよGoogle、上げてほしいのはテレビの音量だよ」

技術開発部の原田です。普段は業務ハッカーへの道を記載しています。
今回は趣向を変えて原田の自宅で構築した、Google Homeを用いたランニングコストゼロで実現するスマートホームコントロールについて記載します。

はじめに

Google Homeを使って色々出来るのではないかと期待して購入したけれど、意外に出来ることが少なくてガッカリした、という方も居られるかもしれません。
もっとテレビや照明器具なども自由に音声で操作したいですよね。

そこで本稿では、ランニングコストがかからないようにすることを条件に、音声で家電を操作する、スマートホームコントロールのシステムを紹介します。

各種クラウドサービスも用います。
Actions on Google/Dialogflow/Firebase(Realtime Database)
これらを無料で使用できる枠の中で用います。

また、Google Home以外の筐体として以下を使用します。
イニシャルコストだけかかってしまいますが、赤外線送信の仕組みがGoogle Homeに無いため仕方ありません。
・Raspberry Pi Zero W (¥1,296)
・RPZ-IR-Senser (¥4,350)

構成図

早速ですが、原田が実現したシステム構成は以下の通りです。

図1

画像中央に赤い線が惹かれていますが、原田の自宅の内外を示しています。
赤線より上側:原田の自宅外のクラウドサービス群
赤線より下側:原田の自宅内の筐体またはソフトウェア

アイコンの説明(図の矢印順。左下から)

ghomemini Google Home Mini
AoG Actions On Google
DF Dialogflow
FB Firebase
Node Node.js
RP Raspberry Pi Zero W
RPZ RPZ-IR-Sensor
天井 照明(赤外線リモコンで操作できるタイプ)
television テレビ(赤外線リモコンで操作できるタイプ)

要は「音声でリビングにある家電を自由に操作したい」というものです。自分で言うのも何ですが、発想が怠惰ですね・・・。

一見結構複雑な仕組みにしており、サービスのつなぎ目が多々ある印象です。
ですが、サービスを幾つか使い、役割を分担をすることで、サービスの拡張性があることを最後に追加開発の項目で説明します。

なお、冒頭の画像が今回のシステム構成の自宅側の構成です。
ケーブルがたった2本でスッキリしています。どちらも電源です。

用語解説

構成図の通りで、動作についてはほぼ説明不要かと思いますが、技術や筐体の用語について少し解説します。

Google Home Mini 音声を受け取る筐体。原田はMiniを使用しましたが、Google Homeの通常版でも構築可能です。当然ですがマイク+スピーカーがあります。
Google Assistant Google HomeやAndroidに搭載されているソフトウェアです。筐体の位置情報を元に天気情報を返すなどはGoogle公式の機能だけで実現しています。
Actions On Google Google Assistantの機能を拡張させるサービス基盤です。Actions On Google自体にはロジックはありません。Actions On Google内ではサービスを起動するためのウェイクワード(OK, Google XXXにつないで)を定義程度のことだけが可能です。会話のロジックは記載しません。
あくまでその音声認識/解析、会話方式の定義についてはDialogflowのような後続のアプリに任せる形をとっています。Dialogflow以外のサービス(音声認識/解析サービス)にも接続可能です。今回はDialogflowを用います。
なお、第三者に公開することも可能ですが、今回はテストバージョンのアプリケーションを作成するのみとします。
Dialogflow Googleの言語解析エンジンです。自然言語の解析を行います。ユーザにバックエンドを意識させないよう、サービスとして使える形になっています。Actions On Googleに接続できるだけでなく、SlackやFacebookMessangerなど外部のサービスに言語解析結果を渡すことも可能です。言語解析後の処理まではDialogflowは担当しません。
Firebase 元々はmBaaSの一種です。Realtime Databaseの仕組みが便利であり、それを用いられていることが事例として多いです。
Firebase Functions ≒Google Cloud PlatformのCloud Functions。FaaSの機能も備えており、RESTの受け口もNode.jsで記載できます。
一定以上の使い方をすると課金されてしまいますが、自宅の中を制御する程度であればランニングコストはかかりません。
Node.js サーバサイドjavascript環境です。NPMパッケージマネージャで機能を追加可能です。今回はコードの記載を一部に止めますが、照明を付けるなどのロジックはNode.jsに記載されています。Node.jsを採用したのには各種ライブラリが豊富であったためです。Firebaseのデータベースの変更検知が出来るfirebase(ライブラリが同名なのがややこしいですが)、Google Homeに発話させるGoogle-Home-Notifier,シェルコマンドを実行出来るshelljsを用いています。近頃は新機能が出たときにNode.jsが真っ先にサポートされるため、最近は何でもNode.jsで組んでしまいます・・・
Raspberry Pi Zero W 5ドルPCと歌われて世に出た小型PC Zeroの後継機です。Bluetooth,Wifiが標準搭載。消費電力も小さく電気代が安く済む。通称ラズパイ。OSはRaspbian(Stretch)にしています
RPZ-IR-Sensor ラズパイに取り付け可能なセンサーキットです。赤外線送受信,温度計,湿度計,気圧,照度も測定可能なセンサーが付いています。

構築手順解説

登場人物(サービス、ソフトウェア)がやたら多いですが、あまり心配する必要はありません。
以下の4ステップで可能です。

  1. Firebaseでリアルタイムデータベースを作成し、Dialogflowからの受け口をFirebase Functionsで用意する
  2. Google Assistantが標準で出来ないことを行うためにActions On Googleを用意する
  3. Dialogflowでの音声認識/解析の処理を定義し、結果をFirebaseに書き込む(Firebase Functions経由)
  4. ラズパイ上のNode.jsがFirebaseのRealtime Databaseの変更を検知しRPZ-IR-Sensorに指示、赤外線を送信して照明器具やテレビを操作する

以下にそれぞれ手順を解説しますが、非常に細かい部分については一部割愛します。
割愛する内容についてはテキストで記載しておきます。

1.Firebaseでリアルタイムデータベースを作成し、Dialogflowからの受け口をFirebase Functionsで用意する

データベースを作成します。FirebaseリアルタイムデータベースはKVSであり、テーブルを意識する必要はありません。
コマンドを記載すると良いだけなので、commandというキーを作成します。
本来は認証によるアクセス制限を考慮する必要がありますが、今回は簡単にどこからでも読み書き出来るように設定します。

左メニューのDevelop -> Databaseをクリック。「ルール」を選択
readとwriteの権限をtrueに変更する
Firebase01

続けて「データ」を選択
ツリーにcontol、その下にcommandを追加します。commandの値は”test”で構いません。(スキーマを作成することが大事)
Firebase02

ここの記載:
”https://XXXXXXXXXXXXXXXX.firebaseio.com”がデータベースへのアクセス先です。

また、Firebase上で、Dialogflowからの受け口を作る必要があります。
こちらの説明は一部割愛し、概要のみ記載します。

概要
この作業は、Dialogflowが作成した命令文をFirebaseが受信するため、Firebase側に受け口を作る作業です。
Firebase Functionsという機能を使います。
作業用のPC(例えば自宅のWindowsPC)などにNode.jsをインストール、Node.jsのアプリケーションを作成(いずれもコマンドのみで作成可能)します。
少しだけ改変を行い、Firebaseのcontrol/commandスキーマに[target,action]の内容をカンマ区切りで書き込むようにします。
そしてFirebase Functionsへのデプロイを行い、Firebase FunctionsへのURLを得ます。”https://us-central1-XXXXXXXXXXXXXXXXXXXXXXXXXXXX.cloudfunctions.net/test” などとなります。(※1)
このURLがFirebase側の受け口になるため、Dialogflowの設定箇所でこのURL設定を用います。

ドキュメントは左メニューのDevelop -> Functions -> スタートガイド を参照してください。

後ほど(※1)のURLを使用します。

もう一つFirebase上で情報を取得しておきます。

Project OverviewからwebアプリにFirebaseを追加をクリック
Firebase03

// Initialize…以下にあるconfigの内容をコピーしておきます。(※2)
Firebase04

こちらのconfig内容は、最後のNode.jsのアプリケーション内で使用します。

2.Google Assistantが標準で出来ないことを行うためにActions On Googleを用意する

Actions On Googleから、サービスを作成し、言語解析エンジンのDialogflowに接続する箇所まで登録します。

Actions On Googleのページhttps://console.actions.google.com/
に進み(Googleへのアカウントへのログインが必要です)、Add/Importで任意の名前でプロジェクトを作成します。
AoG01

プロジェクト名は任意、Japanを選択してCreateしてください。
AoG02

Build Custom AppからDialogflowのBUILDをクリックしてください。
AoG03

一度Dialogflowのページに進みます。
プロジェクト名、DEFAULT LANGUAGEを日本語、API VERSION V2を有効にしてCREATEをしてください。
AoG04

そのままDialogflowにおいて画面左のIntegrationsから Google AssistantのINTEGRATION SETTINGS
AoG05

特に何も設定せずに右下のTESTボタンをクリックしてください。
AoG06

Actions On Googleの操作に戻ります。
Actions On Googleのページを開き、Overviewに遷移してください
AoG08
ActionsのところにDialogflow actionsとあり、Actions On GoogleとDialogflowが紐付けられたことが表示されています。

続けて App Information のEDITをクリックしてください。

Assitant appの情報を埋めていきます。今回は多少不完全であっても構いません。
必要なものを適宜埋めていきます。
AoG09

Assistant app name:
家電操作先生 (何でも良いですが、呼びやすい名前で良いでしょう)

Pronunciation:
ひらがなで記載しても良い。(発音です)

Assistant app introduction :
このアプリでできること:家電操作

Assistant app voice :
お好きにどうぞ

Short description :
お好きにどうぞ

Full description :
お好きにどうぞ

Sample invocations :
Ok Google, 家電操作先生につないで (と表示されているはずですが、変更や言い回しの追加可能です)

他は設定を求められますが、テストのみでよければ上記だけで構いません。
画面右下のSAVEをクリックしてください。
Actions On GoogleのページからTEST DRAFTを押すと、シミュレータが起動します。
AoG10

シミュレータ上で「家電操作先生につないで」と入力してください。
AoG12

テストバージョンです、という反応が帰ってくると成功です。

これらの作業をしたところで、Google Homeに「Ok Google 家電操作先生につないで」と話しかけると、なんと「わかりました。家電操作先生のテストバージョンです」と返答してきます。
Actions On Googleが、自分の端末(Google Home)にドラフトのアプリケーションを配備しているということです。

3.Dialogflowでの音声認識/解析の処理を定義し、結果をFirebaseに書き込む(Firebase Functions経由)

次はDialogflowの設定です。Dialogflowのタスクは以下の通りです。
「Actions On Googleから届いた音声を処理し、命令文に直したものを後続のFirebaseに接続する。」
ただ、Dialogflowの設定項目は用語を知らなければ概念がつかみにくいです。
ですが、以下3つの言葉を把握しておけば解釈が容易です。

Intent:
「会話の意図」「問いかけに対する反応の定義」

Entity:
「言い回しの定義」「言い回しを検知しキーワードに置き換える」

Fullfillment:
「言語解析後の処理を行うサーバの定義」

まず説明し易いため、Entityの設定から行います。Entityは言い回しの定義です。
DialogflowのEntities横の+をクリックし、下を参考にtargetというEntityを作成します。
「照明」は「ライト」と呼ばれることもあるので、「照明」「ライト」をまとめて「ceilinglight」と捉えてね、と指定しています。
Dialogflow01

同様にactionを作成します。「電源音」というのは言語モデルが「オン」を「音」と捉えてしまった時にも対処できるようにしたものです。
Dialogflow02

無事にtargetとactionが定義できました。
Dialogflow03
次にIntentで会話を定義します。Intentsの横にある+をクリックします。

タイトルは家電操作で良いでしょう。
Contextsは一旦設定なしで構いません。
User saysで「ユーザがこう話したら」、を定義します。
target(テレビ、照明)に対して、action(電源オン、音量上げて)と問いかけるため、「target を action」(注:半角スペース必要)と入力し、それぞれの言葉をダブルクリック→@actionや@targetを選択します。
Dialogflow04

Eventsは一旦設定なしで構いません。
続いてActionの項目です。Actionは「言語解析後の処理を行うサーバにどのような値を渡すか」を定義します。
Actionのリストに含まれるすべての項目値が後処理のサーバに送信されます。
画像を参考に設定してください。
合わせてResponseを設定します。(ユーザに何と返答するかを定義します。)
Responseのところに$target,$actionと$付きにするのと良いです。

Dialogflow05

Intentの設定はこれで完了です。SAVEをクリックしておきます。

続いてFulfillmentです。後処理のサーバを指定します。
画面左のFulfillmentからWebhookを有効にしてください。
Dialogflow06

URLの箇所に、(※1)で設定したFirebase FunctionsのURLを指定してください。
Dialogflow07

作成したFulfillmentをIntentに紐付けます。
「家電操作」のIntentを開き、Responseの下にあるFulfillmentにUse webhookのチェックボックスをONしたら完了です。

これでDialogflowの設定は完了です。シミュレータで動作を確認してみましょう。
試しにActions On Googleで家電操作先生を起動させ、「テレビを付けて」と入力してみてください。
AoG13

「televisionをpower_onやな。操作したで」という文字列が帰ってくれば成功です。
Dialogflowの中で言い換えをしており、「テレビ」という文字列を「television」に、「付けて」を「power_on」にそれぞれ言い換えていることがわかります。FulFillmentにはこの「television」「power_on」という文字列が送信されます。
なお、Fulfillmentに到達していなくてもシミュレータ上で返答が帰ってきます。

4.ラズパイ上のNode.jsがFirebaseのRealtime Databaseの変更を検知しRPZ-IR-Sensorに指示、赤外線を送信して照明器具やテレビを操作する

とうとう最後です。ラズパイへNode.jsをインストールし、各種ライブラリをインストール、Firebaseを検知させる。DBの変更を検知した際に赤外線送信コマンド(irsendコマンド)が動作するようにする。

4.の説明は一部割愛します。
4.については事前に準備作業が必要であり、ここでは詳細な手順説明を省きます。
準備作業とは、実際にあるテレビの赤外線リモコンの各ボタンを押した際に出る赤外線のパターンをirrecordコマンドを用いて記録しておき、irsendコマンドでその動作を確認することです。
ラズパイにおいて「irsend SEND_ONCE television vol_up」などのコマンドを実行するとテレビの音量が上がる、という状況にしておかなくてはなりません。

ラズパイで以下を実行します。

$ sudo apt-get install -y nodejs
$ cd 任意のディレクトリ
$ mkdir firebase_listener
$ cd firebase_listener
$ npm init
$ npm install firebase shelljs forever
$ npm install
$ touch index.js

index.jsの内容を以下に改変します。
※2 にある取得したFirebaseの設定値を用います。

// モジュール読み込み
var firebase = require('firebase');
var shell = require('shelljs');
 
// 命令内容からirsendコマンドへの変換
function parseCommand(command) {
    console.log(command);
    var result = {cmd:'',msg:''};
    var irsend = 'irsend SEND_ONCE ';
 
    if(command.startsWith('ceilinglight')){
        // ceilinglight,power_on to irsend SEND_ONCE ceiling_light power_on
        var array = command.split(',');
        result.cmd = irsend + 'ceiling_light'+ ' ' + array[1];
        result.msg = '';
    }
    if(command.startsWith('television')){
        // television,vol_up to irsend SEND_ONCE television vol_up
        var array = command.split(',');
        result.cmd = irsend + 'television' + ' ' + array[1];
        result.msg = '';
    }
 
    return result;
}
 
// control以下が変更された時にirsendコマンドを実行する
function commandChanged( snapshot ) {
    console.log("---command changed---");
    var data = snapshot.val();
 
    var command = parseCommand(data.command);
 
    // Execute command if needed
    if(command.cmd != '') {
        // async true.
        shell.exec(command.cmd, {async:true});
    }
 
    return;
}
 
// Node.jsから見たFirebaseへの接続先
// DialogflowやActions On Googleではないので注意
// Firebaseのプロジェクトページから以下の記述部分をコピーすると良い
// *****プロジェクト個別に要指定 ここから*****
var config = {
    apiKey: "XXXXXXXXXXXXXXXX",
    authDomain: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    databaseURL: "https://XXXXXXXXXXX.firebaseio.com",
    projectId: "XXXXXXXXXXXXXX",
    storageBucket: "XXXXXXXXXXXXXXXXXXXXXXXX",
    messagingSenderId: "XXXXXXXXXXX"
};
// *****プロジェクト個別に要指定 ここまで*****
 
firebase.initializeApp( config );
 
var db = firebase.database();
var control = db.ref( '/control' );
 
// firebaseの値に変化があった際にイベントを発火させる
control.on('value',function(snapshot){commandChanged(snapshot);});

アプリの起動(forever startとすることで、ラズパイを再起動した際に自動起動します)

手順は以上です。お疲れ様でした。

使用方法

使用方法は至って簡単です。Google Homeに話しかけましょう。

1.Google Homeに「OK, Google 家電操作先生につないで」と話しかけます(操作モードが作成したアプリケーションに切り替わります)
2.Google Homeに「テレビを付けて」「照明を電源オン」と話しかけます (「Ok, Google」が不要です)

まとめ

趣味で始めたにしては結構複雑なシステムが出来てしまいました(笑)

まず、このシステムの根幹の部分は以下の部分です。

rootofsystem

・Firebaseのリアルタイムデータベースに、実行したいコマンドをテキストで記入する。
・自宅のラズパイで動作しているNode.jsがFirebaseのDBの変更を検知し、コマンドに応じた処理を実施する。

根幹の部分についてはこう書くと非常にシンプルですね。

DBの値の変化というイベントを検知できるため、実はネットワーク周りの設定が不要というのは大きなメリットです。(自宅ネットワークにも何も手を加えていません)
また、Node.jsで記載するソフトウェアのロジックは自分で記載出来るため、その後の処理を自由に定義、改変することが出来ます。

クラウドサービスを利用しつつ、自由度の高いアプリケーションを構築したい場合の構成には向いているのではないでしょうか。

追加開発

実はより便利にするために2つほど追加開発をしました。
いずれも標準の使い方だけでは実行できないものになっています。システム構成図を載せておきます。

IFTTTを経由して、任意のテキストメッセージをGoogle Homeに喋らせる

図2

Firebaseの値はHTTP通信によって更新が可能であるため、IFTTTからHTTPリクエストを送信してDBを更新させることが可能です。
ここでは、アプリ側を改修してGoogle Homeにテキストメッセージを喋らせるようにしています。(Google-Home-Notifierを使用)

さらにIFTTTを使って、原田の場合以下のようなこともしています。

  • 毎日20:15になったら、「理央さん歯磨きをしましょう(娘あてのメッセージ)」とGoogle Homeに喋らせる(IF Date & Time THEN Webhook)
  • 原田が自宅近くを通ったら、Google Homeに「旦那がそろそろ帰ってきます」と喋らせる(IF Location THEN Webhook)

※ IFTTTのTHEN設定はWebhookを使用します。control/commandの値を「justsay,テスト」更新するようにします。 (HTTPはPUT,テキスト「”justsay,テスト”」となるように)
アプリ側の改修は、control/commandの内容がjustsay,XXXと書いてあれば、Google-Home-NotifierでGoogle Homeに発話させるようにしています。

※ curlコマンドで動作を確認するためには、以下のようにコンソールで実行してください。Firebaseのcontrol/command値を変更できます。


curl -X PUT -d '"justsay,テスト"' 'https://XXXXXXXXXXXXXXXX.firebaseio.com/control/command.json'

Google HomeでWEB家計簿にランチ費用を登録する

図3

利用しているWEB家計簿サービスZaimには開発者用のAPIが作成できるようになっていたため、それを用いてランチの費用を登録出来るようにしました。

音声で入力できるので、通常のアプリを使って入力するよりは、幾らか簡単になりました。(Developer Programへの登録と、アクセストークンの取得などが必要です)

さらなる追加開発の構想

Firebase、Node.jsというシステムの根幹構成は変えずとも、例えば以下のような技術的工夫/改善が考えられるでしょう。

  • (技術要素の交換)言語モデルを家電操作に最適化されたものを用意し、Dialogflowに取って変える
  • (インプット種別の追加)メールの内容をGoogle Homeに読み上げてもらう
  • (アウトプット機器の追加)別の部屋の操作も可能にする(もう一台ラズパイ+赤外線送信機を用意、監視スキーマは同じで良い)
  • (センサーデータの取得によるアクション)RPZ-IR-Sensorで室温を取得してFirebaseに記録、必要とあればエアコンを操作させる

根幹のDBとアプリケーションがあるだけですので、それと接続するサービスは幾らでも考えられます。
今後は(多段になったとしても)サービスの組み合わせで世の中の利便性を向上する方法を考えられてはいかがでしょうか。

なお、私が自宅内で身体を動かさず怠惰になっていくのは火を見るよりも明らかです。ダイエットせな・・・。

オチ

ここまで記事を書いておいて何なのですが、実は単純に製品としてNature Remo(http://nature.global/) や sRemoR(http://sremor.socinno.com/)を購入すると、労せず簡単に赤外線送信機能によるホームコントロールができます。
スマートフォンアプリも提供されており、共にIFTTTも対応しているとのことです。(2/9時点売り切れていますが)

・・・か、家計簿への登録なんて音声で出来ないでしょう!(苦し紛れ)

関連記事

  1. IoT奮闘記 ~なめこから始まるIoTシステム構築~

  2. Nature Remoを使って憧れのスマートホーム化!

  3. Google Homeの機能紹介 ~ブロードキャスト機能、メモ機能~

  4. 観葉植物とお話しよう!(Wio NodeとGrove土壌水分センサ)

  5. 娘に渡すIoTデバイス(Wio LTE+GPSセンサー)

  6. M5StickC(マイコン)で格ゲーをつくる

  7. 金曜日に届いたFitbit Inspire HRで週末2つアプリを作っ…

  8. SORACOM LTE-M Buttonで飲み会に行くことを妻に通知す…

PAGE TOP