AWS
RaspberryPi
Slack
IoT
APIGateway

Raspberry PiとSlackで外出先から自宅のエアコンを動かそう!

はじめに

暑いですよね。外出時に家電(エアコン)をリモコン制御してみたいと思い、Raspberry Piを買ってみました。

リモコンは下記の学習リモコン(Raspberry Pi専用)を買いました。便利です!

全体像

Slackで命令すると、自宅のエアコンが稼働します。やったね!!!

AWS IoTを使ってみたかったのです。
(自宅のRaspberry Piとクラウド(インターネット)をセキュアに接続したかった、というのもあります)

それでは、下記の順番で簡単に解説していきます。

  1. IoT Core
  2. API Gateway
  3. Slack

環境など

Raspberry Pi

  • Raspberry Pi 3 Mobile B+
  • Raspbian 9.4
  • Python 3.6

家電

  • エアコン
    • 本体:MSZ-GV225-W
    • リモコン:RH151

AWS

  • API Gateway
  • IoT Core

IoT Core

こちらを参考にIoT CoreとRaspberry Piの設定を行います。

具体的には下記となります。

  • ポリシーの作成(IoT Core用)
  • モノの作成
  • 証明書の作成とダウンロード
  • Raspberry PiにAWS IoTのSDKをインストール

API Gateway

API GatewayとIoT Coreの連携は、下記を参考にさせていただきました。

ポリシー作成

ロールにアタッチするポリシーを作成します。ポリシー名は任意です。

  • サービス: IoT
  • アクション: 書き込み(Publish)
  • リソース: すべてのリソース
  • 名前: iot-publish-poricy

ロール作成

API Gatewayで使用するロールを作成します。ロール名は任意です。

  • ロール名: ApiGateway-HomeControl-Role

さきほど作成したポリシーをアタッチします。

なお、ここで作成したロールARNをコピーしておきます。

IoTエンドポイントの確認

IoT Coreの設定を選択し、エンドポイントをメモしておきます。

APIの作成

API GatewayのTOP画面にアクセスし、API作成を行います。API名は任意です。

  • API名: HomeControl

リソースの作成

作成したAPIに対するリソースを作成します。リソース名は任意です。

  • リソース名: control

メソッドの作成

POSTメソッドを作成します。

POSTメソッドのセットアップを行います。AWSリージョンやサブドメインは必要に応じて読み替えてください。

  • 統合タイプ: AWSサービス
  • AWSリージョン: ap-northeast-1
  • AWSサブドメイン: xxxxx(IoTエンドポイント先頭の固有部分)
  • HTTPメソッド: POST
  • アクションの種類: パス上書きの使用
  • パス上書き: Publishしたいtopics(先頭のtopicsが必要)
  • 実行ロール: 先ほど作成したロール

APIの動作確認

IoT Coreのテスト準備

IoT Coreのテストを選択し、さきほど設定したトピックをsubscribeします。
なお、このときは、topics/を除いて入力してください。

Screenshot_2018-07-16 AWS IoT.png

API Gatewayでテスト実行

API Gatewayでさきほど作成したPOSTメソッドを選択し、テストします。

リクエスト本文を適当に入力し、テストボタンを選択します。

{
    "text": "this is test message!!!"
}

テスト結果

動作結果として、下記となれば成功です!

  • API Gatewayのメソッドテスト
    • ステータス: 200
    • レスポンス本文: "message": "OK"
  • IoT Coreのsubscribe
    • "text": "this is test message!!!"

APIのデプロイ

アクションからAPIのデプロイを選択します。

新しいステージを作成してデプロイします。内容は適当です。

先ほど作成したControlのPOSTメソッドを選択し、URLをコピーしておきます。

Slack

Slash Commandsを使用します。アプリを検索して追加してください。

コマンドは/controlとしておきます。お好みでどうぞ。

設定画面のURLに、さきほどデプロイしたAPIのアドレスを貼り付けます。

他の設定はお好みでどうぞ。最後に保存しましょう。

動作確認

さきほどと同じようにIoT Coreの準備をしましょう。手順は省略します。
ブラウザを開きっぱなしの場合はそのままでOKです。

では、実際にslackで試しましょう!

テスト結果

Slackのテスト結果

とりあえず応答が返ってきました。いい感じです。

IoT Coreのテスト結果

IoT Coreはこうなりました。

Screenshot_2018-07-16 AWS IoT(2).png

どうやらjson形式ではないようです。
API Gatewayの設定を頑張ればjson形式に変換できそうですが、今回はこのまま進めます。

Raspberry Pi

