4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

enebularAdvent Calendar 2020

Day 23

enebularのNode-RedからBOCCOを発話させる

Last updated at Posted at 2020-12-22

はじめに

enebularのNode-Redから文字を入力しBOCCOを発話させてみました。

BOCCOとは、ユカイ工学から開発した家族をつなぐコミュニケーションロボットです。

BOCCOに話しかけると、それが音声メッセージとして送信され、スマートフォンからはテキストか音声でメッセージを送信することができます。
子供、両親、祖父母などのスマートフォンの操作ができない家族とも簡単にコミュニケーションをとることができる、そんなコミュケーションロボットです。また、温度センサや振動センサ、鍵センサとの連携もできます。

またBOCCOには開発者向けに、BOCCOに自由な言葉を発話させたり、BOCCOに話しかけられた発話データを取得したりすることができるようにAPIが公開されています。

そのAPIを利用することNode-RedからBOCCOを発話させることができるので、その方法について説明します。
意外と、APIをたたくときにcurlコマンドからNode-Redへの置き換えに詰まってしまいました。
なので、本記事はBOCCO API以外のAPIをNode-Redから叩くときに参考になるかと思います。

本記事執筆にあたって[@1ft_seabass](https://qiita.com/tseigo/lgtms)さんにとてもよく助けていただきました、ありがとうございます!!

BOCCO APIをつかう前準備

BOCCO APIを使うためには下記の準備が必要です。

  1. BOCCOを買う
  2. BOCCOアプリのユーザーアカウントをつくる
  3. BOCCO APIの利用申請を行い、APIキーを取得しておく

本記事のスコープ

本記事では、BOCCO APIでメッセージを送信する部分の実装を書きます。なので、APIのアクセストークンの取得チャットルームの取得(発話させたいアプリ上のルームのuuid取得)は事前にcurlコマンドを通して行われているものとします。

curlコマンドからNode-Redの置き換えを考える

BOCCOにメッセージを送信するためには、curlコマンドで下記のようにします。
※access_toke-xxxxxxxxxには、「アクセストークンの取得」を参考にし取得したもの、room-id-xxxxxxxxxには、「チャットルームの取得」を参考にした文字列が入ります。


curl -i "https://api.bocco.me/alpha/rooms/room-id-xxxxxxxxx" \
    -d "access_token=access_toke-xxxxxxxxx" \
    -d "unique_id=`uuidgen`" \
    -d "media=text" \
    -d "text=こんにちはBOCCO!" \
    -H "Accept-Language: ja"

ぱっとみて、NOde-Redに置き換える上で疑問に思った点は下記の通りです

  • (おそらくPOSTだと考えていたが、)POSTなのかどうかよくわからん
  • uuidgenにはいるUUID version 4のNode-Red上での生成方法
  • -dや-HのペイロードをNode-Red上でどう表記するか

よくよく調べると、curlのオプションから

  • -d : POSTリクエストとしてフォームを送信
  • -H : HEADER HTTPヘッダにHEADERを追加もしくは変更

を意味するので、 上記のcurlはPOSTで良さそうだということがわかりました。

メッセージを送信するためのNode-Redのフロー

結果として、メッセージを送信するためのNode-Redのフローは下記のようになりました。

image.png


[{"id":"a511b8e0.9cce78","type":"tab","label":"フロー 2","disabled":false,"info":""},{"id":"a1bd5804.e816f8","type":"inject","z":"a511b8e0.9cce78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":200,"wires":[["5d0ef47f.4601fc"]]},{"id":"5d0ef47f.4601fc","type":"change","z":"a511b8e0.9cce78","name":"curl -d 部分","rules":[{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"payload.access_token","pt":"msg","to":"x2c4sjxacw4tq72q5h9vrsgjbcz3p55ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","tot":"str"},{"t":"set","p":"payload.media","pt":"msg","to":"text","tot":"str"},{"t":"set","p":"payload.text","pt":"msg","to":"こんにちはBOCCO!","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":200,"wires":[["fd594459.862968"]]},{"id":"1945a3cc.d39e4c","type":"change","z":"a511b8e0.9cce78","name":"curl -H 部分(ヘッダー)","rules":[{"t":"set","p":"headers.Accept-Language","pt":"msg","to":"ja","tot":"str"},{"t":"set","p":"headers.Content-Type","pt":"msg","to":"application/x-www-form-urlencoded","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":300,"wires":[["a41d5dc1.08334","e1875ceb.2a6d1"]]},{"id":"a41d5dc1.08334","type":"http request","z":"a511b8e0.9cce78","name":"","method":"POST","ret":"txt","paytoqs":true,"url":"https://api.bocco.me/alpha/rooms/E7607BA3-2AA0-4DEB-8959-XXXXXXXXXXXX/messages","tls":"","persist":false,"proxy":"","authType":"","x":550,"y":300,"wires":[["301fb11b.5e036e"]]},{"id":"301fb11b.5e036e","type":"debug","z":"a511b8e0.9cce78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":300,"wires":[]},{"id":"e1875ceb.2a6d1","type":"debug","z":"a511b8e0.9cce78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":380,"wires":[]},{"id":"fd594459.862968","type":"uuid","z":"a511b8e0.9cce78","uuidVersion":"v4","namespaceType":"","namespace":"","namespaceCustom":"","name":"payload.unique_id に uuid を付与","field":"payload.unique_id","fieldType":"msg","x":640,"y":200,"wires":[["1945a3cc.d39e4c"]]}]

一つ一つみていきます。

injectノード(タイムスタンプ)

injectノード(タイムスタンプ)が、このフローの開始ボタンとなっています。
この左四角ボタンをおすとフローが開始されます。
注意する点としては、タイムスタンプは日時のペイロードをもち、次のノードへと流れていきます。

image.png

changeノード(curl -d 部分)

次のchangeノードではcurlコマンドでいう-dの部分を記述する役割を持っています。
changeノードは上から下へ処理が降りていきます。
なので最初の。msg.payloadに対して{}と代入しているのは、先ほどのinjectノード(タイムスタンプ)の日時のペイロードを初期化するためです。それ以下のpayloadはcurlコマンドの要素をそれぞれ記載しています。
「msg.payload.~~~」と記述します。

image.png

uuidノード(payload.unique_idにuuidを付与)

これはuuidを生成するノードです。
「パレットの管理」→「ノードを追加」で「uuid」と検索すると、「node-red-contrib-uuid」と出てくるので追加して使います。

image.png

こちらはcurlコマンドでいう「"unique_id=uuidgen"」に対応している部分となります。

image.png

changeノード(curl -H)

こちらのノードにはcurlコマンドで「"Accept-Language: ja"」に対応します。
そして、このノードにはもう一つ重要なmsg.headerが入ります。
それが画像に記載のある「msg.headers.Content-Type」とその値「application/x-www-form-urlencoded」です。
これは盲点というか、全く未知のことでしたが、[@1ft_seabass](https://qiita.com/tseigo/lgtms)さんにご指導いただき理解しました。

image.png

Node-Redではもともとjsonで送るようContent-Typeが「application/json」で指定されているようです。
なので、どのContent-Typeでおくるのか意識して記述する必要があります。

※調べていたら同じようなことで、詰まっていたかがいらっしゃいました。Node-REDでA3RT APIを使うときのハマりどころ

http requestノード

こちらのノードでは「POST」を指定してURL部分はcurlコマンドで記述したURLを入れます。

image.png

動作確認

先ほどのノードを動かしてみると...喋った!!!!!!!BOCCCOがenebularのNode-Redから喋った!!!!!!!!
curlコマンド上のtextを変更すれば送信するメッセージを自由にかえることができます。

応用編:UIからテキストを入力してBOCCOを発話させる

全体のフローは下記の通りです。
先ほどのinjectノード(タイムスタンプ)部分がtext inputノードに置きえています。
主に変更が必要な3点のノードについて下記で解説します。

image.png


[{"id":"fbe90451.f204e8","type":"tab","label":"フロー 2","disabled":false,"info":""},{"id":"f22ca949.cbcff8","type":"comment","z":"fbe90451.f204e8","name":"メッセージ送信","info":"","x":100,"y":80,"wires":[]},{"id":"c50ee121.d83cf","type":"change","z":"fbe90451.f204e8","name":"curl -H 部分","rules":[{"t":"set","p":"headers.Accept-Language","pt":"msg","to":"ja","tot":"str"},{"t":"set","p":"headers.Content-Type","pt":"msg","to":"application/x-www-form-urlencoded","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":280,"wires":[["1646e643.b3242a","7d781da3.478604"]]},{"id":"1646e643.b3242a","type":"http request","z":"fbe90451.f204e8","name":"","method":"POST","ret":"txt","paytoqs":true,"url":"https://api.bocco.me/alpha/rooms/xxxxxxxx/messages","tls":"","persist":false,"proxy":"","authType":"","x":310,"y":340,"wires":[["ba5cd2d2.6f1b5"]]},{"id":"ba5cd2d2.6f1b5","type":"debug","z":"fbe90451.f204e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":340,"wires":[]},{"id":"7d781da3.478604","type":"debug","z":"fbe90451.f204e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":280,"wires":[]},{"id":"d85b093f.57a428","type":"ui_text_input","z":"fbe90451.f204e8","name":"","label":"","tooltip":"","group":"f11ebb11.fd1b88","order":4,"width":0,"height":0,"passthru":true,"mode":"text","delay":"300","topic":"","x":80,"y":220,"wires":[["db7bd901.751608","99c90f9c.edaba"]]},{"id":"c21ab3a0.6b448","type":"debug","z":"fbe90451.f204e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.text","targetType":"msg","x":490,"y":140,"wires":[]},{"id":"99c90f9c.edaba","type":"change","z":"fbe90451.f204e8","name":"msg.payload → msg.payload.text","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.text","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":220,"wires":[["c21ab3a0.6b448","18258676.518dea"]]},{"id":"db7bd901.751608","type":"debug","z":"fbe90451.f204e8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":270,"y":140,"wires":[]},{"id":"320fc2e2.485a5e","type":"change","z":"fbe90451.f204e8","name":"curl -d 部分","rules":[{"t":"set","p":"payload.access_token","pt":"msg","to":"xxxxxxxxxxx","tot":"str"},{"t":"set","p":"payload.media","pt":"msg","to":"text","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":280,"wires":[["c50ee121.d83cf"]]},{"id":"18258676.518dea","type":"uuid","z":"fbe90451.f204e8","uuidVersion":"v4","namespaceType":"","namespace":"","namespaceCustom":"","name":"payload.unique_id に uuid を付与","field":"payload.unique_id","fieldType":"msg","x":620,"y":220,"wires":[["320fc2e2.485a5e"]]},{"id":"f11ebb11.fd1b88","type":"ui_group","z":"","name":"text","tab":"a7ecc75a.8f0de8","order":1,"disp":true,"width":"6","collapse":false},{"id":"a7ecc75a.8f0de8","type":"ui_tab","z":"","name":"home","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

text inputノード

こちらにはテキストを入力するためのノードになります。
入力されたテキストはmsg.payloadに格納されます。
またこちらノードはダッシュボードに追加しておきます。
text inputノードのプロパティから「Group」→「新規にui_groupに追加」でぽちぽち進めていきましょう。
そうすると、右のダッシュボード画面の「タブ&リンク」にui_groupが追加されます。

image.png

changeノード(msg.payload → msg.payload.text)

先ほどのtext inputノードで入力されたテキストはmsg.payloadに格納されます。
なので、curlコマンドで渡されるように、msg.payload.textに変換して次のノードに渡します。
この時、「値の移動」を使って変換します。

changeノードの使い方はこちらの記事がわかりやすかったです。

image.png

changeノード(curl -d 部分)

こちらのノードは下記のように設定します。
今回は初期化する必要はないのでmsg.payloadに{}は代入しません。
また、msg.payload.textはinput textノードから流れてくるので、ここには記述しません。

image.png

動かしてみる

デプロイし、UIを表示させ、テキストを入力するとBOCCOが発話してくれます。

image.png

おわりに

今回はenebularのNode-Redを使ってBOCCOを発話させてみました。
curlコマンドで記述されたAPIのPOSTをNode-Redに置き換える方法を理解することができました。
Node-Redのノードごとに流れていくmsg.payloadの動きを、ちゃんとdebugノードでデバッグメッセージで表示させて、確認することが重要だと感じました。
これで他のAPIもNode-Redから叩くことができそうです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?