Skip to content

Latest commit

 

History

History
430 lines (315 loc) · 26.8 KB

README_python_ja.md

File metadata and controls

430 lines (315 loc) · 26.8 KB

サンプルアプリ「気分屋aibo」について紹介していきます。まずはここからはじめていきましょう!

⚠️ 注意:

本ページで紹介している手順や、webページ、画面はすべて公開当時のものです。最新版では、UIが変わっている可能性があります。ご注意ください。

現在公開されているサンプルコードは、複数のaiboが登録されているアカウントに対応できていない部分があります。あらかじめご了承ください。

気分屋aibo

下記のような流れで、サンプルアプリ「気分屋aibo」について解説しながら、実際に開発をしていきます。まずはこのアプリを動かしてみたい、という方は、開発手順の項目からはじめてください。

準備

まずは、GitHubリポジトリから本サンプルアプリのソースコードをダウンロードします。ダウンロードができたら、好きなディレクトリに展開しておきましょう。

サンプルアプリ「気分屋aibo」とは

サンプルアプリ「気分屋aibo」とは、aiboに「おはよう」と言うと、aiboの気分に応じてさまざなふるまいを実行してくれるシンプルな連携アプリです。

開発内容:

  • aiboが検知した言葉を外部に通知する仕組み(Events API)を使い、aiboが「おはよう」と言われたときに、aiboの気分に応じて、とっても喜ぶ顔を洗う仕草をするブルッと震えるのいずれかのふるまいを実行させます。(Action API)
  • 「気分屋aibo」のアプリについて紹介し、連携を促すwebページを作成します。このページから「連携する」ボタンを押すと、下図「連携画面の流れ」のように連携が進むようにします。
気分屋aiboの紹介ページ

システム構成

本アプリでは、Google Cloud Platform (GCP) *1を利用しています。本システムの構成を下記に示します。

システム構成図

上記図中の濃い青色で囲われた箇所は、実際に開発していくwebアプリの、バックエンド/フロントエンドにあたります。また、図中のaibo Cloudは既に用意されているサーバーで、aiboとwebアプリを中継する存在です。

  • フロントエンド

    • Cloud Storage
      • 気分屋aiboの顔となるページです。気分屋aiboについてオーナーに紹介し、連携を促します。このページに配置されている「連携する」ボタンを選択することで、実際に連携が開始されます。
  • バックエンド

    • Cloud Functions
      • 連携アプリと、オーナーのaiboを実際に連携させる機能を担います。
      • aibo からのイベント通知を受け取ります。イベントに応じたふるまいをaiboに指示する役割があります。
    • Firestore
      • 連携中のaiboに関する情報を保存します。たとえば、deviceIdaccess tokenなどがこれにあたります。
  • 外部サーバー

    • aibo Cloud
      • Events API、 Action APIの接続先となります。aiboからのイベント検知、aiboへの動作指示の中継を行います。
      • Cloud Functionsでデプロイしたサーバーの認証を行います。

(*1) コラム: GCP (Google Cloud Platform) とは Google が展開するクラウドサービスです。GCPでは、web開発に必要な多種多様なツールがクラウド経由で提供されています。例えば、GCPサービスの一つであるCloud Functionsを使えば、サーバーの構築/保守などについて意識することなく、アプリケーションを実行できるようになります。またCloud Functionsは使用された分のみの従量課金制となるため、個人開発の規模であれば低額な料金で利用することができます。(料金については、必ずご自身で公式ページをご確認ください)

ファイル構成

ファイル構成は、下記の通りです。大まかにはGCPのサービスごとに(Cloud Functions、Cloud Storage)フォルダーが分かれています。

