チカラの技術

電子工作やプログラミング

Wikipediaでアイアイの情報量を盛って歌うシステムを作りました(歌う編)

こんにちは。
前回の記事の予告通りgoogle homeさんに歌ってもらいました。

歌は心と情報量

いきなりですが結果からです。
IoTシステムを構築して歌ってもらいました。
www.youtube.com

google homeさんは200文字程度が読み上げ限界なので
概要のみの読み上げになりますが、
これで気になったおさるさんはいつでも調べてもらえますね!

技術解説

システム概要

概要図です。 f:id:powerOfTech:20180813194724p:plain 前回のpythonプログラムを使ってシステムを構成しました。
本当はインターネットにデータを出したくなかったのですが
google homeからローカルで直接情報を引っ張ってくる手段がなかったので
こんな冗長に見える構成になっています。

後段ではsocket.IOという双方向通信プロトコルのライブラリを使い、
RaspberryPiをクライアントとして接続させています。
これはローカルのRaspberryPiをwebサーバーとして公開する事を避けるためです。
webサーバーを公開するとなるとセキュリティやポートの設定などが必要になってきますからね・・・
(そもそも私の住処は集合住宅なので・・・)

以下、要素技術を解説していきます。

IFTTT

まず、IFはgoogle assistantを指定して以下のように設定しました。
f:id:powerOfTech:20180813201122p:plain

thenについてはweb hooksで
AzureサーバーにPOSTするようにしています。
f:id:powerOfTech:20180813201357p:plain
"TextField"部分にアイアイなどのキーワードが入り、送信されます。
また送信情報には"token"を追加し、
Azureサーバーはこのtokenを持ったリクエストのみ受け付けるようにしています。
(画像のtokenは変更済みですので今はもう使えません)

なお、tokenはこちらのハッシュ生成サービスを利用して生成しました。入力は適当です。
tool-taro.com

webサーバー

AzureのApp serviceからnode.jsの実行環境を利用しています。 ここではコード全文を記載します。

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser');

// this programs receive IFTTT message and send it to raspberry pi 

// setting body pearser
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(bodyParser.json());

var client;

//AzureにアップロードするときはPORTを環境変数で決めるため、必ず下記が必要になる。
var port = process.env.PORT || 8080;

//認証用トークン。IFTTTから同じトークンが送られて来た場合のみ本プログラムは動作する
const token = "9C3C4A2D197074C63221EA9FC98FF8323F40F543FF6E48CF1E4BCE9A83373957"

app.post(`/`, (req, res) => {
    console.log('IFTTT posted!' + req);
    //check token (authenticated User)
    if (req.body.token == token) {
        req.body.name = req.body.name.trim();
        var check = req.body.name;
        var sendName;
        // verify word from IFTTT(google home)
        if (check == "II" || check == "ii" || check == "I愛" || check == "I 愛" || check == "i愛") {
            sendName = "アイアイ";
        } else {
            sendName = req.body.name;
        }
        // send to raspberry pi 
        client.emit('ifttt', sendName);
    }
});

io.sockets.on('connection', (socket) => {
    client = socket;
    console.log('ras-pi connected');
});

//start server
http.listen(port, function () {
    console.log('listening on *:' + port);
});

「アイアイ」がその文字のまま解釈してくれない事があるので、修正コードが入っていますw
「オランウータン」は一発なので、google assistantに認識されやすい固有名詞と
そうでないものがあるという事ですね。
セキュリティ的にはトークンでガードしています。

ローカルのraspberryPi

node.jsからpython(前回の記事のコードを少し変更したもの)プログラムを読んで、wikipediaの情報を得ています。
そしてgoogle-home-notifierというライブラリでgoogle homeに喋らせたい内容を送ります。
あとはgoogle homeが読み上げてくれます。

//google home settings
var googlehome = require('google-home-notifier');
var language = 'ja'; 
googlehome.ip('192.168.123.456');
googlehome.device('Google Home', language); 

//// socket IOを接続先(Azureサーバー)指定で読み込む
var socket = require('socket.io-client')('https://iotwebappraiot.azurewebsites.net/');
socket.on('connect', function(){
    console.log('connected!');
});

socket.on('ifttt', function (name) {
    
    // サーバから受け取った動物の名前をwikipediaパーサーへ送り、
    var spawn = require('child_process').spawn;
    py = spawn('python3', ['WikiExForHome.py', name]);
    // wikipediaから抽出した内容をパーサーから受け取る。
    var say;    
    py.stdout.on('data', function (data) {
        say = data.toString();
        console.log(say);

        //wikiの内容をgoogle homeへ送信する。(話させる)
        try {
            googlehome.notify(say, function (res) {
                console.log(res);
            });
            //error
        } catch (err) {
            console.log(err);
        }
    });
});

まとめ

まとめます。

  • 情報量を増したアイアイを歌ってもらうIoTシステムを作った。
  • IFTTTのWebhooksは、自前のwebサーバーが作れればある意味なんでも出来るのでとても使い勝手が良い。
  • ひと昔前と比べると格段に個人で(POCレベルの)IoTシステムを作る事は楽になっているけど、
    「初めての人でも簡単です」とはまだまだ言えない感じ。

参考資料

Google AssistantとRaspberry Piで自宅の家電を操作する

socket.io が提供してくれているものは何か

Raspberry Pi で google-home-notifier を利用してGoogleHomeをしゃべらす方法

おまけ

google home + IFTTT の構成だけでもこのようにgoogle homeと歌うことができます。 youtu.be

IFTTTの「IF」に次のように設定、返事を登録できます。
f:id:powerOfTech:20180813210314p:plain
なお、後段の「THEN」は使わないのでなんでも良いです。

それでは!