BOCCO APIとESP32をつかってBOCCOからメッセージを取得する

# はじめに
ユカイ工学から開発した家族をつなぐコミュニケーションロボットの[BOCCO](https://www.bocco.me/bocco/)です。
BOCCOに話しかけると、それが音声メッセージとして送信され、スマートフォンからはテキストか音声でメッセージを送信することができます。
子供、両親、祖父母などのスマートフォンの操作ができない家族とも簡単にコミュニケーションをとることができる、そんなコミュケーションロボットです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212276/589e210a-e0b2-e16e-9433-eab676ba67e1.png" width="500">

BOCCOには開発者向けに、BOCCOに自由な言葉をしゃべらせたりデータを取得したりすることができるようにAPIが公開されています。[
BOCCO API 概要 | BOCCO API Documentation](http://api-docs.bocco.me/)

少し前にESP32からBOCCOを発話できるようにESP8266向けのAPIを改良してみました。
[BOCCO APIをつかってみよう！-ESP32と定型文ボタン-](https://note.com/ux_xu/n/na6c3ae041887)

そこで、今回はBOCCOとそのAPIをつかって、**送信されたメッセージBOCCOからESP32で取得できる**ようにしてみました。

※挙動がよくわかっていないところがあるので、こうした方が良さそう！、というところは随時改良してください...！

# BOCCO APIをESP32でつかうためのライブラリを改良
プログラムは[こちら](https://github.com/minwinmin/BOCCO-API-for-ESP32)にあげてあります。
プログラムにはbocco_api.cppとbocco_api.hに下記をつけくわえました。
解説は下記のコードのコメントアウトに簡単に追加していきます。

```bocco_api.cpp

/** 最新のメッセージを取得する **/
// 263 ~ 282行目
String BoccoAPI::getMessageText(){
  //GETパラメータを作る
  const String data = "access_token="+this->accessToken;
  const String url = BoccoAPI::API_ROOMS+"/"+this->firstRoomId+BoccoAPI::API_ROOMS_MESSAGES;

  //JSONを取得
  //https://api.bocco.me/alpha/rooms/{room_id}/messages?access_token={access_token}のURLでGETリクエストを送っている
  String json = this->get(url,data,BoccoAPI::RETRY_CNT);
  
  //30件のメッセージに関する情報がjsonでかえってくるので、大きめの容量を指定した。
  const size_t capacity = 50000;
  DynamicJsonDocument doc(capacity);
  deserializeJson(doc, json);
  //0番目の要素が一番古いメッセージ
  JsonObject root_29 = doc[0];
  // 30番目の要素が一番新しいメッセージ（0からのカウントなので、下記の番号は29となっている）
　// JsonObject root_29 = doc[29];
  // JSON形式のレスポンスでtextという項目にメッセージが格納されている
  const char* root_29_text = root_29["text"];
  //抽出したtextをString型に変換にして返り値に指定する
  String root_29_text_str = root_29_text;

  return root_29_text_str;
}

```

```bocco_api.h
// 19 ~ 26行目
public:
  bool createSessions();
  void setAccessToken(const char* accessToken);
  bool getFirstRoom();
  // bool getSecondRoom();
  bool postMessageText(const char* text);
  // 追加
  String getMessageText();

```

# サンプルコード

雑なサンプルコードですが下記に示します。
APIを使用するのに必要な情報は各自で用意しましょう(xxxxxxxxxと書かれている部分に記載する)。
ESP32 dev moduleについているボタンを押すとBOCCOに送信されたメッセージをコンソール画面に表示してくれます。


```c++

#include <WiFiManager.h>
#include <WiFi.h>

#include "config.h"
#include "bocco_api.h"

//BOCCO API ライブラリ
//BOCCO アカウント情報
#define BOCCO_EMAIL     "xxxxxxxxx"
#define BOCCO_PASSWORD  "xxxxxxxxx"
#define BOCCO_API_KEY   "xxxxxxxxx"
//初期設定の為のアクセスポイント名
#define AP_NAME "test"

BoccoAPI boccoAPI(BOCCO_EMAIL, BOCCO_PASSWORD, BOCCO_API_KEY);


//プッシュスイッチ
#define SW 0
#define PIN 2
#define PIN2 4

//変数初期化
int valueSW = HIGH;
int valueSW2 = 1;
int valueSW3 = 1;

//ボタン割り込み
void clickSw(){
  Serial.println("clickSw");
  valueSW = digitalRead(SW);
  Serial.println(valueSW);
}

void greetingSw(){
  Serial.println("Sw");
  //valueSW2 = digitalRead(PIN);
  Serial.println(digitalRead(PIN));
  valueSW2 = digitalRead(PIN);
}

void greetingSw2(){
  Serial.println("Sw");
  //valueSW2 = digitalRead(PIN);
  Serial.println(digitalRead(PIN2));
  valueSW3 = digitalRead(PIN2);
}

void setup() {
  Serial.begin(115200);
  Serial.println();

  WiFiManager wifiManager;
  wifiManager.setTimeout(180);
  if(!wifiManager.autoConnect(AP_NAME)) {
    Serial.println("timeout");
    delay(3000);
    //初期設定が成功シない場合 reset して初期設定をリトライする
    ESP.restart();
    delay(5000);
    return;
  }
  //ルーターとの接続に成功
  Serial.println("connected...");
  delay(1000);

  //BOCCO アクセストークンを取得する
//  if(!boccoAPI.createSessions() ){
//    Serial.println("BOCCO アクセストークン取得に失敗");
//    return;
//  }

  //アクセストークンを設定
  boccoAPI.setAccessToken("xxxxxxxxxx");

  //BOCCO 1番目のルームを取得
  if(!boccoAPI.getFirstRoom()){
      Serial.println("BOCCO ルーム取得に失敗");
      return;
  }

  //boccoAPI.postMessageText("テストテスト");

  //ボタン割り込み設定
  pinMode(SW, INPUT_PULLUP);
  attachInterrupt(SW, clickSw, CHANGE );

}



void loop() {
  if(digitalRead(SW) == LOW){
    Serial.println("test");
    Serial.println(boccoAPI.getMessageText());
  }
  delay(500);
}

```

https://arduinojson.org/v6/assistant/

すると、このように動作することが確認できます。
部屋センサが明るくなったという意味の「Brighter」がかえってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212276/fea19364-8dec-4e59-b7f2-78485ec34cd6.png)

# おわりに
BOCCO APIをつかうためのESP32用ライブラリを改良することでBOCCOからメッセージを取得することができることがわかりました。

よくわからないことが1つあります。
確実にメッセージが取得できないことです。
ESP32のボタンをおしたときに空のメッセージがかえってくることがありました。
とくに最新のメッセージに近づくほど、JSONの要素番号が大きくなるほど、例えばbocco_api.cppのdoc[29]のときメッセージが取得できる時とできない時があります。doc[0]やdoc[1]のように要素番号が若いとき取得がうまくいきやすい印象です。

APIでかえってくるJSONのデータ大きすぎるからでしょうか。

そういったところをもう少し改良する必要があります。

# ちょっとしたメモ
ArduinoJsonのライブラリをつかうとき、[ArduinoJson Assistant](https://arduinojson.org/v6/assistant/)をつかうとJSONを自動でパースしてくれて、プログラムに使える形で変換してくれるので便利です。