Alexaで365スケジュール読み上げ機能をAutomateで作る

#2021年4月29日　更新
スケジュールの開始時刻も読み上げるようバージョンアップしました。

#はじめに
###Amazon echo 使ってますか？
我が家は、家電のON/OFF、天気予報やニュースの読み上げ、食事や運転や睡眠中のBGM、fire tv stickとの連携・・・etc.
本格的なリモートワークにシフトした今では、生活には欠かせない必需品です。

そんなechoの頭脳ともいえるAlexaに、O365 の予定表を読み上げてもらうことで、いつでもどこでも、声だけでスケジュールの確認をしてみたいと思いつきました。

本ツール作成の作成には、Microsft MVPのJunichi Kodamaさん（@KodamaJn）の[(1. Alexa スキル編) 買い物メモを Alexa から LINE に送信する仕組みを Power Automate で作る](https://jn.hateblo.jp/entry/2020/09/11/234026)を大変、大いに参考にさせていただきました。
いつもありがとうございます

#概要
以下の構造で構成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/596ed9e3-4184-f9c2-bf4c-883d396b7238.png)


①「スケジュールの確認」というスキルを作成し、AutomateへリクエストをPosting
②Automateフローでカレンダスケジュールを取得
③スキルに取得したスケジュールを読み上げるよう応答

実際にはこんな感じです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Alexaで365のスケジュールを読み上げるスキル、バージョンアップしました。<br>記事も更新しました。<a href="https://t.co/9vsiWiA9Vw">https://t.co/9vsiWiA9Vw</a> <a href="https://t.co/mJKozTd32c">pic.twitter.com/mJKozTd32c</a></p>&mdash; Miyake Mito (@MiTo60448639) <a href="https://twitter.com/MiTo60448639/status/1387703373596708864?ref_src=twsrc%5Etfw">April 29, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

それでは実際に作成していきます。

#Alexa スキルの作成


alexa developer consoleにて作成します。
Junichi Kodamaさん（@KodamaJn）の[(1. Alexa スキル編) 買い物メモを Alexa から LINE に送信する仕組みを Power Automate で作る](https://jn.hateblo.jp/entry/2020/09/11/234026)にて大変丁寧に解説されていますので、参考にスキルを作成してください。
ただし、今回は呼びかけと応答は1つのみですので、スロットの定義は不要です。
またサンプル発話も一つだけ設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1c1932c0-9be8-4dad-5e0c-388355e2d1b2.png)

スキルの呼び出し名も任意ですが、今回は「スケジュールの確認」としておきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7d4383fa-72a4-f67f-02b7-6ce1c99fdcdc.png)

#Automate フローの作成
Automateにて、365のスケジュールを取得し、Alexaスキルに応答するフローを作成します。
こちらも、Junichi Kodamaさん（@KodamaJn）の[(3. Power Automate 編) 買い物メモを Alexa から LINE に送信する仕組みを Power Automate で作る](https://jn.hateblo.jp/entry/2020/09/14/130624)にて丁寧に解説されていますので、参考にしてください。

全体像です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a4b5c482-2b95-8411-2168-280a5cd6ddc2.png)


###HTTP要求の受信時
トリガーに「HTTP 要求の受信時」を選択し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a62e6b78-4047-bc5b-53c4-92f6b6400d5e.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/2fc8eb59-5c58-89ad-3b5c-2aa4364fd1b9.png)
「サンプルのペイロードを使用してスキーマを作成する」に下記を入力し、JSONスキーマの定義を作成します。

