M5StickCを使って外出先からお家のエアコンを操作（前編）

# やりたいことのイメージ
### イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/5b33e135-7114-bbf3-2f06-d3797dcc1829.png)

### 処理の流れ
1. Slack 上で Bot にメッセージを送る
1. Slack Bot が Amazon API Gateway が発行した API を叩く
1. Amazon API Gateway をトリガーにして、Lambda function が実行される
1. Lambda function が AWS IoT Core にメッセージを格納する（Publish する）
1. M5StickC が AWS IoT Core に定期的にメッセージをとりに行く（Subscribe する）
1. M5StickC が 受信したメッセージに応じて、エアコンのリモコン操作を実行する（赤外線を照射する）

※前編には6,5を実装する手順を記載し、後編には4,3,2を実装する手順を記載します。

### エアコンのリモコン操作の種類
- Cool：電源オン（冷房）
- Heat：電源オン（暖房）
- Stop：電源オフ

# 用意するもの
- [M5StickC](https://www.switch-science.com/catalog/5517/)　または　[M5StickC Plus](https://www.switch-science.com/products/6470)
- [M5Stack用赤外線送受信ユニット](https://www.switch-science.com/catalog/5699/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/a6ebb360-0c02-bb93-2a38-d0a8d8cc72be.png)
- AWSアカウント

# 環境
- Windows 10 Pro　バージョン：20H2　OSビルド：19042.1110
- Arduino IDE 1.8.15

※本記事の記述は上記の環境となりますが、別途、Windows 11 + Arduino IDE 2.2.1 + M5StickC Plus でも動作を確認しています。

# 目次
1. Arduino IDE のセットアップ
1. リモコン信号の学習
1. AWS IoT Core の設定
1. M5StickC へのプログラムの書き込み


# 1. Arduino IDE のセットアップ
Arduino IDE はインストール済みの前提で進めます。
まだインストールしていない場合は、[[Software | Arduino]](https://www.arduino.cc/en/software) にアクセスし、インストーラをダウンロードしてインストールしてください。

### ボードを追加する
Arduino IDE を起動します。

[ファイル]-[環境設定]を開きます。

「追加のボードマネージャの URL」に https://dl.espressif.com/dl/package_esp32_index.json を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/64320e47-35a3-7e6c-f7f7-eb0c75755e31.png)

[ツール]-[ボード]-[ボードマネージャ]を開きます。

検索欄に「ESP32」を入力し、表示された「esp32 by Espressif System」をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/22b8a04e-a9e1-96d2-2223-f947b47d52cb.png)

# 2. リモコン信号の学習
### ライブラリを追加する
[スケッチ]-[ライブラリをインクルード]-[ライブラリを管理]を開きます。

検索欄に「IRremoteESP8266」と入力し、ESP32対応のIRremoteをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/7acdc1fb-bfb4-a8ae-d1c3-da9b9eb5853f.png)

### コードを書く
IRremoteESP8266のサンプルからIRrecvDumpV2を開きます。
（[ファイル]-[スケッチ例]-[IRremoteESP8266]-[IRrecvDumpV2]）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/25357f0a-d466-679e-c56c-d3454afbe44f.png)

