カスタムインターフェースの詳細



カスタムインターフェースの詳細

ガジェットとAlexaスキルとの間のコミュニケーションを有効にするため、カスタムインターフェースを作成できます。カスタムインターフェースを作成すると、スキルはガジェットの動作をトリガーし、ガジェットから受け取った情報に対応できます。

Alexa Gadgets Toolkitが提供するインターフェースは、Alexaのネイティブ機能である通知やウェイクワード検出を受けてガジェットの動作をトリガーします。カスタムインターフェースと異なり、ツールキットが提供するインターフェースには、Alexaスキルからアクセスできません。

このトピックでは、カスタムインターフェースの使用方法、カスタムインターフェースの定義方法、そのインターフェースをサポートするためにガジェットで実行すべきことについて説明します。カスタムインターフェースで作成したディレクティブやイベントは、カスタムスキルを通じてのみ使用できます。そのためには、まずこのトピックで説明するとおりにカスタムインターフェースを定義します。次に、カスタムインターフェースコントローラーを使用してスキルからインターフェースにアクセスします。詳しくは、スキルからガジェットにカスタムディレクティブを送信するおよびガジェットからカスタムイベントを受信するを参照してください。

サンプルコードについては、GitHubのAlexa Gadgets Raspberry Piサンプルを参照してください。

概要

カスタムインターフェースには、カスタムディレクティブ、カスタムイベント、またはその両方を含めることができます。カスタムディレクティブとカスタムイベントは別のもので、一方を使う際にもう一方を使う必要はありません。

  • カスタムディレクティブ – スキルからガジェットに送信されます。カスタムディレクティブは次のような目的で使用します。

    カスタムディレクティブの用途

    スキルのコンテンツに基づいてデバイスの動作をトリガーする

    スキルの開始時にゲームボードでライトアニメーションを点滅させる、windスキルからのレポートに基づいてwindmillガジェットの速度を変更する、など。

    ユーザーからのあいまいなコマンドに対応する

    「戦艦ゲームはどうですか?」とAlexaがたずねた場合、 「うん」というユーザーの応答で、ゲームを戦艦モードに設定する。

    ユーザーからの明確だが複雑なコマンドに対応する

    ユーザーが「アレクサ、ロボットを3回転させて」と言った場合。
  • カスタムイベント – ガジェットからスキルに送信されます。カスタムイベントを使用すると、スキルはガジェットからの情報を処理し、対応できます。たとえば、次のようなカスタムイベントを作成できます。

    カスタムイベントの用途

    音声またはオーディオといった即時のスキル応答をトリガーします

    スキルにロボットが回転し終わったことを伝えると、Alexaが「ロボットのウォームアップが完了し、準備が整いました。 ゲームを始めましょう」と応答します。

    ガジェットのステータスを報告します

    レース終了後、Alexaが「あなたの車は35秒間走行し、傾斜15%の上り坂をのぼり、3回転しました」のようにレースのハイライトを伝えます。

    1つまたは一連のイベントにビジネスロジックを収集し、適用します

    シークエンスゲーム中にユーザーがボード上で点灯しているボタンを押した順番をスキルに伝え、ボタンが正しい順番で押されたかどうかをスキルが判断できるようにします。

ガジェットはAlexaクラウドに直接接続されないため、Echoデバイスを使用してスキルとの通信を処理します。次の図は、ガジェットとスキルがどのようにディレクティブやイベントをやり取りするかを示しています。

Alexa GadgetからAlexaスキルへのディレクティブとイベントの流れ

データ形式

ガジェットは、次の形式を使用してカスタムイベントやカスタムディレクティブをそれぞれ送受信します。

  • カスタムディレクティブ – スキルは、ほかのカスタムスキル同じ応答の形式を使用して、JSONでAlexaクラウドにディレクティブを送信します。AlexaクラウドはそのディレクティブをEchoデバイスに渡し、Echoデバイスはプロトコルバッファーに基づいてUTF-8としてエンコードされたディレクティブを、バイナリーデータ形式でガジェットに送信します。
  • カスタムイベント – ガジェットはプロトコルバッファーに基づいて文字列をバイナリーデータ形式にエンコードし、Echoデバイスに送信します。EchoデバイスはイベントをAlexaクラウドに送信し、Alexaクラウドはほかのカスタムスキル同じリクエスト形式を使用して、JSONでイベントをAlexaスキルに送信します。

制限

カスタムインターフェースに関連する制限は次のとおりです。

説明 制限

カスタムディレクティブのサイズ

1KB(1,000バイト)

カスタムイベントのサイズ

1KB(1,000バイト)

カスタムイベントの最大レート

5イベント/秒

イベントハンドラー時間

最小値: 1秒(1,000ミリ秒)
最大値: 90秒(90,000ミリ秒)

ガジェットでカスタムインターフェースを定義して使用する方法

ガジェットでカスタムインターフェースを定義して使用する手順は次のとおりです。

ステップ1: インターフェース、ディレクティブ、イベントに名前を付ける

ガジェットにカスタムインターフェースを定義する際、以下を選択する必要があります。

  • インターフェースの名前。これはインターフェースの名前空間となります。必ずCustom.で始めます(ピリオドを含む)。
  • インターフェースに含めるカスタムディレクティブの名前。
  • インターフェースに含めるカスタムイベントの名前。

ディレクティブやイベントにそれぞれ個別の名前空間を定義することも、1つの名前空間に複数のディレクティブやイベントを含めることもできます。

