1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LineからLambda経由でSesameの鍵を開け閉めするまで

Posted at

やりたいこと

Sesameを買って、スマートホーム化を進めているところ。
どうしてもSesameの公式アプリのレスポンスが遅い。
「開けて」って言ったら、すぐ開けてほしい。

※Sesameとは
自宅の鍵に取り付けるだけで、スマホから開け閉めできる!というやつ。
https://jp.candyhouse.co

できたこと

Lineの個人チャンネルにて「鍵あけて」「鍵しめて」というと、Sesameがスッと起動する。

構成

Line→AWS API Gateway→Lambda→Sesame

Lambda上はPythonで書いてます。
コードはPycharmで書いて、そのままデプロイまでしちゃいます。簡単。

ローカル環境はMacOSです。

1.SesameのAPIを確認する。

まず公式ページの「ダッシュボード(BETA)」からログイン。
「API設定」から認証コードを入手します。

入手した認証コードを使いながら、とりあえずcurlで叩いてみます。
API仕様の詳細は、公式見てください。
https://docs.candyhouse.co/#get-sesame-list

こう打つと
curl -H "Authorization: **************" \
https://api.candyhouse.co/public/sesames
こう返ってくる
{
     "device_id": "*******************",
     "serial": "********",
     "nickname": "************"
}

応答はすべてJSON形式。
上の"device_id"をもとに、ロック・ロック解除・ステータス確認のAPIを使います。

2.LambdaからAPIを叩く

pythonで書くことにしているので、line-bot-sdkを使いました。

line-bot-sdkの使い方はこちら。
https://github.com/line/line-bot-sdk-python

1.でCURLしていたのは、requestsで実現します。
CURLをpython形式にしてくれるサイトが合ったので、使わせて頂きました。
https://curl.trillworks.com

pythonのソースは以下のとおり。
鍵のOPEN/CLOSEの指示のあと、10秒Sleepしてから、鍵の状態を返却します。
ちなみにAWS Lambdaのタイムアウト値は初期値が3秒なので、広げないと永遠に成立しません。
(実は結構ハマった)

app.py
import os, sys
import json
import time
import requests

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
from linebot.exceptions import (
    LineBotApiError, InvalidSignatureError
)

channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
if channel_secret is None:
    print('Specify LINE_CHANNEL_SECRET as environment variable.')
    sys.exit(1)
if channel_access_token is None:
    print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
    sys.exit(1)

line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(channel_secret)


def lambda_handler(event, context):
    signature = event["headers"]["X-Line-Signature"]
    body = event["body"]
    ok_json = {"isBase64Encoded": False,
               "statusCode": 200,
               "headers": {},
               "body": ""}
    error_json = {"isBase64Encoded": False,
                  "statusCode": 403,
                  "headers": {},
                  "body": "Error"}

    def controll_sesame(controll):
        # ロック解除
        controll_headers = {
            'Authorization': '**************************',
            'Content-Type': 'application/json',
        }
        if controll == "OPEN":
            controll_data = '{"command":"unlock"}'
        elif controll == "CLOSE":
            controll_data = '{"command":"lock"}'
        else:
            pass

        controll_response = requests.post(
            'https://api.candyhouse.co/public/sesame/*************************',
            headers=controll_headers, data=controll_data)

        time.sleep(10)

        # 状態確認
        confirm_headers = {
            'Authorization': '*************************',
        }
        confirm_response = requests.get('https://api.candyhouse.co/public/sesame/*************************',
                                        headers=confirm_headers)
        response_data = confirm_response.json()
        locked = response_data['locked']

        # 結果返却
        if locked:
            message_text = "閉まってるよ"
        else:
            message_text = "空いてるよ"

        return message_text

    @handler.add(MessageEvent, message=TextMessage)
    def message(line_event):
        text = line_event.message.text
        if text == "鍵あけて":
            message_text = controll_sesame("OPEN")
        elif text == "鍵しめて":
            message_text = controll_sesame("CLOSE")
        else:
            message_text = text

        line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=message_text))

    try:
        handler.handle(body, signature)
    except LineBotApiError:
        return error_json
    except InvalidSignatureError:
        return error_json

    return ok_json

3.API Gatewayを設定する

AWSコンソールからAPI GatewayをLambdaに括り付ける。
あまり詳しく学びきれてないので、公式見ながらチクチク作る。

最近?HTTP APIができたようですが、REST APIを選択します。
できたら「ダッシュボード」に書かれているURLを控えておきます。

4.LineからAPI Gatewayに接続する。

まずはDeveloperとして登録。
https://developers.line.biz/ja/

Messaging APIとしてチャンネルを作成します。
「Webhook URL」に3.で控えたAPI GatewayのURLを指定します。

またLineチャンネルに設定されているチャネルアクセストークンと
チャネルシークレットは、Lambdaの環境変数に登録しておきます。

5.ハマりどころ

pythonのコードはPycharmで書いていました。
PycharmにはAWS Toolkitというプラグインがあり、
これを導入することでローカルからLambdaへのデプロイが可能になります。

ただこれをやる際、IAMロールに権限をつけておく必要があるのに気付かず
手探りで権限を広げて、とりあえずデプロイが成功。
結果として、Lambda、IAM、S3、APIGateway、CloudFormationの権限を付与しました。

不足はないですが、過剰はあるかもしれません。
勉強不足。。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?