IR Unit の IN は Grove の G33 なので、kRecvPin を 33 に変更します。
```c
const uint16_t kRecvPin = 33;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/c8df46a1-f574-c82e-daea-6a3dac6a4750.png)

### M5StickC に書き込む
ボードを選択します。
（[ツール]-[ボード]-[ESP32 Arduino]-[M5StickC]）
*※ M5StickC Plus の場合も、「M5Stick-C」を選択すればOKです。*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/c3994bda-2e6f-7a74-2fe8-6e5775236ae5.png)

ボーレートを選択します。
（[ツール]-[Upload Speed]-[115200]）

シリアルポートを選択します。
（[ツール]-[シリアルポート]-[COM?]）
※COMの後ろの番号の確認方法は、デバイスマネージャーを開き、「ポート(COMとLPT)」配下に表示される番号を確認してください。

M5StickC に書き込みます。
（[スケッチ]-[マイコンボードに書き込む]）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/4bee406e-542c-b692-8e76-e336b5ed64b5.png)

### 赤外線を受信する
書き込みが完了したら、シリアルモニタを開きます。
（[ツール]-[シリアルモニタ]）

右下のボーレートを 115200bps に合わせます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/ea28507f-2454-63ef-ddd4-a3c042595429.png)

IR Unit に向かってリモコンを操作すると、シリアルモニタにリモコン信号の内容が表示されます。
※後ほどソースコード内に記述するため、rawData の部分を控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/07e2cfe0-b753-2113-f103-e53d6cb4f8a1.png)


##### シリアルモニタに表示された内容

電源オン（冷房）
> Timestamp : 001052.147
Library   : v2.7.20

> Protocol  : COOLIX
Code      : 0xB2BF90 (24 Bits)
Mesg Desc.: Power: On, Mode: 0 (Cool), Fan: 5 (Auto), Temp: 27C, Zone Follow: Off, Sensor Temp: Off
uint16_t rawData[199] = {4502, 4394,  592, 1578,  590, 522,  562, 1576,  592, 1576,  592, 520,  562, 520,  564, 1578,  592, 520,  562, 522,  562, 1576,  592, 520,  564, 496,  586, 1578,  592, 1578,  590, 520,  564, 1578,  590, 1576,  592, 520,  564, 1578,  590, 1578,  590, 1578,  590, 1578,  592, 1578,  592, 1576,  592, 520,  564, 1580,  588, 522,  562, 520,  564, 520,  562, 520,  564, 520,  564, 520,  564, 1578,  590, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  562, 522,  562, 522,  562, 520,  564, 1576,  592, 1576,  590, 522,  564, 1576,  592, 1578,  590, 1576,  592, 1578,  592, 5156,  4500, 4394,  592, 1578,  592, 520,  564, 1576,  592, 1576,  592, 520,  564, 520,  564, 1578,  592, 518,  564, 520,  564, 1576,  592, 520,  564, 520,  562, 1576,  592, 1576,  592, 520,  564, 1578,  590, 1576,  594, 520,  564, 1578,  590, 1578,  590, 1578,  590, 1578,  590, 1578,  592, 1576,  592, 520,  564, 1576,  592, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 1576,  592, 1576,  592, 520,  564, 1576,  592, 1576,  592, 1576,  592, 1576,  592};  // COOLIX B2BF90
uint64_t data = 0xB2BF90;



電源オン（暖房）
> Timestamp : 001062.601
Library   : v2.7.20

> Protocol  : COOLIX
Code      : 0xB2BF9C (24 Bits)
Mesg Desc.: Power: On, Mode: 3 (Heat), Fan: 5 (Auto), Temp: 27C, Zone Follow: Off, Sensor Temp: Off
uint16_t rawData[199] = {4500, 4394,  592, 1576,  592, 520,  562, 1578,  592, 1578,  590, 522,  564, 520,  562, 1578,  592, 520,  562, 520,  564, 1578,  592, 520,  562, 520,  564, 1578,  590, 1578,  590, 520,  564, 1578,  590, 1576,  592, 520,  564, 1576,  592, 1576,  592, 1576,  592, 1576,  592, 1576,  592, 1578,  590, 520,  564, 1578,  592, 520,  564, 520,  564, 520,  562, 520,  564, 522,  562, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 1576,  592, 1576,  592, 494,  590, 520,  564, 520,  564, 1578,  592, 1576,  594, 520,  564, 520,  564, 520,  562, 1576,  592, 1576,  592, 5156,  4500, 4392,  594, 1576,  592, 520,  564, 1576,  592, 1576,  592, 520,  564, 520,  564, 1576,  592, 520,  562, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 1576,  592, 520,  564, 1576,  592, 1576,  592, 520,  564, 1576,  592, 1576,  592, 1576,  594, 1576,  592, 1576,  592, 1576,  592, 520,  564, 1576,  592, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 1576,  594, 1576,  592, 518,  564, 520,  564, 520,  564, 1578,  592, 1576,  592, 518,  564, 520,  564, 520,  564, 1576,  592, 1576,  592};  // COOLIX B2BF9C
uint64_t data = 0xB2BF9C;


電源オフ
> Timestamp : 001065.001
Library   : v2.7.20

> Protocol  : COOLIX
Code      : 0xB27BE0 (24 Bits)
Mesg Desc.: Power: Off
uint16_t rawData[199] = {4498, 4392,  592, 1576,  594, 520,  566, 1574,  592, 1578,  592, 520,  564, 518,  564, 1576,  592, 520,  564, 520,  564, 1576,  594, 520,  564, 520,  562, 1578,  592, 1576,  592, 520,  562, 1578,  592, 520,  564, 1576,  592, 1576,  594, 1576,  592, 1576,  592, 520,  564, 1578,  592, 1576,  592, 1578,  590, 520,  564, 494,  590, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 1574,  594, 1576,  590, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 520,  564, 520,  568, 1574,  592, 1578,  590, 1576,  592, 1576,  592, 1576,  592, 5154,  4502, 4392,  592, 1576,  592, 520,  564, 1576,  592, 1576,  592, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1576,  592, 1576,  592, 518,  564, 1576,  592, 520,  564, 1576,  592, 1576,  592, 1576,  592, 1576,  592, 520,  564, 1576,  594, 1576,  592, 1578,  592, 518,  566, 518,  564, 520,  564, 520,  564, 1576,  592, 520,  564, 520,  564, 1578,  592, 1576,  594, 1576,  592, 518,  566, 518,  564, 494,  590, 520,  564, 520,  564, 520,  566, 518,  564, 520,  564, 1576,  592, 1576,  594, 1576,  592, 1576,  592, 1580,  588};  // COOLIX B27BE0
uint64_t data = 0xB27BE0;


### テストしてみる

学習したリモコン信号を実際に照射してみて、エアコンを操作できるかテストしてみます。

IRremoteESP8266 のサンプルから IRsendDemo を開きます。
（[ファイル]-[スケッチ例]-[IRremoteESP8266]-[IRsendDemo]）

以下の様に内容を書き換えて、M5StickC に書き込みします。
rawData の部分に、先ほど受信した内容をコピペしています。

```c
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <M5StickC.h>

