もはや朝のTeamsの挨拶すら怠い人向けのPower Automateのすゝめ

# はじめに
ハイブリッドワークで、
**とりあえず朝はTeamsで挨拶しようぜ！** という
会社もあるのではないでしょうか。

 - 打刻を打つ
 - Teamsで連絡する

 なに、この二重作業
 **本当に嫌なので自動化チャレンジ**

# 実現したいこと
**Teamsでの挨拶を手軽にする**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/62636895-6b36-3e74-d40c-c34d1d874a39.png)

- 「おはようございます。勤務開始します。本日は出社しています。」
- 「勤務終了します。」

とりあえずこのパターンで考えます。

「打刻」もできたらいいのですが、APIの領域ですね。
一旦割愛です。

# Power Automateで出来ること
Power Autmateはモバイルアプリが用意されています。

https://learn.microsoft.com/ja-jp/power-automate/introduction-to-button-flows#trigger-an-instant-flow

- **Android**

https://play.google.com/store/apps/details?id=com.microsoft.flow&referrer=utm_source%3Ddocs%26utm_medium%3Dcpc%26anid%3Dadmob&pli=1

- **iOS**

https://apps.apple.com/app/apple-store/id1094928825

- **Windows Phone**

https://apps.microsoft.com/store/apps?hl=en-us&gl=US

### モバイルアプリの画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/036d205e-44ff-64db-1e8a-b655bde9f215.png)

キャッチーなボタンですね。
私はiphoneユーザーなので`ショートカット`という**iOSの機能も交えると、よりCool。**

平日の朝、家で大体始める時間帯か、会社についたときにPower Automateのアプリを開くショートカットを仕込みます。
アプリを探して立ち上げるのも手間ですからね。

## 必要な情報
さて固定的な部分はなんでしょうか？
整理します。

 - 勤務開始の場合
    - 「おはようございます。勤務開始します。」
    - 「お疲れ様です。勤務開始します。」

 - 勤務終了の場合
     - 「お疲れ様です。勤務終了します。」

とします。
本日は早めに失礼します。など個別の時は手作業。

そして上記に
- 「在宅勤務です。」
- 「出社しています。」

を追加します。

## 条件を整理する

 - 勤務開始について
     - おはようございます。 - 5:00 ~ 11:00開始の場合
     - お疲れ様です。 - 上記以外

なるべく条件はシンプルにしましょう。

 - 勤務終了について
     - こちらは条件分岐がなし。

こころを込めたメッセージはしっかりと入力した方が良いでしょう。

 - 勤務場所について（在宅 or 出社）
     - 現在地が自宅の場合、在宅
     - 勤務先の場合、出社

という分岐ができます。他のワーキングスペースをよく使う場合は、その情報に応じた分岐が必要ですね。

# 想定する状況
Teamsにおける勤怠に関する共有は、下記の状況と想定して書きます。
 - チーム - チャネル

グループチャットではない想定ですね。
**雑ですが「gatsuo」というチームに「勤怠」というチャネルを設けます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/d7b8eb46-c4d7-f132-2409-4e7e0f838a75.png)

このケースの場合、一つのメッセージに、Replyする形で最初の人からメッセージが積みあがってきますね。

 - **その日に既にメッセージは存在するか**
 - **リプライする場合はIdは何か**

これらの情報が必要がです。

ここで登場するアクションが
Teams コネクタの`メッセージを取得する`
です。

https://learn.microsoft.com/ja-jp/connectors/teams/#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B

チャネルの**メッセージのオブジェクトを格納した配列**が取得できます。
ここから**ID**と**作られた時間**を特定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/825846a0-acd0-a5bb-e5d5-5715bf964bf7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/d9f3d9f3-32d2-0bdb-6f21-c3916f5830b3.png)

`id`と`createTime`から必要な情報が確認できますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/8bb8b5c0-0dc3-8a4e-c28b-da32c0bd2d40.png)

 - 当日と同じ場合は、私は最初に投稿する人 ※タイムゾーンの課題はあります
 - そうでない場合は、リプライする人

