Help us understand the problem. What is going on with this article?

ソラコムの【あのボタン】で勤怠打刻してみた(その1)

みなさん、在宅勤務やってますか?そして在宅勤務の打刻忘れてませんか?僕は忘れっぽいんですが、在宅勤務の打刻だけは忘れてません。が、打刻をしたあとslackのスレッドにも業務を開始する旨を開始時間と一緒に投稿する必要があります。そして退勤するときも同様に打刻した後に同じスレッドに退勤時間を投稿する必要があります。これがまあ面倒くさいんですよ。面倒くさいことはなんとかして解決する、それがエンジニアってもんじゃないですか(偏見)

というわけで、今回はこのSlackへの投稿を自動化してみたいと思います。
※今回はプライベートのテスト環境でためしてます。

今回使うもの

さて何をつかってこれを自動化しようか考えたときに机の上にあるものを見つけました。
IMG_20200511_215729.jpg
そうです、以前Soracom UGのハンズオンで買ったあのボタンです。ハンズオンが終わった後には、ラズパイと連携するネタに使いその流れで夏場はこれを使って遠隔でエアコンの電源をつけるリモコンとして使っていました。そして今年も稼働させようとしてたところでした(いや、本当ですよ)。ですが、今はそのシステムよりも打刻をこれで楽にさせるほうが大事だと思ったので、これを使っていきたいと思います。

イメージ

3種類のトリガーを生かしてこう割り振りたいと思います

  • シングルクリックで出勤の連絡をする
  • ダブルタップで退勤の連絡をする
  • ロングタップは直前の投稿を消す(できたら実装したい)

Slackのtokenを取得

まずはslackにメッセージを投稿させるためにtokenを取得します。こちらのサイトから、Create an Appをクリックして、新規のSlack appを作成します。
コメント 2020-05-11 224520.png

このようなダイアログが表示されるので、ここでApp Nameと今回使用するワークスペースを指定して、下のCreate Appをクリックします。App Nameはわかりやすい名前にしておきましょう。後で変更することもできます。
コメント 2020-05-11 224630.png

作成すると、以下の画面が出力されるので、右下のPermissionsを選択しておきます。
コメント 2020-05-11 225736.png

次の画面をスクロールしたときにScopesという項目がありますが、こちらはUser Token Scopesの中からchat:write、そしてchannel:historyを選択します。
コメント 2020-05-11 234143.png

上にスクロールして、Install App to Workspaceをクリックします。
コメント 2020-05-11 233735.png

以下の画面が出るので、Allowを押して次に進みます。
コメント 2020-05-11 234241.png

その後、以下のようにOAuth Access Tokenが発行されるので、コピーしておきましょう。
コメント 2020-05-11 234734.png

lambdaの実装

その前に今回のシチュエーション

今回はslackに勤怠チャンネルがあって、下図のようなメッセージが毎朝投稿されるからこれに出勤時刻、退勤時刻を投稿するというシチュエーションを考えます。(念のために言いますが、あくまで架空のものです)
コメント 2020-05-12 012340.png

今回の実行環境

  • AWS lambda(RuntimeはPython3.6)
  • SlackのPython SDK

環境構築(lambdaを作成)

  1. AWSにログインして検索窓からlambdaと入力しlambdaにアクセス
  2. 関数名はお好みに設定し、ランタイムはPython3系(今回はPython3.6)を選択
  3. あとは特にいじらずに関数の作成をクリック
  4. SlackのSDKを使うので、Cloud9で開発環境を構築する(特に何も設定をいじらずに順に設定してOK)
  5. Web IDEを立ち上げて右側のlambdaマークをクリックして、先程作成したlambdaを選択し、IDE環境にインポートする コメント 2020-05-12 025319.png
  6. IDEの下のターミナルでcd YOUR_LAMBDAと入力し、実行環境にディレクトリを移動したら、以下のコマンドを実行し、SlackのSDKをインストールする
python -m pip install --target=./ slackclient

ソースコード