では、最後にRaspberry Piの環境作成を行っていきます。

AWS IoT CoreとRaspberry Piの接続については、下記を参考にしてください。これ以降はできるものとして進めていきます。

リモコンの学習

最初に紹介した通り、下記を使用します。

SW-No.1にエアコン電源ONを学習させます。
(学習方法は製品の説明書を参考にしてください)

  • SW-No.1
    • GPIO No.4
    • PIN No.7

学習後、正常に動作するかを確認してください。

ソースコード

プログラム終了時にGPIO.cleanup()を実行する必要があるため、実行ディレクトリにfinish.txtを作成することで終了トリガーとしています。
(と、ここまで作っておいて、Slackでfinishパラメータを与えたらいいだけでは?と気づきました……)

IoT Coreとの接続に必要なパラメータは、外部設定ファイル(config.ini)から読み込むようにしています。

sample_remote_control.py
import os
import configparser
import time
import json
import RPi.GPIO as GPIO
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient

#Use PIN 7 (GPIO 4)
GPIO_AIRCON_PIN = 7

#programme finish trigger file
FINISH_FILE = "finish.txt"


def main():
    init_gpio()

    (root_ca, private_key, certificate,
        client_id, endpoint, port, topic) = parse_config_file()

    # https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/sphinx/html/index.html
    client = AWSIoTMQTTClient(client_id)
    client.configureEndpoint(endpoint, port)
    client.configureCredentials(root_ca, private_key, certificate)

    client.configureAutoReconnectBackoffTime(1, 32, 20)
    client.configureOfflinePublishQueueing(-1)
    client.configureDrainingFrequency(2)
    client.configureConnectDisconnectTimeout(10)
    client.configureMQTTOperationTimeout(5)

    client.connect()
    client.subscribe(topic, 1, subscribe_callback)

    while True:
        time.sleep(5)

        if is_finish():
            os.remove(FINISH_FILE)
            GPIO.cleanup()
            print("Finish remote controller")
            break

def init_gpio():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(GPIO_AIRCON_PIN, GPIO.OUT, initial=GPIO.HIGH)

def parse_config_file():
    config = configparser.ConfigParser()
    config.read("config.ini")

    return (
        config["AWS_IOT_CONNECT"]["ROOT_CA"],
        config["AWS_IOT_CONNECT"]["PRIVATE_KEY"],
        config["AWS_IOT_CONNECT"]["CERTIFICATE"],
        config["AWS_IOT_CORE"]["CLIENT_ID"],
        config["AWS_IOT_CORE"]["ENDPOINT"],
        int(config["AWS_IOT_CORE"]["PORT"]),
        config["AWS_IOT_CORE"]["TOPIC"]
    )

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

    params = parse_payload(message.payload.decode(encoding="utf-8"))
    print(json.dumps(params, indent=4))

    remote_control(params)

    print("--------------\n\n")

def parse_payload(payload):
    params = {}
    key_value_list = payload.split("&")
    for item in key_value_list:
        (key, value) = item.split("=")
        params[key] = value
    return params

def remote_control(params):
    if params["text"] == "aircon":
        print("Execute GPIO_AIRCON_PIN")
        execute(GPIO_AIRCON_PIN)

def execute(pin_no):
    GPIO.output(pin_no, True)
    time.sleep(0.5)
    GPIO.output(pin_no, False)
    time.sleep(0.5)

def is_finish():
    if os.path.isfile(FINISH_FILE):
        return True
    return False

if __name__ == "__main__":
    main()
config.ini
[AWS_IOT_CONNECT]
ROOT_CA = ./cert/root_ca.pem
PRIVATE_KEY = ./cert/private.pem.key
CERTIFICATE = ./cert/certificate.pem.crt.txt

[AWS_IOT_CORE]
CLIENT_ID = test_client_id
ENDPOINT = xxxxxxxnortheast-1.amazonaws.com
PORT = 8883
TOPIC = raspberry_pi/test

config.iniファイルの内容は、適宜変更してください。

ソースコードは、GitHubにも置いています。

動作方法

それでは、実際に動作してみましょう!!!!

開始

Raspberry Piで下記コマンドを実行します。

ssh接続を解除してもバックグラウンド実行してほしいため、nohupを使用しています。

$ nohup sudo python sample_remote_control.py > output.txt &

slackで制御!

/control aircon

エアコン

が起動する!!!

終了

Raspberry Piで下記コマンドを実行します。

$ touch finish.txt

まとめ

エアコンの電気代を節約しつつ、仕事から解放されたらSlackでエアコンをONにすることで、帰宅時には快適です!!!

参考