LoginSignup
5
7

More than 5 years have passed since last update.

平日19時にエアコンONにする?と聞く仕組みを作った

Posted at

はじめに

以前に外出先からエアコンを動かす仕組みを作りました。

しかしながら、実際に使っていると、うっかり忘れてしまうという運用上の欠点が発覚しました(知ってた)。

そこで今回は、予め決まった時間になると「エアコンをONにする?」と聞くようにすることで、うっかり忘れてしまうことを防ぎたいと思います!

全体像

system.png

Lambdaを定期実行し、「エアコンをONにする?」とSlackにボタン付きでPOSTします。
SlackでYesボタンを選択すると、別途用意されているAPI Gatewayを叩くことでエアコンが付きます!

なお、本記事の内容は、赤枠部分になります。赤枠以外は前回の内容そのままです。

環境構築

Slackの環境構築

難しいことは行いません。メッセージを「受信」してアクション結果を「送信」するSlackアプリを作成します。

なお、投稿対象となるチャンネルは準備済みとします。

アプリの作成

Slackの下記サイトを開き、Appを作成します。

slack01.png

適当に作成します。

slack02.png

Incoming Webhooks

「Incoming Webhooks」を選択し、Onにします。

slack03.png

一番下の「Add New Webhooks to Workspace」を選択し、許可を行います。

ここで作成されたWebhooks URLは後に必要になるためメモしておきます。

slack04.png

Interactive Components

続いて、「Interactive Components」を選択し、Onにします。

slack05.png

「Request URL」には、応答先のURLを入力し、「Save Changes」を選択します。

ここの応答先とは、Slack上でボタンを押した際にPOSTする先となります。私の場合は、以前に作成したAPI Gatewayを使い回すため、そのURLを入力しています。

slack06.png

AWSの環境構築

Slackに通知するLambda(定期実行)を作成します。

AWS SAMを使っているため、ポイントだけご紹介します。

Lambda

app.py
import os
import json
import requests

SLACK_WEBHOOK_URL = os.environ["SLACK_WEBHOOK_URL"]

def lambda_handler(event, context):
    post_slack("エアコンをOnにしますか?")

def post_slack(message):
    payload = {
        "attachments": [
            {
                "text": message,
                "callback_id": "ask_aircon",
                "color": "#3AA3E3",
                "attachment_type": "default",
                "actions": [
                    {
                        "name": "aircon",
                        "text": "Yes",
                        "type": "button",
                        "value": "yes"
                    },
                    {
                        "name": "aircon",
                        "text": "No",
                        "type": "button",
                        "value": "no"
                    }
                ]
            }
        ]
    }

    # http://requests-docs-ja.readthedocs.io/en/latest/user/quickstart/
    try:
        response = requests.post(SLACK_WEBHOOK_URL, data=json.dumps(payload))
    except requests.exceptions.RequestException as e:
        print(e)
    else:
        print(response.status_code)

環境変数として下記を設定しています。

Key Value
SLACK_WEBHOOK_URL Incoming WebhooksのWebhooks URL

全貌はこちらをどうぞ。

CloudWatch Events

下記のcron式を使用し、「毎週月~金のAM10時(UTC)」に実行させています。日本時間の19時ですね。帰宅時間!(帰れるとは言ってない)

cron(0 10 ? * MON-FRI *)

Raspberry Pi

以前の作成したRaspberry Piのコードを修正します。

修正結果はこちら。受信データの解析処理を分離させました。

main.py
#長いので省略

def subscribe_callback(client, userdata, message):
    logger.info("Received a new message: ")
    logger.info(message.payload)
    logger.info("from topic: ")
    logger.info(message.topic)

    params = parse_payload.parse(message.payload)
    logger.info(json.dumps(params, indent=4))

    remote_control(params)

def remote_control(params):
    if is_aircon_on(params):
        logger.info("Execute GPIO_AIRCON_PIN")
        execute(GPIO_AIRCON_PIN)

def is_aircon_on(params):
    if params["command"] == "/control" and params["param"] == "aircon":
        return True
    if params["command"] == "ask_aircon" and params["param"] == "yes":
        return True
    return False
parse_payload.py
import json
import urllib.parse as url_parse


def parse(payload):
    format_type = _check_format(payload)

    if format_type == "slash_commands":
        data = _parse_slash_commands(payload)
        return {
            "command": data["command"],
            "param": data["text"],
            "data": data
        }
    elif format_type == "interactive_message":
        data = _parse_interactive_message(payload)
        return {
            "command": data["callback_id"],
            "param": data["actions"][0]["value"],
            "data": data
        }
    else:
        return {}


def _check_format(payload):
    data = url_parse.unquote(payload.decode(encoding="utf-8"))
    if data.startswith("payload="):
        return "interactive_message"
    else:
        return "slash_commands"


def _parse_slash_commands(payload):
    params = {}
    key_value_list = url_parse.unquote(payload.decode(encoding="utf-8")).split("&")
    for item in key_value_list:
        (key, value) = item.split("=")
        params[key] = value
    return params


def _parse_interactive_message(payload):
    data = url_parse.unquote(payload.decode(encoding="utf-8")).lstrip("payload=")
    return json.loads(data)

全貌はこちらをどうぞ。

動作結果

平日の19時になると、Slackにメッセージが来ます。それをiPhoneが通知してくれます。

result01.PNG

通知をタップ、もしくは、Slackを開くと下記のようになっており、「Yes」を選択すればエアコンがONになります!!

result02.PNG

1週間ほど運用してみましたが、エアコンを付け忘れて帰宅しても部屋が暑い、ということは無くなりました!!はっぴー!!

参考

5
7
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
5
7