```
{
    "type": "object",
    "properties": {
        "version": {
            "type": "string"
        },
        "session": {
            "type": "object",
            "properties": {
                "new": {
                    "type": "boolean"
                },
                "sessionId": {
                    "type": "string"
                },
                "application": {
                    "type": "object",
                    "properties": {
                        "applicationId": {
                            "type": "string"
                        }
                    }
                },
                "attributes": {
                    "type": "object",
                    "properties": {
                        "locale": {
                            "type": "string"
                        }
                    }
                },
                "user": {
                    "type": "object",
                    "properties": {
                        "userId": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "context": {
            "type": "object",
            "properties": {
                "Viewports": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "type": {
                                "type": "string"
                            },
                            "id": {
                                "type": "string"
                            },
                            "shape": {
                                "type": "string"
                            },
                            "dpi": {
                                "type": "integer"
                            },
                            "presentationType": {
                                "type": "string"
                            },
                            "canRotate": {
                                "type": "boolean"
                            },
                            "configuration": {
                                "type": "object",
                                "properties": {
                                    "current": {
                                        "type": "object",
                                        "properties": {
                                            "mode": {
                                                "type": "string"
                                            },
                                            "video": {
                                                "type": "object",
                                                "properties": {
                                                    "codecs": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            },
                                            "size": {
                                                "type": "object",
                                                "properties": {
                                                    "type": {
                                                        "type": "string"
                                                    },
                                                    "pixelWidth": {
                                                        "type": "integer"
                                                    },
                                                    "pixelHeight": {
                                                        "type": "integer"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        "required": [
                            "type",
                            "id",
                            "shape",
                            "dpi",
                            "presentationType",
                            "canRotate",
                            "configuration"
                        ]
                    }
                },
                "Viewport": {
                    "type": "object",
                    "properties": {
                        "experiences": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "arcMinuteWidth": {
                                        "type": "integer"
                                    },
                                    "arcMinuteHeight": {
                                        "type": "integer"
                                    },
                                    "canRotate": {
                                        "type": "boolean"
                                    },
                                    "canResize": {
                                        "type": "boolean"
                                    }
                                },
                                "required": [
                                    "arcMinuteWidth",
                                    "arcMinuteHeight",
                                    "canRotate",
                                    "canResize"
                                ]
                            }
                        },
                        "mode": {
                            "type": "string"
                        },
                        "shape": {
                            "type": "string"
                        },
                        "pixelWidth": {
                            "type": "integer"
                        },
                        "pixelHeight": {
                            "type": "integer"
                        },
                        "dpi": {
                            "type": "integer"
                        },
                        "currentPixelWidth": {
                            "type": "integer"
                        },
                        "currentPixelHeight": {
                            "type": "integer"
                        },
                        "touch": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        },
                        "video": {
                            "type": "object",
                            "properties": {
                                "codecs": {
                                    "type": "array",
                                    "items": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                },
                "System": {
                    "type": "object",
                    "properties": {
                        "application": {
                            "type": "object",
                            "properties": {
                                "applicationId": {
                                    "type": "string"
                                }
                            }
                        },
                        "user": {
                            "type": "object",
                            "properties": {
                                "userId": {
                                    "type": "string"
                                }
                            }
                        },
                        "device": {
                            "type": "object",
                            "properties": {
                                "deviceId": {
                                    "type": "string"
                                },
                                "supportedInterfaces": {
                                    "type": "object",
                                    "properties": {}
                                }
                            }
                        },
                        "apiEndpoint": {
                            "type": "string"
                        },
                        "apiAccessToken": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "request": {
            "type": "object",
            "properties": {
                "type": {
                    "type": "string"
                },
                "requestId": {
                    "type": "string"
                },
                "timestamp": {
                    "type": "string"
                },
                "locale": {
                    "type": "string"
                },
                "reason": {
                    "type": "string"
                }
            }
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ea4ffa2f-2f16-ecab-4dc4-a3e174b090cf.png)


###スケジュールイベントの取得
Office 365 Outlookより「イベントのカレンダービュー」を取得を選択し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/abd252bd-882f-6a31-0d7d-c787a6ca7c5d.png)

自身の予定表を選び、開始時刻と終了時刻を入力します。
下記の設定ですと、今から1日間のスケジュールを取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/bee37c94-96d1-50b9-3415-056ae7684ff2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/e6c65c00-a9d3-b5cb-e088-3d60946f3145.png)

スケジュールを開始時間順で取得したいので、並び替えに"start/dateTime"を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/41e1623d-a74e-f527-9411-5940d1b07983.png)


###スケジュールの件名を取得
上記で取得した複数のスケジュールより、件名のみを取得します。
ここでも、[Applay to eachを回避](https://mofumofupower.hatenablog.com/entry/2020/08/12/093000)し、処理の高速化を図ります。
データ操作の選択を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/438f5a0f-269d-e73e-2cee-010bed782cbf.png)

開始には、イベントのカレンダービュー取得より、Value
マップには、予定の開始時刻と件名をセットします。
開始時刻は下記を入力してください。

```
concat(substring(convertTimeZone(item()?['start'],'UTC','Tokyo Standard Time'),0,10),' ',substring(convertTimeZone(item()?['start'],'UTC','Tokyo Standard Time'),11,5))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/3f8fdbaf-9e30-4f90-9d20-c2ed56f688a7.png)


さらに、データ操作の参加を選び、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4ec1523b-3732-0b3c-fc67-4d8bbcaa2258.png)
上記の選択の結果を「と」という文字で結合していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/54d77a16-e3f8-5839-fbf3-32811e4a5042.png)

###Alexaへ応答
要求の応答を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/412a7fa1-0ee3-9c11-e663-bfe9ca1d0361.png)

ヘッダーに

```
Content-Type
application/json;charset=utf-8
```

本文に

```
{
  "response": {
    "outputSpeech": {
      "text": "［結合の出力］",
      "type": "PlainText"
    },
    "reprompt": {
      "outputSpeech": {
        "text": "［結合の出力］",
        "type": "PlainText"
      }
    },
    "shouldEndSession": true
  },
  "version": "1.0"
}
```

を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4407c602-f53a-a5b5-8858-3c0d8da2a5ab.png)

#エンドポイントの取得
作成したフローを保存し再度開くと、トリガーのHTTP要求の受信時にある「HTTP POST の URL」の値をコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6d407247-4624-3ea3-f271-395d50c5bbd3.png)

alexa developer consoleに戻り、エンドポイントを選択し、HTTPSを選択し、デフォルトの地域に上記のURLをペーストします。
さらに、「開発用のエンドポイントは、証明機関が発行したワイルドカード証明書をもつドメインのサブドメインです」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/b4758190-b9ef-eec0-0c99-fc6383bfb37c.png)

以上で設定は完了です。

#まとめ
「あれ、この後のスケジュールって何があったっけ？」といった時に役に立つスキルだと思います。
必要なスキルは自分で作る、ぜひ実感ください。