.
├── CloudFunctions
│   ├── aibo_api_ctrl.py
│   └── main.py
│   └── requirements.txt
└── CloudStorage
    └── callback.html
    └── index.html
  • CloudFunctions/main.py

    • 気分屋aiboのバックエンド側メイン処理になります。連携やAction API、Events APIなど、すべての処理の大枠がここに書かれています。
  • CloudFunctions/aibo_api_ctrl.py

    • main.pyaibo_api_ctrlとして読み込まれるコードです。main.pyにて実行する内容の詳細が記述されています。
  • CloudFunctions/requirements.txt

    • GCPへのデプロイ(*2)時に必要な設定が書かれています。
  • CloudStorage/index.html

    • 気分屋aiboのトップページとなるhtmlファイルです。連携アプリのエントリーURLとして設定されます。
    • フロンドエンドのコードでは、簡単にUIを構築するための CSS フレームワークとして Bootstrap を利用しています。
  • CloudStorage/callback.html

    • 認証完了後に、リダイレクトされるページです。リダイレクトURLとして設定されます。
    • 認証処理後の結果(認証完了認証エラー通信エラーなど)を提示します。

(*2) コラム: デプロイとは デプロイとは、プログラムやファイルなどを実際に動かせる状態にすることを言います。pythonファイルやhtmlファイルを単に作成するだけでは、インターネット上で実際に動作する状態にはなりません。作成したファイルが動作するように様々な設定をすることを「デプロイ」 (日本語訳:配備・配置)といいます。

コード解説

バックエンドの処理内容を、実行の流れに沿って解説していきます。

1. 外部からのリクエスト処理をメイン関数で受け取り、その内容を読み取る

CloudFunctions/main.py

# ..(省略)..
def hello_world(request):
   # ..(省略)..

   # リクエスト情報の取得
   request_json = request.get_json()
   print(request_json)

hello_world()に書かれている内容が、本サンプルアプリのメイン処理となります。 hello_world()は、外部からのリクエスト情報(後述)がhello_world()の引数requestに格納されて、呼び出されます。 まずは、このrequestの内容をjson形式に変換し、プログラムで読み取れる状態にします。

2. リクエストの内容に応じて、実行する処理を振り分ける

CloudFunctions/main.py

# ..(省略)..

# エンドポイントの検証
if 'eventId' in request_json and request_json['eventId'] == 'endpoint_verification':
   print("エンドポイントの検証")
   return request_json

# aibo APIの実行
if 'eventId' in request_json:
   print("aibo APIの実行")
   res = aibo_api_execute(request_json)
   # レスポンス
   if res:
      headers = {
      }
      return ('Success!', 200, headers)
   else:
      headers = {
      }
      return ('Failed', 500, headers)

# OAuth認証
if 'code' in request_json:
   print("連携処理の実行")
   aibo_oauth_execute(request_json)
   # ..(省略)..
   return ('Success!', 200, headers)

json形式に変換したrequest_jsonに応じて、実行する内容を振り分けます。下記3つの処理のうち1つを実行します。

3. aibo APIの実行

CloudFunctions/main.py

# ..(省略)..

def aibo_app(access_token, device_id, eventId):
   # 「おはよう」と言われたとき
   if eventId == 'voice_command::goodmorning':
      # aiboの気分を0から2の整数でランダムに設定
      kibun = random.randint(0, 2)

      # 気分に応じてふるまいを実行
      if kibun == 0:
         print("とっても喜ぶ")
         res = aibo_api_ctrl.aibo_control_sync(access_token, device_id, 'play_motion', '{"Category":"overJoyed","Mode":"NONE"}') # とっても喜ぶ
      elif kibun == 1:
         print("顔を洗う仕草をする")
         res = aibo_api_ctrl.aibo_control_sync(access_token, device_id, 'play_motion', '{"Category":"washFace","Mode":"NONE"}') # 顔を洗う仕草をする
      else:
         print("ブルッと震える")
         res = aibo_api_ctrl.aibo_control_sync(access_token, device_id, 'play_motion', '{"Category":"jiggle","Mode":"NONE"}') # ブルッと震える
      return res
   else:
      return True