const uint16_t kIrLed = 32;  // IR Unit の OUT

IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

// IRrecvDumpV2で赤外線を受信してシリアルモニタに表示された rawData をコピペする
// 冷房の信号を照射
uint16_t rawData[199] = {4502, 4394, 592, 1578, 590, 522, 562, 1576, 592, 1576, 592, 520, 562, 520, 564, 1578, 592, 520, 562, 522, 562, 1576, 592, 520, 564, 496, 586, 1578, 592, 1578, 590, 520, 564, 1578, 590, 1576, 592, 520, 564, 1578, 590, 1578, 590, 1578, 590, 1578, 592, 1578, 592, 1576, 592, 520, 564, 1580, 588, 522, 562, 520, 564, 520, 562, 520, 564, 520, 564, 520, 564, 1578, 590, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 562, 522, 562, 522, 562, 520, 564, 1576, 592, 1576, 590, 522, 564, 1576, 592, 1578, 590, 1576, 592, 1578, 592, 5156, 4500, 4394, 592, 1578, 592, 520, 564, 1576, 592, 1576, 592, 520, 564, 520, 564, 1578, 592, 518, 564, 520, 564, 1576, 592, 520, 564, 520, 562, 1576, 592, 1576, 592, 520, 564, 1578, 590, 1576, 594, 520, 564, 1578, 590, 1578, 590, 1578, 590, 1578, 590, 1578, 592, 1576, 592, 520, 564, 1576, 592, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 1576, 592, 1576, 592, 520, 564, 1576, 592, 1576, 592, 1576, 592, 1576, 592};

void setup() {
  M5.begin();
  irsend.begin();
#if ESP8266
  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
#else  // ESP8266
  Serial.begin(115200, SERIAL_8N1);
#endif  // ESP8266
}

void loop() {
 M5.update();
  if ( M5.BtnA.wasReleased() ) {
    Serial.println("a rawData capture from IRrecvDumpV2");
    irsend.sendRaw(rawData, 199, 38);  // Send a raw data capture at 38kHz.
    delay(2000);
  }
}

```
*※ M5StickC Plus の場合は、`#include <M5StickC.h>` の部分を `#include <M5StickCPlus.h>` に置き換えてください。*

書き込みが終わったら、M5StickC の Aボタン（正面の M5 と書かれたボタン）を押して、エアコンが電源オン（冷房）できれば成功です。

うまくかない場合は、IR Unit のトランスミッターをエアコンの受信部分に向けて、近づけて試してみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/62cb2997-9c47-474d-6def-e2fd946391ed.png)


# 3. AWS IoT Core の設定

### ポリシーを作成する

AWSコンソールにサインインし、画面左上の[サービス▼]を開き、[IoT Core]をクリックします。

[安全性]-[ポリシー]をクリックします。
[ポリシーの作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/3b35dbf0-85c7-fcec-4d45-d0b77763cef2.png)


任意の名前を設定します。ここでは、M5StickC-Policy という名前にしました。
続けて、「アクション」「リソースARN」「効果」を設定します。
検証時点では、以下のように設定していました。