と見分けられます。

ここで、最初の`条件分岐`が割り出せます。

最新の投稿を判断するには、first関数または添え字`インデックス`で、
`最初のオブジェクトを取得する`必要があります。

```plaintext:関数の場合
first(outputs('メッセージを取得します')?['body/value'])
```

```plaintext:インデックスで指定
outputs('メッセージを取得します')['body/value'][0]
```

さらに`id`や`createDateTime`を取得する場合は、
```plaintext:関数の場合
// id
first(outputs('メッセージを取得します')?['body/value'])?['id']

// createDateTime
first(outputs('メッセージを取得します')?['body/value'])?['createdDateTime']
```

```plaintext:インデックスで指定
// id
outputs('メッセージを取得します')['body/value'][0]['id']
// createDateTime
outputs('メッセージを取得します')['body/value'][0]['createdDateTime']
```

これで文字列でタイムスタンプが取得できます。

が、案の定**タイムゾーンの変換**は、必須ですので

アクションの場合は、
- タイム ゾーンの変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/35e521a4-fa1c-6717-354d-2d5a38ba4e1f.png)

もしくは
- 関数の場合
```plaintext
convertTimezone(outputs('メッセージを取得します')['body/value'][0]['createdDateTime'], 'UTC', 'Tokyo Standard Time')
```
といった対策が必要になります。

# ボタン トリガー トークンについて

https://learn.microsoft.com/ja-jp/power-automate/introduction-to-button-trigger-tokens

さて、Teamsのメッセージの情報もさることながら、同時にモバイルアプリでボタンを押した際にも、押された時間や押された場所など情報が必要になります。

何と驚くことに、ボタン トリガー トークンで得られる情報はとても多いです。

|パラメーター|説明
|---|---
|市区町村|フローを実行しているデバイスが位置する市区町村。
|国/地域|フローを実行しているデバイスが位置する国/地域。
|完全な住所|フローを実行しているデバイスが位置する完全な住所。
|緯度|フローを実行しているデバイスが位置する緯度。
|経度|フローを実行しているデバイスが位置する経度。
|PostalCode|フローを実行しているデバイスが位置する郵便番号。
|都道府県|フローを実行しているデバイスが位置する都道府県。
|住所|フローを実行しているデバイスが位置する番地。
|タイムスタンプ|フローを実行しているデバイスが位置する地域の時間。
|日付|フローを実行しているデバイスが位置する地域の日付。
|ユーザー名|フローを実行しているデバイスにサインインしているユーザーのユーザー名。
|ユーザーのメール|フローを実行しているデバイスにサインインしているユーザーのメール アドレス。

> 上記learnより引用

ここから`完全な住所`と`タイムスタンプ`を使うことにします。

なおこの部分でも、時間については`タイム ゾーンの変換`のアクション or 関数による処理は必要ですので
ご注意ください。

# フロー

さて、材料が揃ったので下記の2つのフローを作ることにします
1. 勤務を開始するときのフロー
1. 勤務を終了するときのフロー

## 1. 勤務を開始するときのフロー
ざっと流れは下記の通りとなります。

1. 勤務先と自宅の住所を変数として格納する
1. ボタンが押されたタイムスタンプを取得する
1. 【分岐】タイムスタンプから時間を抜き出し、
「おはようございます。」「お疲れ様です。」の算出する
1. 投稿するメッセージを確定し、Teamsに投稿する

順番に見ていきましょう

### 1. 勤務先と自宅の住所を変数として格納する
個人情報なので、扱いに注意ですね。
私の情報もダミーでいきます。

住所情報が`ボタン トリガー トークン`で、どうとれるか
サンプルは下記のとおりです。 ※東京で飯田橋の例

**住所**
```
Iidabashi, Chiyoda Ku, Tokyo, 102-0072, Japan
```
どう取得できるか、是非試してみてください。