デフォルトの関数を消して、以下のソースコードに書き換えます。channel IDには皆さんのお使いのワークスペースのアドレスのhttps://WORKSPACE_URL/archives/channelIdの形式のとき、channelIdの文字列をコピペします。

from slack import WebClient
from slack.errors import SlackApiError
from datetime import datetime
import datetime as dt
import json
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

token = "YOUR_TOKEN"
client = WebClient(token=token)

def lambda_handler(event, context):
    logger.info('request event: \n' + json.dumps(event))

    # クリックイベントを取得する
    click_type = event['deviceEvent']['buttonClicked'].get('clickType')
    logger.info("click_type: " + click_type)

    try:
        # 返信するスレッドのtsを取得
        channelId = 'YOUR_CHANNEL_ID'   # https://WORKSPACE_URL/archives/channelId
        response = client.conversations_history(channel=channelId)
        ts = response["messages"][0]["ts"]

        # 投稿時刻を設定し、スレッドに送信
        nowDate = datetime.utcnow() + dt.timedelta(hours=9)
        nowTime = nowDate.strftime("%H:%M")
        if click_type == "SINGLE":
            message = "業務開始します {}".format(nowTime)
        elif click_type == "DOUBLE":
            message = "業務終了します {}".format(nowTime)
        response = client.chat_postMessage(
            channel=channelId,
            thread_ts=ts,
            text=message)
        logger.info(response)
        return{
            'statusCode': 200,
            'body': 'Succeed'
        }
    except SlackApiError as e:
        logger.info(e.response["ok"] is False)
        logger.info(e.response["error"])

        return {
            'statusCode': 500,
            'body': f"Got an error {e.response['error']}"
        }

テスト

Cloud9上でlambdaを開発したときには、その場で関数をテストすることができます。右側のlambdaのタブの上部にある再生ボタンの隣の下矢印をクリックして、Run Localを選択して再生ボタンを押します。
コメント 2020-05-12 035409.png

これでローカル環境で実行できる状態ですが、実際にLTE-Mボタンを押したときにlambdaが受け取るデータが無いとテストができません。そこで以下のjsonをコピーして、test payloadに貼り付けます。なお、使うJSONは以前使用したものと全く一緒ですが、今回のコードの動作に影響はないのでそのまま使います。

{
    "deviceInfo": {
        "deviceId": "G030PMXXXXXXXXXX",
        "type": "button",
        "remainingLife": 94.2,
        "attributes": {
            "projectRegion": "us-west-2",
            "projectName": "One-click-Raspi",
            "placementName": "button1",
            "deviceTemplateName": "RequestCmd"
        }
    },
    "deviceEvent": {
        "buttonClicked": {
            "clickType": "SINGLE",
            "reportedTime": "2019-01-24T18:49:36.813Z"
        }
    },
    "placementInfo": {
        "projectName": "One-click-Raspi",
        "placementName": "button1",
        "attributes": {
            "SINGLE": "{\"cmd\":\"green\"}",
            "DOUBLE": "{\"cmd\":\"blue\"}",
            "LONG": "{\"cmd\":\"red\"}"
        },
        "devices": {
            "RequestCmd": "G030PMXXXXXXXXXX"
        }
    }
}

貼り付けたら左上にあるRunボタンをクリックして、テストしてみます。以下のように指定したチャンネルに最後に投稿されたスレッドにメッセージが送信されれば、成功です。
コメント 2020-05-12 130512.png

デプロイ

それでは、最後に作成した関数をlambdaのリソースにデプロイします。IDEの右側にあるlambdaタブで先程作成したlocal lambdaを右クリックしてdeployを選択して関数をデプロイをします。デプロイを終えて、lambdaのリソースに移動し先程作成したlambdaにCloud9からデプロイした環境が反映されていたら成功です。
コメント 2020-05-12 041828.png

今回はここまで

長くなったので、今回はここまでにします。次回いよいよボタンからこのlambdaを実行していきます。

後編はこちら
ソラコムの【あのボタン】で勤怠打刻してみた(その2)

KMiura95
IBM Champion 2020 / LINE API Expert 2020
iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away