| アクション | リソースARN | 効果 |
|:-:|:-:|:-:|
| Iot:* | * | 許可 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/73d1d3b1-aebe-026a-b7c1-266bea422b48.png)

最終的には、以下のように設定しました。
「\<region>:\<AWS-account-ID>」の部分は、自分の環境に書き換える必要があります。

| 効果 | アクション | リソースARN |
|:-:|:-:|:-:|
| 許可 | iot:Connect | arn:aws:iot:\<region>:\<AWS-account-ID>:client/${iot:ClientId} |
| 許可 | iot:Receive | arn:aws:iot:\<region>:\<AWS-account-ID>:topic/$aws/things/myM5StickC/shadow/update/delta |
| 許可 | iot:Subscribe | arn:aws:iot:\<region>:\<AWS-account-ID>:topicfilter/$aws/things/myM5StickC/shadow/update/delta |

JSON
```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:<region>:<AWS-account-ID>:client/${iot:ClientId}"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Receive",
      "Resource": "arn:aws:iot:<region>:<AWS-account-ID>:topic/$aws/things/myM5StickC/shadow/update/delta"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "arn:aws:iot:<region>:<AWS-account-ID>:topicfilter/$aws/things/myM5StickC/shadow/update/delta"
    }
  ]
}
```

### モノを作成する

[管理]-[モノ]をクリックします。
[モノを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/78cfd37f-1dae-c38f-297c-8f5b590a7ae7.png)


[1つのモノを作成]を選択し、[次へ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/47501422-ab81-5f1e-1417-8550cce674da.png)


モノの名前欄に任意の名前を入力し、[次へ]をクリックします。
ここでは、「myM5StickC」と設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/03e709b0-ef55-8b47-029d-49fa84f077bf.png)


[新しい証明書を自動生成(推奨)]を選択し、[次へ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/39eb95bb-359f-54c3-9d64-4979d539ae70.png)


先ほど作成したポリシーを選択して、[モノを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/2188cb85-bf46-a9b3-4d31-93135f21b376.png)


デバイス証明書、パブリックキー、プライベートキー、ルートCA証明書の「RSA 2048 ビットキー: Amazon ルート CA 1」というものをダウンロードします。
※このうち、デバイス証明書、プライベートキー、ルートCA証明書は、後ほど、デバイス側のソースコード内に記述する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/23752115-850e-ac10-d840-f192eaa6e112.png)


# 4. M5StickC へのプログラムの書き込み

### ライブラリを準備する

[スケッチ]-[ライブラリをインクルード]-[ライブラリを管理]を開きます。
検索欄に「PubSubClient」と入力し、以下をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/13281b4f-ebb9-bc33-3237-240293a839b3.png)

ここでパケットサイズ（一度にやりとりできるメッセージの長さ）を大きくしておきます。
PubSubClient.h を開きます。私のPCでは以下の場所にありました。
C:\Users\xxxxxxx\Documents\Arduino\libraries\PubSubClient\src\PubSubClient.h

MQTT_MAX_PACKET_SIZE　の値を 256 から 2048 に変更して保存します。
`#define MQTT_MAX_PACKET_SIZE 2048`

もうひとつ、先ほどと同じ要領で、「Arduino_JSON」をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/9c3d92de-d919-5f01-78b3-7fae1f97d6ba.png)



### コードを書く

karaage0703さんが公開されているコードを参考にしました。

https://github.com/karaage0703/esp32-sample

m5stack-iot　=>　m5stack-iot.ino　を開けばOK。


##### 環境ごとの設定

以下の部分は自分の環境に合わせて書く必要があります。

WiFiの設定。自分の家の無線LANルータに接続するための認証情報を入れます。

```c
// WiFi Setting
const char* ssid = "";
const char* password = "";
```

awsEndpointの部分は、AWS IoTの設定画面から「設定」ボタンを押して確認できます。

```c
const char* awsEndpoint = "xxx.xxx.xxx.amazonaws.com";
```

『char *pubTopic = "";』の部分は、今回publishではなくsubscribeする形なので、subTopicという変数名にしました。
トピックは、Device Shadow MQTT トピックを指定しています。

```c
char *subTopic = "$aws/things/myM5StickC/shadow/update/delta";
```

rootCA、certificate、privateKeyは、先ほどダウンロードしたものをそれぞれテキストエディタで開き、文字列をコピーして貼り付けます。