私の考えですが、複数条件で値を割り出す場合は、
Key:Valueのペアになっているオブジェクトが便利です。

ですので、まずは`変数を初期化する`で勤務先と自宅の住所、
そして、それぞれに応じた文言をValueとして格納します。

なお繰り返しですが、情報はダミーです。

```変数を初期化する: 場所による文章の選択
{
    "Iidabashi, Chiyoda Ku, Tokyo, 102-0072, Japan" : "出社しています。",
    "GatsuoChou, Maji City, Sea, XXX-XXXX, Japan" : "在宅勤務です。"
}
```

この設定によって、変数[現在地]で文言が決定できます。

### 2. ボタンが押されたタイムスタンプを取得する
このタイミングで必要になるのは、タイムゾーンの変換です。
例はこちら。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2ba4aa85-bed8-1b76-2ad4-5f0ffe83d0d0.png)

前述の通り、関数でも全く問題ないです。
ただアクションの場合、メモなども残せたりと便利です。

ラウンド トリック日時パターンは文字列による、**当日の投稿か、否か**で仕様しています。
具体的には
```plaintext:日時の取得
substring(body('タイム_ゾーンの変換'), 0, 10)
```
上記のように、文字列で日付の比較用に利用しています。
Excelでいう`left関数`のような挙動ですね。

### 3. 【分岐】タイムスタンプから時間を抜き出し、「おはようございます。」「お疲れ様です。」の算出する
さて、ここでIF文の必要があります。Simpleに越したことはありません。

タイムスタンプを例に挙げます。

```plaintext:時間を数値として取得する関数
int(formatDateTime(body('タイム_ゾーンの変換'),'HH'))
```
タイムスタンプから時間を抜き出しています。
`hh`の場合、午前・午後の判断が数値で判断できないため、`HH`で対応しましょう。
こちらで24時間による表現ができます。

この関数との組み合わせで、
If文で、5時以上で11時以下の場合という条件が設定できますね。

- trueの場合、「おはようございます。」
- falseの場合は、「お疲れ様です。」

という文字列の作成をしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b681fa33-0a3c-f345-54a6-1ca3e5c4a357.png)

- 全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/43fae6c9-c057-eb40-ea27-26b0adcd0d3f.png)

:::note warn
作成を採用しているのは、ただ単に楽だからです
:::

### 4. 投稿するメッセージを確定し、Teamsに投稿する
同日に投稿した履歴がない場合は、自分が最初の投稿者となります。

`メッセージを取得します`アクションと`utcNow()`で比較しましょう。
なお`utcNow()`もタイムゾーンの変換が必要なので`アクション` or `関数`で対応しちゃってください。

一旦は関数対応を載せます。


- チャットまたはチャネルでメッセージを投稿する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/81680138-63ec-21db-1961-f1a47628415e.png)

反対に、履歴がある場合は、`応答`のアクションを実施します。

- チャネル内のメッセージで応答します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/5f3fe1c1-cbaa-34d4-77fb-a30ae44d45d6.png)

```plaintext
substring(body('タイム_ゾーンの変換_ボタンが押された時間'),0,10)

substring(variables('messageTime'),0,10)
```
上記の比較です。

- 初回の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/157ea83b-6917-4c14-7fdb-3f1df4825392.png)

- それ以外の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/978f794b-31a9-ef73-d12b-ffc8e861c2b1.png)

役者が揃いました。
全体像はコチラ！

# 完成系

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/ba723c98-de2a-a19d-948f-090e13e9159f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/be9c4cd9-081a-0444-08a0-e85e4d173509.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/36a4ef17-9ccb-5747-2419-d5c769318fcb.png)

といったところです。変数の宣言が多い分冗長になりますね。
キレイに作りたいものです。

ただ自分のやりたくないを駆逐していく感覚は、気持ちいいコトこの上ないのでShareです！

是非トライしてみましょ～！

See you later♪