実際にaiboにAPI実行を指示している処理について解説します。

  • aibo_appという関数の引数eventIdに、aiboが検知したイベントの内容が伝えられます。
  • 上記のeventIdを見て、「おはよう」と言われた場合にだけ、aiboに指示を出すようにします。
  • aiboの気分は、0から2の整数でランダムに設定します。このランダムな数字に応じて、実行する内容を決めます。
  • aiboに指示する内容は、aibo_control_syncという関数で指定します。
  • aiboに指示する内容を上記の関数に渡すと、関数内部でAction APIが呼ばれaiboがふるまいを見せてくれます。

開発手順

気分屋aiboは、下記の手順で開発していきます。

手順 内容 作業場所
1 気分屋aiboを連携アプリとして登録する aibo デベロッパーサイト
2 気分屋aiboの認証情報をコードに反映する ローカルフォルダー(./CloudFunctions
3 気分屋aibo をデプロイする Google Cloud Platform, ローカルフォルダー(./CloudFunctions, ./CloudStorage
4 aibo CloudにGCPエンドポイントの通知先を設定する aibo デベロッパーサイト
5 aibo Cloudへ通知するイベントを設定する aibo デベロッパーサイト

作業内容をaibo デベロッパーサイトの図と対応させて図示すると、下記のようなイメージになります。 開発手順

1. 気分屋aiboを連携アプリとして登録する

aibo デベロッパーサイトの開発者設定へサインインします。 作成した連携アプリの項目をクリックして、「新しく連携アプリを作成する」ボタンをクリックします。

開発者設定・連携アプリ新規作成画面

連携アプリ名や、連携アプリの説明を入力していきます。 ここまでで、気分屋aiboを連携アプリとして登録し、実際に開発を行う準備が整いました。

TIP: 上記の連携アプリの情報を設定した段階では、連携アプリ一覧に公開されることはありません。ここで入力した内容は別途「掲載申請」を行って審査に合格すると公開されます。詳しくはデベロッパーサイトの連携アプリの掲載申請を参照してください。

2. 気分屋aiboの認証情報をコードに反映する

  1. 気分屋aiboを連携アプリとして登録した際に生成された、クライアントIDクライアントシークレット をコピーし、手元のメモ帳などに記しておきます。

    認証情報の取得画面

    💡 開発のポイント1:

    POINT1: クライアントIDクライアントシークレットは今後複数回使用します。分かりやすいようにメモしておきましょう!

  2. サンプルコードを修正します。

    • CloudFunctions/main.py を編集し、CLIENT_IDCLIENT_SECRET を1.でコピーした値に書き換えます。

      CloudFunctions/main.py 10行目

      # 連携アプリの情報
      CLIENT_ID = 'XXX'
      CLIENT_SECRET = 'XXX'

    まだソースコードをダウンロードしていない場合は、GitHubリポジトリからソースコードをダウンロードして、好みのフォルダーへ展開してから、編集しましょう。

3. 気分屋aibo をデプロイする

ここからはGCPを使いながら、作業するフェーズにうつります。新しいプロジェクトを追加し、Firestore、Cloud Functions、Cloud Storage をそれぞれ準備します。

  1. 新しいプロジェクトの追加

    • GCPにログインします。Google Cloud Platform
      • Googleアカウントを持っていない方は、アカウントを作成してからGCPにログインしてください。
      • Googleアカウントをすでに持っている方でも、Google Cloud Platformへの登録とクレジットカードの登録が必要になります。
    • 「aiboSample」という名前で新しいプロジェクトを追加します。
      • Google Cloud Platform の右横にあるボタン(下図)を選択します。

        新規プロジェクト選択画面
      • プロジェクト選択のポップアップが出たら、新しいプロジェクトボタンを押します。

      • プロジェクト名を「aiboSample」として作成します。

  2. Firestore の準備

    • コンソール画面の上部にある検索ボックスに「Firestore」と入力して、Firestoreのプロダクトを選択します。

      検索ボックスからFirestoreを選択する方法の解説
    • Firestoreのモードを選択する画面が現れたら、ネイティブモードを選択します。

    • デプロイするロケーションを選択します。

      • 好きなロケーションを選択して、データベースを作成します。ここで選択したロケーションに実際のデータが配置されます。

      NOTE: 選択したロケーションによっては、料金が発生する可能性があります。無料枠での利用に適したロケーションの確認には、Google公式サイトを参考にしてください。

    • データベースを作成しています。と表示されている間は数分間待ちましょう。リダイレクト先に空のデータベースが作成されれば、このステップの準備は完了です。

      Firestore設定完了後画面
  3. Cloud Functions の準備

    • コンソール画面の上部にある検索ボックスに「Cloud Functions」と入力して、Cloud Functionsのプロダクトを選択します。

      検索ボックスからCloud Functionsを選択する方法の解説
    • 関数を作成を押します。

    • はじめてCloud Functionsを使用する場合には、必要なAPIを有効化します。

    • 関数を下記のように設定します。

      • 関数名: my-linkable-app
      • リージョン: Firestoreと同じ地域を選択
      • トリガータイプ: HTTP
      • 未認証の呼び出しを許可
      • HTTPSが必須にチェック
    • 下記のような画面に遷移します。

      Cloud Functions 設定画面
    • Cloud Build APIについての警告が出る場合は、APIを有効にするをクリックして、Cloud Build APIを有効にします。 Cloud Build APIの有効化画面

    • 元の画面に戻り、関数内で使用する言語(ランタイム)を、Python 3.9に設定します。

    • 次に、ローカルにあるCloudFunctionsフォルダーの中の、main.pyrequirements.txtaibo_api_ctrl.pyをクラウド上にアップロードします。

      • main.pyrequirements.txtについては、ローカルのコードをそれぞれコピーして、クラウド上ファイルにペーストします。
      • aibo_api_ctrl.pyは、+(プラス)ボタンを押して新しくファイルを作成してから、ローカルのファイルの内容をペーストします。
      • デプロイボタンを押します。

      TIP: デプロイが完了するには数分間かかる場合があります。しばらく待ちましょう:tea:

    • 関数がデプロイできたら、デプロイ先のURLをメモします。

      • "my-linkable-app"をクリックして、関数のダッシュボードページを開き、トリガータブを選択してトリガーURLをコピーします。
      トリガー URLの確認画面

      💡 開発のポイント2:

      POINT2: 今コピーしたトリガーURLが、認証許可エンドポイントのURLになります。"エンドポイントURL"としてメモしておきましょう。

  4. Cloud Storage の準備

    • コンソール画面の上部にある検索ボックスに「Cloud Storage」と入力して、Cloud Storageのプロダクトを選択します。

      検索ボックスからCloud Storageを選択する方法の解説
    • バケットを作成ボタンを押し、下記の条件で新しいストレージを作成します。リージョンについてはFirestore、Cloud Functionsと同じ、もしくは近い場所を選択してください。

      • バケット名: my-linkable-app_XXX (*3)
      • ストレージクラス: Standard
      • アクセス制御: 均一

      なおバケットに対する公開アクセス禁止は適用しません。チェックボックスには、チェックを付けずに進みます。

      (*3) バケット名について バケット名は、リージョンごとに一意の名前が必要です。(他のユーザが既に使用している名前は使用できません。) XXXには、123など好きな数字を入れておきましょう。

    • インターネット上から誰でもアクセスができるように、権限の設定を行います。

      • 権限のタブをクリックし、権限を追加ボタンを押します。
      • 新しいプリンシパルに、allUsersと入力して、ロールにStorage オブジェクト閲覧者と入力します。
      Cloud Storage権限設定画面
    • ローカルのCloudStorage/callback.html を編集します。

      • コード内の認証認可エンドポイントを、開発のポイント2でメモしたエンドポイントURLに書き換えます。

        CloudStorage/callback.html 111行目

        const auth_endpoint = `https://xxx`
    • オブジェクトタブをクリックし、編集したcallback.html をCloud Storage にアップロードします。

      • アップロードされたらcallback.htmlを選択し、公開URLをコールバックURLとしてメモしておきましょう。
    • CloudStorage/index.html を編集します。

      • コード内の下記2つの変数をメモ帳の値に書き換えます。

        • client_idを、クライアントIDに書き換えます。
        • redirect_uriを、コールバックURLに書き換えます。

        CloudStorage/index.html 170行目

        const client_id = 'XXX';
        const redirect_uri = 'https://xxx';
        const region = 'JP';
    • CloudStorage/index.htmlをCloud Storage にアップロードします。

      • アップロードされたらindex.htmlを選択し、公開URLをフロントページURLとしてメモしておきましょう。
    • CloudStorage/image以下のpngファイル群をCloud Storage にアップロードします。CloudStorage/imageのフォルダーごとドラッグ&ドロップしてアップロードできます。

      Cloud Storageへのファイルアップロード完了後イメージ

    💡 開発のポイント3:

    POINT3: "Cloud Storage の準備"の項目では、新しく2つのURLをメモしました。(コールバックURL, フロントページURL)

    🚩 「気分屋aibo のデプロイ」のまとめ:

    well done!: おつかれさまです! ここまでで「気分屋aibo をデプロイする」が完了しました。 これで気分屋aiboのフロント・バックエンド両方がインターネットから実際にアクセスできる形になったはずです。これ以降は、この両方のリソースとソニーが提供するaibo Cloudをつなぐ設定に移ります。つなぐ設定をすることで、今回デプロイしたリソースとaibo Cloudが連携して動作するようになります。

4. aibo CloudにGCPエンドポイントの通知先を設定する

aibo デベロッパーサイトで、連携アプリに必要な設定を行います。

  1. エンドポイントの設定を行います。

    • 今回作成した、[アプリ名]の連携アプリ設定のページに進みます。

      エンドポイント設定画面
    • エンドポイントに、エンドポイントURLとしてメモしたURL(Cloud Functionsへのデプロイ先)を設定します。

      https://xxx
      
    • エンドポイントを設定すると、エンドポイントの検証が行われ、検証に成功すると登録が完了します。

  2. 連携アプリのサーバー設定をします。

    最後に、下記の画面のようにサーバー設定のタブを開き、編集ボタンを押して下記3つのURLを記入します。

    • 連携アプリのエントリーURL に、 フロントページURLを設定
    • 認証後のリダイレクトURL に、 コールバックURLを設定
    • 連携中のアプリのURL に、 フロントページURLを設定
    連携アプリのサーバー設定画面

5. aibo Cloudへ通知するイベントを設定する

  • Cloud Functionsへデプロイした関数に通知するイベントを追加します。
  • 本サンプルアプリでは、音声コマンドgoodmorningを選択して追加します。
    • イベント通知のタブから、通知するイベントの追加ボタンをクリックします。
    • 音声コマンド項目からgoodmorningを選び、追加します。
    イベント通知設定

動作確認

ここまで来れば、実際に気分屋aiboが動作する準備が整いました。ここからは、期待通りに動作するか確認していきましょう。

気分屋aiboと連携する
  1. メモしておいたフロントページURLをWebブラウザで開きます。
  2. 「気分屋aibo」のwebページが表示されたら、aiboを連携する ボタンを押します。
  3. 以下のような流れでページが遷移し、連携完了ページが表示されれば、連携完了です。

気分屋aibo連携時の画面遷移

気分屋aiboを動かす
  1. (任意)aiboを指示待ち状態にします。

    「気分屋aibo」アプリによる動きを確認しやすくするため、aibo ビジュアルプログラミングを使って、aiboを「指示待ち中」にします。

    • aibo ビジュアルプログラミングにサインインします。
    • ブロックが並んでいる左側のタブから、指示待ち中になるブロックを選択します。
      • 指示待ち中になるブロックは、動きという区分に配置されています。下の方までスクロールして探してみましょう。
    ビジュアルプログラミングの操作画面
    • aiboが指示待ち状態に入ると、オーナーからの指示を待機する状態に入ります。
  2. 「おはよう」と言うと、aiboが下記のうちいずれかのふるまいをしてくれます。

    • とっても喜ぶ
    • 顔を洗う仕草をする
    • ブルッと震える