```c
const char* rootCA = "-----BEGIN CERTIFICATE-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END CERTIFICATE-----\n";
const char* certificate = "-----BEGIN CERTIFICATE-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END CERTIFICATE-----\n";
const char* privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END RSA PRIVATE KEY-----\n";
```

##### コード全文

subscribeしてメッセージ（「Cool」「Heat」「Stop」）を受け取ると、セットしたコールバック関数が呼ばれて、受け取ったメッセージに応じた信号を IR Unit から照射するようにしています。

```c
#include <M5StickC.h>
#include <IRsend.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Arduino_JSON.h>

// WiFi Setting
const char* ssid = "";
const char* password = "";

// AWS IoT Setting
const char* awsEndpoint = "xxx.xxx.xxx.amazonaws.com";
const int port = 8883;
char *subTopic = "$aws/things/myM5StickC/shadow/update/delta";
const char* rootCA = "-----BEGIN CERTIFICATE-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END CERTIFICATE-----\n";
const char* certificate = "-----BEGIN CERTIFICATE-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END CERTIFICATE-----\n";
const char* privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END RSA PRIVATE KEY-----\n";

WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);

const uint16_t kIrLed = 32;  // IR Unit の OUT
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

void setup() {
  M5.begin(); // M5StickC初期化
  irsend.begin(); // IR初期化
  Serial.begin(115200);  //シリアルモニタを利用するためのシリアル通信の設定

  // LCDに文字を表示する
  M5.Axp.ScreenBreath(7); // 画面の明るさ7〜１2
  M5.Lcd.setRotation(1); // 画面を横向きにする
  M5.Lcd.fillScreen(WHITE);
  M5.Lcd.setCursor(5, 10);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.printf("Running");
  // LCD表示が不要な場合は以下を有効化する
  //  M5.Axp.SetLDO2( false ); // 液晶OFF

  // Start WiFi
  Serial.println("Connecting to ");
  Serial.print(ssid);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected.");
 
  // Configure MQTT Client
  httpsClient.setCACert(rootCA);
  httpsClient.setCertificate(certificate);
  httpsClient.setPrivateKey(privateKey);
  mqttClient.setServer(endpoint, port);
  mqttClient.setCallback(mqttCallback);
 
  connectAWSIoT();
}

void connectAWSIoT() {
  while (!mqttClient.connected()) {
    if (mqttClient.connect("ESP32_device")) {
      Serial.println("mqtt Connected.");
      int qos = 0;
      mqttClient.subscribe(subTopic, qos);
      Serial.println("Subscribed.");
    } else {
      Serial.print("Failed. Error state=");
      Serial.print(mqttClient.state());
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void mqttCallback (char* topic, byte* payload, unsigned int length) {
  Serial.print("Received. topic=");
  Serial.println(topic);
  char message[128];
  for (int i = 0; i < length; i++) {
    message[i] = (char)payload[i];
  }
  Serial.println(message);

  // JSONをパースする
  JSONVar obj = JSON.parse(message);

  // 受信したメッセージと用意したメッセージを比較し、一致する場合はそれぞれに応じた赤外線を照射する
  if(strncmp((const char*)obj["message"], "Cool", 4) == 0) {
    // 冷房の信号を照射
    uint16_t rawData[199] = {4502, 4394, 592, 1578, 590, 522, 562, 1576, 592, 1576, 592, 520, 562, 520, 564, 1578, 592, 520, 562, 522, 562, 1576, 592, 520, 564, 496, 586, 1578, 592, 1578, 590, 520, 564, 1578, 590, 1576, 592, 520, 564, 1578, 590, 1578, 590, 1578, 590, 1578, 592, 1578, 592, 1576, 592, 520, 564, 1580, 588, 522, 562, 520, 564, 520, 562, 520, 564, 520, 564, 520, 564, 1578, 590, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 562, 522, 562, 522, 562, 520, 564, 1576, 592, 1576, 590, 522, 564, 1576, 592, 1578, 590, 1576, 592, 1578, 592, 5156, 4500, 4394, 592, 1578, 592, 520, 564, 1576, 592, 1576, 592, 520, 564, 520, 564, 1578, 592, 518, 564, 520, 564, 1576, 592, 520, 564, 520, 562, 1576, 592, 1576, 592, 520, 564, 1578, 590, 1576, 594, 520, 564, 1578, 590, 1578, 590, 1578, 590, 1578, 590, 1578, 592, 1576, 592, 520, 564, 1576, 592, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 1576, 592, 1576, 592, 520, 564, 1576, 592, 1576, 592, 1576, 592, 1576, 592};
    irsend.sendRaw(rawData, 199, 38);  // Send a raw data capture at 38kHz.
    Serial.println("Turned on the AC.");
  } else if (strncmp((const char*)obj["message"], "Heat" ,4) == 0) {
    // 暖房の信号を照射
    uint16_t rawData[199] = {4500, 4394, 592, 1576, 592, 520, 562, 1578, 592, 1578, 590, 522, 564, 520, 562, 1578, 592, 520, 562, 520, 564, 1578, 592, 520, 562, 520, 564, 1578, 590, 1578, 590, 520, 564, 1578, 590, 1576, 592, 520, 564, 1576, 592, 1576, 592, 1576, 592, 1576, 592, 1576, 592, 1578, 590, 520, 564, 1578, 592, 520, 564, 520, 564, 520, 562, 520, 564, 522, 562, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 1576, 592, 1576, 592, 494, 590, 520, 564, 520, 564, 1578, 592, 1576, 594, 520, 564, 520, 564, 520, 562, 1576, 592, 1576, 592, 5156, 4500, 4392, 594, 1576, 592, 520, 564, 1576, 592, 1576, 592, 520, 564, 520, 564, 1576, 592, 520, 562, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 1576, 592, 520, 564, 1576, 592, 1576, 592, 520, 564, 1576, 592, 1576, 592, 1576, 594, 1576, 592, 1576, 592, 1576, 592, 520, 564, 1576, 592, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 1576, 594, 1576, 592, 518, 564, 520, 564, 520, 564, 1578, 592, 1576, 592, 518, 564, 520, 564, 520, 564, 1576, 592, 1576, 592};
    irsend.sendRaw(rawData, 199, 38);  // Send a raw data capture at 38kHz.
    Serial.println("Turned on the heating.");
  } else if (strncmp((const char*)obj["message"], "Stop", 4) == 0) {
    // 停止の信号を照射
    uint16_t rawData[199] = {4498, 4392, 592, 1576, 594, 520, 566, 1574, 592, 1578, 592, 520, 564, 518, 564, 1576, 592, 520, 564, 520, 564, 1576, 594, 520, 564, 520, 562, 1578, 592, 1576, 592, 520, 562, 1578, 592, 520, 564, 1576, 592, 1576, 594, 1576, 592, 1576, 592, 520, 564, 1578, 592, 1576, 592, 1578, 590, 520, 564, 494, 590, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 1574, 594, 1576, 590, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 564, 520, 568, 1574, 592, 1578, 590, 1576, 592, 1576, 592, 1576, 592, 5154, 4502, 4392, 592, 1576, 592, 520, 564, 1576, 592, 1576, 592, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1576, 592, 1576, 592, 518, 564, 1576, 592, 520, 564, 1576, 592, 1576, 592, 1576, 592, 1576, 592, 520, 564, 1576, 594, 1576, 592, 1578, 592, 518, 566, 518, 564, 520, 564, 520, 564, 1576, 592, 520, 564, 520, 564, 1578, 592, 1576, 594, 1576, 592, 518, 566, 518, 564, 494, 590, 520, 564, 520, 564, 520, 566, 518, 564, 520, 564, 1576, 592, 1576, 594, 1576, 592, 1576, 592, 1580, 588};
    irsend.sendRaw(rawData, 199, 38);  // Send a raw data capture at 38kHz.
    Serial.println("Stopped the AC.");
  }
}

void mqttLoop() {
  if (!mqttClient.connected()) {
    connectAWSIoT();
  }
  mqttClient.loop();
}

void loop() {
  mqttLoop();
  delay(10000);
}
```
*※ M5StickC Plus の場合は、`#include <M5StickC.h>` の部分を `#include <M5StickCPlus.h>` に置き換えてください。*


### テストしてみる

AWS IoT > 管理 > すべてのデバイス > モノ > myM5StickC　を開きます。
[アクティビティ]タブを開き、「MQTTテストクライアント」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/e6c49e6a-7893-3172-1237-50372d7e6b7e.png)


[トピックに公開する]タブを開き、トピック名欄に「$aws/things/myM5StickC/shadow/update/delta」を入力し、メッセージペイロード欄に「Cool」「Heat」「Stop」のいずれかを入力して発行ボタンをクリックしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/5d7a290f-92fb-0502-3576-f9a133772392.png)

これで、エアコン操作が実行できれば成功です。


# 続き
[後編](https://qiita.com/jonxjon/items/da2251cabff5058abbdb)に記載します。