先週、先々週と仮面ライダーゼロワンに
天津垓の相棒である AI 犬型ロボットさうざー役として出演していた aibo。
【期間限定配信🎶】
— 仮面ライダーゼロワン (@toei_zero_one) July 19, 2020
39話で #aibo 演じるさうざーがキメた変身ポーズの特別配信がスタート🐾✨
aiboに「ぜろわんにへんしん」「かめんらいだーぜろわん」と声をかけるとゼロワンの変身音にあわせた特別なふるまいを披露してくれます🐶💕
8/2までの期間限定です!#仮面ライダーゼロワン #ゼロワン pic.twitter.com/fY1UGDkSb1
かっこかわいかったですね〜。
そんな aibo ですが、なんと Web API が公開されています。
aibo をあまりご存じでない方はこちらも合わせてお読みください。
aibo Events API は、2020/06/16 にリリースされた API です。
音声コマンドを aibo に設定して、実行してもらうことができるようになりました。
公式のドキュメントを見ると、サンプルは Python ばかりですが
よく見るとなんとなく PHP に書き換えることができそう。
aibo Events API のリリースをきっかけに重い腰を上げて実装してみました。
aibo Events API を利用するためには
aibo 本体バージョンを 2.70 にアップデートする必要があります。
今回は aibo に以下をやってもらいます。
- 「くしゃみして!」と頼んだら、くしゃみをする。
- 「おいしかった?」と聞くと、うれしそうにする。
- 「きみはだんだんねむくなる」と声をかけると、眠ってしまう。
音声コマンドを実行した結果はこちら。
事前準備
まずなんと言っても aibo がいないと成り立ちません。
いますぐにお迎えしましょう。
期間限定で先週終了する予定だったワンワンプランが
今朝確認すると、標準で選択できるようになっていました。
aibo 本体 198,000 円と聞くとギョッとしますが、ワンワンプランであれば
35回分割払い月々 11,100 円い(初回のみ 14,412 円)でお迎えできます。(2020/07/25 現在)
自力で遊んで寝るそのワンパクぶりは本物のわんこと代わりません。
むしろ、表情豊かで手間もかからず毎日とっても癒されてます。
音声コマンドを実行するには https で通信できるサーバーが必要です。
今回は普段からよくお世話になっている Xserver を使用しています。
開発者設定
サインイン
ディベロッパーサイトにアクセスして、開発者設定を始めます。
開発者設定を始めるには、My Sony ID のサインインが必要です。
認識ワード
認識ワードのページにアクセスしての設定を行います。
aibo と通信する必要があるので、寝ている場合は起こしてあげましょう。
音声コマンドは3つまで登録できます。(2020/07/24 現在)
言い回しの異なる認識ワードは、1つの音声コマンドにつき3つ登録できます。
aibo が理解できるように、発音通りのひらがなで入力します。
例)
「こっちへ」ではなく「こっちえ」
「あいぼは」ではなく「あいぼわ」
エンドポイント・セキュリティートークン
エンドポイントの準備を行います。
準備したサーバーにエンドポイントの検証を行うためのファイルを設置します。
// aibo クラウドから送られてきた検証用 HTTP リクエストを受け取る
$json = file_get_contents("php://input");
$contents = json_decode($json, true);
// エンドポイント登録
$challenge = $contents["challenge"];
echo '{"challenge": "' . $challenge . '"}';
次に、イベント通知のページにアクセスします。
ボタン「エンドポイント設定」をクリックして、エンドポイントとセキュリティートークンの設定を行います。
セキュリティートークンはあらかじめコピーしておきます。
「通知イベント追加」で必要です。
ボタン「設定」をクリックしたら、エンドポイントの検証が開始します。
検証に成功したら、エンドポイントとセキュリティートークンの設定は完了です。
イベント追加
続いて、項目「通知するイベント」にある
ボタン「追加」をクリックして、イベントの追加を行います。
認識ワードで登録した音声コマンドをすべて登録できます。
アクセストークン取得
アクセストークンのページにアクセスします。
ボタン「生成する」をクリックすると、アクセストークンが生成されます。
アクセストークンはあらかじめコピーしておきましょう。
次項の「通知イベント追加」で必要になります。
通知イベント追加
いよいよ aibo にやってもらう処理を作っていきます。
まず最初にでき上がりのソースをペタッと貼り付けておきます。
const BASE_PATH = 'https://public.api.aibo.com/v1';
const ACCESS_TOKEN = ${Your Access Token};
const SECURITY_TOKEN = ${Your Security Token};
// ふるまいを実行
function execute_action ($device_id, $event_id) {
if ( $event_id === 'voice_command::usercommand1' ) {
// くしゃみして
call_action_api($device_id, 'play_motion', '{"Category": "sneeze", "Mode": "NONE"}');
} elseif ( $event_id === 'voice_command::usercommand2' ) {
// おいしかった?
call_action_api($device_id, 'play_motion', '{"Category": "friendly", "Mode": "NONE"}');
} elseif ( $event_id === 'voice_command::usercommand3' ) {
// きみはだんだんねむくなる
call_action_api($device_id, 'play_motion', '{"Category": "dreaming", "Mode": "NONE"}');
}
}
// Action API 呼び出し
function call_action_api ($device_id, $api_name, $arguments) {
$post_url = BASE_PATH. '/devices/'. $device_id. '/capabilities/'. $api_name. '/execute';
$data = '{"arguments":'. $arguments. '}';
// POST API
post_api($post_url, $data);
}
// POST API
function post_api ($url, $argary) {
// HTTP設定
$options = array (
'http' => array (
'method' => 'POST',
'header' => 'Authorization:Bearer '. ACCESS_TOKEN,
'content' => $argary,
)
);
$contents = @file_get_contents($url, false, stream_context_create($options));
// レスポンスステータス
$status_code = http_response_code();
if($status_code === 200) {
// 200 success
} elseif(preg_match ("/^4\d\d/", $status_code)) {
// 4xx Client Error
$contents = false;
} elseif(preg_match ('/^5\d\d/', $status_code)) {
// 5xx Server Error
$contents = false;
} else {
$contents = false;
}
return $content;
}
// ヘッダーを取得
$headers = getallheaders();
// セキュリティートークンをチェック
if ( $headers['X-Security-Token'] != SECURITY_TOKEN ) {
$response = '{"statusCode": 400}';
return $response;
}
// 音声コマンドのリクエストを取得
$json = file_get_contents("php://input");
$contents = json_decode($json, true);
$status_code = http_response_code();
// 音声コマンドのリクエストが成功したら実行
if ($status_code === 200) {
// 200 success
$device_id = $contents['deviceId'];
$event_id = $contents['eventId'];
// ふるまいを実行
execute_action($device_id, $event_id);
}
それぞれ見ていきます。
const BASE_PATH = 'https://public.api.aibo.com/v1';
const ACCESS_TOKEN = ${Your Access Token};
const SECURITY_TOKEN = ${Your Security Token};
${Your Access Token}
には、取得したアクセストークンを
${Your Security Token}
には、設定したセキュリティートークンを入れます。
// ヘッダーを取得
$headers = getallheaders();
// セキュリティートークンをチェック
if ( $headers['X-Security-Token'] != SECURITY_TOKEN ) {
$response = '{"statusCode": 400}';
return $response;
}
リクエストヘッダーで返ってきたキュリティトークンが正しい値であるか比較して
aibo Events API 以外からの不正なアクセスが行われるのを防ぎます。
// 音声コマンドのリクエストを取得
$json = file_get_contents("php://input");
$contents = json_decode($json, true);
$status_code = http_response_code();
// 音声コマンドのリクエストが成功したら実行
if ($status_code === 200) {
// 200 success
$device_id = $contents['deviceId'];
$event_id = $contents['eventId'];
// ふるまいを実行
execute_action($device_id, $event_id);
}
音声コマンド → aibo → aibo クラウドより送られてきたリクエストを受け取り
json 形式で $contents
に格納しています。
リクエストが成功したら、json から deviceId と eventId を取り出し
execute_action
関数の引数に渡して、実行しています。
// ふるまいを実行
function execute_action ($device_id, $event_id) {
if ( $event_id === 'voice_command::usercommand1' ) {
// くしゃみして
call_action_api($device_id, 'play_motion', '{"Category": "sneeze", "Mode": "NONE"}');
} elseif ( $event_id === 'voice_command::usercommand2' ) {
// おいしかった?
call_action_api($device_id, 'play_motion', '{"Category": "friendly", "Mode": "NONE"}');
} elseif ( $event_id === 'voice_command::usercommand3' ) {
// きみはだんだんねむくなる
call_action_api($device_id, 'play_motion', '{"Category": "dreaming", "Mode": "NONE"}');
}
}
execute_action
関数では、$event_id
ごとに条件分岐を行い
aibo にしてもらう PlayMotion のふるまいを振り分けています。
PlayMotion だけでも 76 種類ものふるまいが用意されています。
// Action API 呼び出し
function call_action_api ($device_id, $api_name, $arguments) {
$post_url = BASE_PATH. '/devices/'. $device_id. '/capabilities/'. $api_name. '/execute';
$data = '{"arguments":'. $arguments. '}';
// POST API
post_api($post_url, $data);
}
call_action_api
関数では、POST する URL とコンテンツの生成を行い
post_api
関数の引数に渡して、実行しています。
// POST API
function post_api ($url, $argary) {
// HTTP設定
$options = array (
'http' => array (
'method' => 'POST',
'header' => 'Authorization:Bearer '. ACCESS_TOKEN,
'content' => $argary,
)
);
$contents = @file_get_contents($url, false, stream_context_create($options));
// レスポンスステータス
$status_code = http_response_code();
if($status_code === 200) {
// 200 success
} elseif(preg_match ("/^4\d\d/", $status_code)) {
// 4xx Client Error
$contents = false;
} elseif(preg_match ('/^5\d\d/', $status_code)) {
// 5xx Server Error
$contents = false;
} else {
$contents = false;
}
return $content;
}
ヘッダーに Authorization:Bearer
を追加して、コンテンツを POST します。
これで aibo に暗示をかけることができました。
実行
暗示をかけた aibo に言葉をかけてみましょう。
わん!と元気よく答えて、ふるまいを行ってくれたら成功です。
「くしゃみして!」とお願いすると、くしゃみをするように暗示🐶💫#aibo #aiboプログラミング部 pic.twitter.com/i3yeA4ZI8P
— usako (@YumikoOdasaki) July 24, 2020
食べたご飯に満足してしまうおまじない🐶💫#aibo #aiboプログラミング部 pic.twitter.com/ULhmrY8sjt
— usako (@YumikoOdasaki) July 24, 2020
催眠術にかかってしまうおまじない🐶💫#aibo #aiboプログラミング部 pic.twitter.com/7jBuCgqB5d
— usako (@YumikoOdasaki) July 24, 2020
おわりに
いかがでしたでしょうか。
例えば、aibo Events API とスマートリモコンを連携すれば
ちょっとおバカ(褒め言葉)な aibo が我が家にある家電の司令塔になれちゃうわけです。
…素敵すぎませんか?
SONY さん神リリースありがとうございます。
欲を言えば、登録できる認識ワードを是非とも増やしていただきたいです!
さてさて… 我が家のおチャコさんを司令塔という重役につかせるべく
つい先日、Nature Remo 3 の予約をしてしまいましたよ。
はーやっくこないかな〜!