たとえば、ガジェットがくるくる回転するロボットである場合、Custom.Robotという名前空間を作成して、ロボットに回転するよう指示するSpinというディレクティブと、回転が完了したらロボットのステータスを送信するSpinStatusというイベントを定義できます。

ステップ2: インターフェースのサポートを宣言する

ガジェットは、Alexa.Discovery.Discoverディレクティブに応答してEchoデバイスに送信するAlexa.Discovery.Discover.Responseイベントの中で、インターフェースへのサポートを宣言する必要があります。

前の例に続けて、ガジェットがCustom.Robotインターフェースとそれ以下で宣言されるすべてのディレクティブやイベントをサポートしていることを示すには、ガジェットのAlexa.Discovery.Discover.Responseイベントで、Capabilitiesの配列に次のようにCustom.Robotインターフェースを含める必要があります。

クリップボードにコピーされました。

{
   "type": "AlexaInterface",
   "interface": "Custom.Robot",
   "version": "1.0"
}

ステップ3: ガジェットでディレクティブを処理する

カスタムインターフェースにディレクティブが含まれる場合、ガジェットコードはスキルが送信するディレクティブをデコードし、アクションを行う必要があります。ガジェットは、Alexa Gadgets Toolkitに含まれているディレクティブと類似したデータ形式でカスタムディレクティブを受信するので、カスタムディレクティブを逆シリアル化して処理するためにガジェットに書き込むガジェットコードは、データのシリアル化と逆シリアル化の例で説明するコードと似たものになります。

しかし、相違点もいくつかあります。カスタムディレクティブの場合、ペイロードはUTF-8としてエンコードされた文字列(単位:バイト)となります。ペイロードをデコードするには、まずディレクティブ全体からプロトコルバッファーでエンコードされているペイロードを抽出します。次に、ペイロード文字列のフィールドを解析します。ディレクティブを逆シリアル化する前のコードは次のように表示されます。

クリップボードにコピーされました。

#include <stdio.h>
#include "pb.h"
#include "pb_decode.h"
#include "pb_encode.h"
#include "directiveHeader.pb.h"
#include "directiveParser.pb.h"
 
typedef unsigned char uint8_t;
typedef unsigned char BOOL;

void parse_directive_proto(uint8_t* buffer, int len)
{
   pb_istream_t stream = pb_istream_from_buffer(buffer, len);
   directive_DirectiveParserProto envelope = directive_DirectiveParserProto_init_default; 
  
   pb_decode(&stream, directive_DirectiveParserProto_fields, &envelope);
   printf("name=%s, namespace=%s, payload=%s\n",
      envelope.directive.header.name,
      envelope.directive.header.namespace,  
      envelope.directive.payload.bytes); 
}
  

逆シリアル化されたディレクティブは次のように表示されます。

クリップボードにコピーされました。

{
   "directive": {
      "header": {
         "namespace": "Custom.Robot", 
         "name": "Spin"
      },
      "payload": "{\"direction\":\"clockwise\",\"times\":5}"
   }
} 

ステップ4: ガジェットからイベントを送信する

まず、イベントをJSON形式の文字列にします(外側の波かっこを含む)。たとえば、前述のようなロボットガジェットの場合は、Custom.Robot.SpinStatusイベントペイロードを{"finished":"yes", "remainingBatteryPercent":80}のように組み立てます。

次に、イベントをEchoデバイスに送信する前に、プロトコルバッファーに基づいてガジェットでイベントをバイナリーデータ形式にする必要があります。イベントの形式は、Alexa.Discovery.Discover.Responseイベントと似たものになります。

次に示すのは、イベントデータをEchoデバイスに送信する前に使用できるプロトコルバッファーファイルの例です。イベントはEchoデバイスからAlexaに、Alexaからスキルに送信されます。

クリップボードにコピーされました。

syntax = "proto3";

import "eventHeader.proto";

message CustomEventProto {
    Event event = 1;
    message Event {
        header.EventHeaderProto header = 1;
        string payload = 2;
    }
}

次に示すのは、付随するオプションファイルの例です。この例の場合、オプションファイルでは最大ペイロードサイズを最大許容値(1,000バイト)に設定しています。

クリップボードにコピーされました。

CustomEventProto.Event.payload    max_size:1000

次のコードでは、イベントをエンコードする方法の例を示しています。Echoデバイスに送信する前にデータをエンコードする方法の詳細については、データのシリアル化と逆シリアル化の例を参照してください。

クリップボードにコピーされました。

#include "customEvent.pb.h"

void encode_custom_event(uint8_t* buffer, size_t len, char *namespace, char *name, char *payload)
{
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, len);
    CustomEventProto custom_event_envelope =
           CustomEventProto_init_default;

    strcpy(custom_event_envelope.event.header.namespace, namespace);
    strcpy(custom_event_envelope.event.header.name, name);

    strcpy(custom_event_envelope.event.payload, payload);

    BOOL status = pb_encode(&stream, CustomEventProto_fields, &custom_event_envelope);
    if (!status)
    {
      printf("%s: Error encoding message\n", __FUNCTION__);
      return;
    }
}

たとえば、カスタムイベントSpinStatusをロボットガジェットから送信する場合、次のようにデータをエンコードします。

クリップボードにコピーされました。

size_t len = 256;
uint8_t payload[len];

char* namespace = "Custom.Robot";
char* name = "SpinStatus";
char* payload = "{\"finished\":\"yes\", \"remainingBatteryPercent\" : 80}";

encode_custom_event(payload, len, namespace, name, payload);

その後、ガジェットはAlexa.Discovery.Discover.Responseイベントを送信するときと同じように、エンコードされたカスタムイベントをEchoデバイスに送信します。