AWS IoTとESP32を利用してAlexaに（物理的に）電気のスイッチを操作してもらう

# はじめに
Amazon Echo買ったけど、使わずに結局放置している方多いんじゃないでしょうか？？（私だけ？:thinking:）
周りの人をみてみると、Alexaは家電の操作をメインの使い方にしている方は良く使っているみたいですね。
しかーし、わざわざAlexa対応家電なんか買ってるとお金が...:sob:

買う余裕がない⇨**作ればいい**

発想の転換というやつですかね。知らんけど。
ということでとりあえず電気のスイッチを押してもらうものを作りました。
せっかくなので作り方を共有します。


# 完成物
まずはじめに完成物をどうぞ
古いバージョンなのでマウンタがなく、完成のものとは少し見た目が違いますがこのような感じです。
![IMG_20190315_162503.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/35d5ba26-7c86-20e5-05df-0323eb9b56ca.jpeg)
このように１台のESP32で２台のサーボを操作するものを作成していきます。

1台ですが動いている様子はこちら [^1]
ちょっと品質悪いですが我慢してください。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">動作デモ <a href="https://t.co/39iSgwlGMV">pic.twitter.com/39iSgwlGMV</a></p>&mdash; ふなし (@koni428) <a href="https://twitter.com/koni428/status/1144533769237348352?ref_src=twsrc%5Etfw">2019年6月28日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#環境
###プログラミング環境
  - Python 3.7
  - Arduino v1.8.8(ESP32へ書き込めるようセットアップ済みとする）
  
###使用機器・部品
  - ESP32
  - ブレッドボード
  - サーボモータ SG90 * 2個
  - 強力両面テープ

# 概要
今回のシステムの大まかな構成図はこんな感じです。

![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/645138d6-39f3-64e6-75a5-92c7495c77d1.png)


#作り方
かなり詳しく書くつもりなので、わかるところはどんどん読み飛ばしてください。
一部は[Amazon公式チュートリアル](https://developer.amazon.com/ja/blogs/alexa/post/6cca52f7-1008-4506-9d75-283555c628d3/how-to-create-smart-home-jp-skill-1)の手順を参考にしています。ぜひこちらも参照してみてください。
##AWS IoT
今回、AWSIoTで使用する中心の機能として、MQTTプロトコルでの通信とshadow機能です。
MQTTとは、IoT向けのPubSub型軽量プロトコルとなっており、ざっくり説明すると中央で全てを管理しているサーバが存在し、指定したトピックに対して書き込みができたり、購読しているトピックに変更があると通知が来るような仕組みになっています。あまり詳しくはないので調べてください。
Shadow機能は[Classmethodsさんの解説記事](https://dev.classmethod.jp/cloud/aws-iot-things-shadow/)がわかりやすいです。
では早速セットアップしていきましょう。

###リージョンの設定
**重要**
**AWSのリージョンを米国西部（オレゴン）に変更しましょう**
私はこれで時間を無駄にしました:sob:
![Lambda_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/e9ccd741-7175-422c-c74e-9c5d266f8204.png)

### AWS IoTでモノのポリシーを作成する
AWS IoT Coreを開いた後、左側のところから「安全性」⇨「ポリシー」と進み、「ポリシーの作成」をクリックしましょう。

ポリシーは以下の画像のように作成しましょう。
妥協した設定なので、詳しく設定可能な方は設定してください。
![AWS_IoT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/6cab8a4f-183f-6fc5-4054-972c3e1912f0.png)


入力できると「作成」を押して作成しましょう。



### AWS IoTにモノの登録をする
AWSIoTとESP32を紐付けるためにAWS IoTを使っていきます。
まずAWS IoT Coreを開き、左の「管理」⇨「モノの登録」⇨「単一のモノを作成する」の順に進みます。

この画面では名前のみ決め、次に進みます。
![AWS_IoT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/ec56b4c5-91c6-5a3a-887b-a6c5d3ac4c8a.png)
証明書を作成し、
![AWS_IoT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/bc668c05-d43a-e7a7-a08c-0fb3cc4cf5f5.png)
証明書をダウンロードします。
また、必ず有効化を忘れないようにしましょう。
![AWS_IoT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/6db027fa-6879-4d48-ed2c-ba4be9fda965.png)
![スクリーンショット_2019-06-22_4_16_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/c1f17b2f-fd5a-3eaf-5ad1-4194923adf78.png)

##ESP32

### ESP32とAWS IoTを接続する
####Arduinoに必要ライブラリを導入する
必要となるライブラリは

- PubSubClient
- ArduinoJson(version5系を入れてください）

どちらもライブラリマネージャから導入可能です。
導入方法はググってください。（手抜き:stuck_out_tongue_winking_eye:）

#### スケッチを書き換える
まず、[ここ](https://github.com/konikoni428/powerPotchin/tree/master/ESP32)から私が作成したスケッチをダウンロードしてください。

`10, 11行目`にwifiの設定、`14行目`のendpointの設定、`40行目、61行目`の証明書の設定を書き換えましょう。
14行目のendpointの設定はAWS IoT Core⇨管理⇨先ほど作成したモノ⇨操作の中にあるRestAPIエンドポイントです。
40行目,61行目の証明書は先ほどダウンロードした中身をひたすらコピペしていきます。

書き換えが完了するとESP32に書き込んでみましょう。
![シリアルモニタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/4a20879f-7432-a136-c8f6-17a5bb117921.png)
このようにPublishedが表示されるとOKです！
Error=-2が出た場合は証明書が間違ってる可能性が高いです。
Error=-1はAWSIoTで指定したポリシー違反を起こしていると思います。（今回は何も拒否していないので大丈夫だと思います）

私はWiFiが不安定な事象が発生したのですが、ボードマネージャからESP32用のボードをv1.0.2からv1.0.0にしたところ改善しました。


## AWS Lambda
Lambdaいいですよね。
Lambdaをざっくり解説すると、何か実行するプログラムを書いておき、何かのサービスをトリガーにしてそのプログラムを実行してもらえるサービスです。
しかも、そのトリガーが発火してからサーバーが勝手に立ち上がり、処理が終わると勝手に死亡するのでサーバ管理が全く必要ありません。しかも時間課金で無料枠いっぱい。神かよ。
今回はAlexaからの入力をトリガーにしてAWSIoTへデータを流すor現在の状態をAlexaに返答するといったことに使います。

###Lambda関数作成
**超重要**
**リージョンをオレゴンに変えましょう。**東京で作るとAlexaConsoleで弾かれます。
これからの画像は東京リージョンになってるとこもありますが、気にしないでください。
![Lambda_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/e9ccd741-7175-422c-c74e-9c5d266f8204.png)

こんな感じで関数名だけ決めて作りましょう。言語はPython３.７を使用します。
![スクリーンショット 2019-06-22 2.10.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/7d388cae-7a7a-c1b0-45f2-5774dac57e01.png)


###Roleへのポリシーの追加
AWS IAM⇨ロールに移動し、先ほど自動で作成されたロールを探します。
関数名-role-*****のような形になっているはずです。
それをクリックすると次のページで「ポリシーをアタッチします」という青いボタンが出現するのでためらわず押しましょう。
次に上の方にある「ポリシーの作成」というボタンを押します。

JSONタブを選び、下のJSONファイルをコピペしましょう。
![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/cfdd0b69-61c4-040d-cc49-4afde8c834ae.png)


```json:policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iot:GetThingShadow",
                "iot:Publish"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

そのあとはポリシーの確認⇨名前の設定⇨ポリシーの作成の順に行うと大丈夫です。
これでポリシーの作成は完了したため現在のタブを閉じ、「ポリシーをアタッチします」のボタンを押した後の画面に移動しましょう。
その後はこの画像の通り作成したポリシーを選択し、右下のポリシーのアタッチを行います。
![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/7b77520f-5ded-330c-a846-ebac017acaf3.png)

これでポリシーの設定は完了です。

### Lambda関数の中身を作る
[ここ](https://github.com/konikoni428/powerPotchin/tree/master/Lambda)からファイルをダウンロードしてください。
このコードは[Amazon公式チュートリアル](https://developer.amazon.com/ja/blogs/alexa/post/6cca52f7-1008-4506-9d75-283555c628d3/how-to-create-smart-home-jp-skill-1)で配布されているコードをベースに改変しています。ありがとうございます。

ここでは変更する必要のあるファイルは`config.json`のみです。

```json:config.json
{
    "DEVICES_CAPABILITY": [
        {
            "endpointId": "lightUp",
            "friendlyName": "上の電気（呼び出しに必要な名前）",
            "description": "説明（AlexaAppに表示)",
            "manufacturerName": "your name",
            "displayCategories": [
                "LIGHT"
            ],
            "cookie": {
                "extraDetail1": "optionalDetailForSkillAdapterToReferenceThisDevice"
            },
            "capabilities": [
                {
                    "type": "AlexaInterface",
                    "interface": "Alexa.PowerController",
                    "version": "3",
                    "properties": {
                        "supported": [{
                            "name": "powerState"
                        }],
                        "proactivelyReported": true,
                        "retrievable": true
                    }
                },
                {
                    "type": "AlexaInterface",
                    "interface": "Alexa",
                    "version": "3"
                }
            ]
        },
        {
            "endpointId": "lightDown",
            "friendlyName": "下の電気",
            "description": "部屋の下の電気",
            "manufacturerName": "your name",
            "displayCategories": [
                "LIGHT"
            ],
            "cookie": {
                "extraDetail1": "optionalDetailForSkillAdapterToReferenceThisDevice"
            },
            "capabilities": [
                {
                    "type": "AlexaInterface",
                    "interface": "Alexa.PowerController",
                    "version": "3",
                    "properties": {
                        "supported": [{
                            "name": "powerState"
                        }],
                        "proactivelyReported": true,
                        "retrievable": true
                    }
                },
                {
                    "type": "AlexaInterface",
                    "interface": "Alexa",
                    "version": "3"
                }
            ]
        }
    ],
    "thingsName": "powerPotchinThings"
}
```
`DEVICE_CAPABILITY`で定義するデバイスを書いていきます。
今回は1台のESP32で２つのスイッチを操作する予定なのでlightUp,lightDownの２つを定義しています。
（注：lightUp,lightDownの名前を変更するとArduinoのスケッチを変更する必要があります）
（注：サーボ１台でいい場合はlightDownのブロックを消すといいと思います。)
ここで変更するのは`friendlyName`,`description`,`manifactureName`,`thingsName`のところのみです。
`frienlyName`はAlexaから呼び出す名前になるので、呼びやすい名前に変更してください。
`thingsName`はAWSIoTで設定したモノの名前です。

`discription`,`manifactureName`は適当で大丈夫。

### コードの説明
飛ばしても大丈夫です。

まず、このLambdaに飛んでくるリクエストとして、デバイスを発見するための通信と、デバイスの状態を確認orデバイスの状態を更新させる通信があります。
デバイスを発見する通信は以下に挙げるhandle_discover_v3で処理しています。
といってもconfigのDEVICE_CAPAVILITYを読み込んで返却しているだけですね。

```python:lambda_handler.py
# v3 handlers
def handle_discovery_v3(request):
    with open('config.json') as f:
        config = json.load(f)
        devices_capability = config['DEVICES_CAPABILITY']
    response = {
        "event": {
            "header": {
                "namespace": "Alexa.Discovery",
                "name": "Discover.Response",
                "payloadVersion": "3",
                "messageId": get_uuid()
            },
            "payload": {
                "endpoints": devices_capability
            }
        }
    }
    return response
```

こちらは発見のための通信ではないものが全て流れてきます。
重要なのが`request_namespace`であり、`Alexa.PowerController`はデバイスの電源の状態を制御するために使われます。[ここ](https://developer.amazon.com/ja/docs/device-apis/alexa-powercontroller.html)で詳しいドキュメントが見れます。
`Alexa`の場合はデバイスの状態を確認するために使われており、[ここ](https://developer.amazon.com/ja/docs/device-apis/alexa-interface.html)でドキュメントが見れます。
返却値はそちらを参照してもらうとして、デバイスの制御に重要なのはどのデバイスをON、OFFどちらにするのかであり、その値は`request_device`,`value`に格納されています。それをAWSIoT側に渡していますね。

```python:lambda_function.py
def handle_non_discovery_v3(request):
    request_namespace = request["directive"]["header"]["namespace"]
    request_name = request["directive"]["header"]["name"]
    request_device = request["directive"]["endpoint"]["endpointId"]

    if request_namespace == "Alexa.PowerController":
        if request_name == "TurnOn":
            value = "ON"
        else:
            value = "OFF"

        iot.publish(request_device, value)

        response = {
            "context": {
                "properties": [
                    {
                        "namespace": "Alexa.PowerController",
                        "name": "powerState",
                        "value": value,
                        "timeOfSample": get_utc_timestamp(),
                        "uncertaintyInMilliseconds": 500
                    }
                ]
            },
            "event": {
                "header": {
                    "namespace": "Alexa",
                    "name": "Response",
                    "payloadVersion": "3",
                    "messageId": get_uuid(),
                    "correlationToken": request["directive"]["header"]["correlationToken"]
                },
                "endpoint": {
                    "scope": {
                        "type": "BearerToken",
                        "token": "access-token-from-Amazon"
                    },
                    "endpointId": request_device
                },
                "payload": {}
            }
        }
        return response
```

デバイスの状態アップデートをAWSIoT側に渡すコードの中身はこのようになっています。

```python:iot.py
# -*- coding: utf-8 -*-

import json
import boto3

iot = boto3.client('iot-data')
with open('config.json') as f:
    config = json.load(f)
    things_name = config['thingsName']
    
def publish(device_name, state):
    topic = f'$aws/things/{things_name}/shadow/update'
    payload = {
        "state": {
            "desired": {
            }
        }
    }
    payload["state"]["desired"][device_name] = state
    iot.publish(
        topic=topic,
        qos=0,
        payload=json.dumps(payload, ensure_ascii=False)
    )
    return True
```
このようなpayloadを作り、AWSIoT側に渡しています。

```json:payload.json
{
    "state": {
        "desired": {
            "lightUp": "ON"
        }
    }
}
```

AWS IoTではモノから報告された状態と、desiredで報告された値に差が出るとdeltaトピックに差分を報告します。
ESP32ではそのトピックを購読してあるので差分を解消するようにデバイスを操作してあげればOKですね。

### Lambdaにデプロイする
先ほどダウンロードし、一部書き換えたものをzipに圧縮しlambdaにアップロードします。
圧縮する際は下の画像のようにファイル、フォルダを全部選択して圧縮し、解答したときに余分なフォルダが出来ないようにしましょう。
![スクリーンショット_2019-06-22_15_05_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/903af846-abae-9d41-91f0-b630424d42f5.png)

圧縮ができるとLambdaにアップロードします。
<img width="1300" alt="スクリーンショット_2019-06-22_15_33_52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/3c720fa7-2894-e7c7-4961-3dc8f9cd886b.png">
こんな感じでデプロイしましょう。

すぐにこの画面を使うのでそのままにしておいてください。


## Alexaスキル
Alexaに自作のスキルを登録していきます。
[公式参考ページ](https://developer.amazon.com/ja/docs/smarthome/steps-to-build-a-smart-home-skill.html)



###Alexaスキル登録
まずはじめにAlexa開発者登録を行います。
[こちらのページ](https://developer.amazon.com/alexa/console/ask)からいつも使用しているAmazon.co.jpのid,passでログインしましょう。
amazon.comのアカウントも所持している方はpassが同一だと日本のアカウントにログインできない問題が起こる可能性があるので、違うものに変更しておくことをお勧めします。

ログインできるとスキルの作成と進み、スキル名を入力し、スマートホームを選択します。
<img width="1010" alt="Alexa_Developer_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/d753f97d-61dc-f1ff-d52f-8654464a5483.png">
選択したらスキルの作成を押して次の画面に移動しましょう。

この画面ではまず、スキルIDをLambda関数側にコピーする必要があります。
<img width="1093" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3236323331342f66363565633761632d343232642d613461312d353164352d6533633631383162653862622e706e67.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/b11b6fbd-83fd-dfaf-b849-21ad8a4b175e.png">
:arrow_up:AlexaConsoleの画面の囲っているIDを:arrow_down:のLambdaの画面に貼り付けましょう
<img width="1030" alt="Lambda_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/ee07b01d-2690-4add-64a5-9c2ed49d6ec8.png">
この様にコピペしてから右下の追加を押してから右上の保存を押してLambda関数を保存してください。

最後に、Lambdaの右上にあるARNをコピーしておきましょう。
Lambdaの画面↓
<img width="1351" alt="Lambda_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/44937dbd-5a0a-d7a8-ae75-b91fd38356fd.png">

そしてそれが終わると、コピーしたARNをAlexa側に登録します。
AlexaConsoleの画面↓
<img width="1115" alt="Alexa_Developer_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/474a56c5-d9f9-9773-abee-5f35b4869a05.png">

特にエラーなく完了すると大丈夫です！

###アカウントリンクの設定
次にアカウントリンクを設定します。
OAuth2.0を使ってアカウントとリンクさせる機能を提供する必要があるのですが、Login with AmazonというAmazonのアカウントを使ってログインするものがAmazonより提供されているのでそれを使う様にセットアップしていきます。
まず、[Login with amazonのコンソールページ](https://developer.amazon.com/loginwithamazon/console/site/lwa/overview.html)に移動しましょう。
そこでセキュリティプロファイルの新規作成を行います。

- セキュリティプロファイル名
- セキュリティプロファイルの説明
- プライバシー規約同意書URL

の入力欄があると思うのですが、適当に埋めましょう。外部に公開するわけではないので、規約同意書URLはexample.comなどで大丈夫です。

登録が完了すると:gear:マークからWeb設定に移動します。
そこでは許可された返信URLをAlexaConsole側のリダイレクト先のURIを設定し、AlexaConsole側の設定は以下の様に入力しましょう

| 設定項目     |      値|
|:--------------------|----------------------:|
| 認証画面のURI     |      https://www.amazon.com/ap/oa|
| アクセストークンのURI|   https://api.amazon.com/auth/o2/token |
| クライアント ID     |   login with amazonに表示 |
| クライアントシークレット|   login with amazonに表示 |
| スコープ|   profile |

![alexa_account_link.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/b2086bbe-941f-92c3-6d00-1630e771f6fd.png)
保存を押して、正常に保存されるとOKです。

## Alexaアプリ
ここからはAlexaアプリでスキルを有効化してデバイスの検索をしていきます。
スマートフォンにAlexaアプリを入れてることを前提とします。

### Alexaスキルの有効化
Alexaアプリでスキルの画面に移動し、有効なスキル⇨開発⇨先ほど作成したスキル名に移動します。
有効にして使用するを押して手順に従うと、最終的にデバイスの検索が始まって２台のシーンが検出されるとOKです。
ここでログイン画面がでない場合はアカウントリンクの設定が怪しいです。
デバイスが検出されない場合はLambdaが怪しいです。

### 名前の変更について
Alexaアプリの最初の画面に戻り、右下のデバイスを選ぶと、照明のボタンが上に存在すると思うので押すと、config.jsonで設定した`friendlyName`の値が反映されているはずです。
名前を変更したい場合は一度デバイスをアプリで削除してからLambdaの`friendlyName`を更新してから新しいデバイスの追加を行うと新しい名前で見つけることができると思います。

###ESP32までデータが流れるか確認する
Alexaアプリからモノの状態を変更すると、Alexa->Lambda->AWS IoT->ESP32という順にデータが流れていきます。ということでAlexaアプリでON,OFFを切り替えてESP32のシリアルモニタにその情報が流れてきているか確認しましょう。

ON,OFFを切り替えたときにこのような表示があればOKです。

```text:一部です
Received. topic=$aws/things/powerPotchinThings/shadow/update/delta
lightDown -> OFF
```
ここまで完成するとあとはハードウェア側のセットアップです。


##ESP32

###サーボモータをつなぐ
```c++:arduino.ino
#define LIGHT_UP_PIN 27
#define LIGHT_DOWN_PIN 25
#define BUTTON_PIN 0
```
こちらに定義したピンにpwm信号が流れるようになっています。なので、`LIGHT_UP_PIN`,`LIGHT_DOWN_PIN`に指定したピン番号にサーボモータのオレンジの線が繋がるようにつなぎましょう。
また、`BUTTON_PIN`はその場でスイッチを切り替えたい場合に使うスイッチ用のピンとなっています。外付けでプルアップ抵抗を繋ぐことを想定しています。（書き換えることのできる方は内臓プルアップに変更も可能です）
![esp32-alexa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/c109041e-a0c6-552f-b133-007798fbe29f.png)

接続が完了するとボタンを押したりAlexaアプリからON,OFFを切り替えたりしてサーボモータが動くか確かめましょう。

##モーターを固定するマウンタを作る。
３Dプリンタを使って作ります。
~~ない方は買いましょう。~~
なくても両面テープでくっつけるだけでもなんとかなります。力が逃げてスイッチが押せなくなったりするので、何かしらの方法でマウンタを作ることをお勧めします。
Fusion360でサクッと作ったモデルが[こちら](https://a360.co/2FOhwDl)から閲覧・DL可能です。使えそうなら使ってください。
使用例はこんな感じ
![IMG_20190628_153719.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/0c3e4ec9-0ac3-c8bf-f401-af6749a5b5ef.jpeg)


##設置
ブレットボードをいい感じのところに貼り付けて、ESP３２の電源を確保すると完成！！:heart_eyes: [^2]
![IMG_20190628_172134.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262314/12ea72a0-17b9-b05d-35e1-6eabe662eeba.jpeg)

##モーターの角度を調整する
ArduinoのスケッチのswitchLightをいじってください。

```c++:arduino.ino
void switchLight(char* state, char* deviceName) {
  int ch;
  if(!strcmp(deviceName, "lightUp")) ch = 0;
  else if(!strcmp(deviceName, "lightDown")) ch = 1;
  
  if (!strcmp(state, "OFF")) {
    if(ch == 1){
      ledcWrite(ch, 80);<-これ
    }else{
      ledcWrite(ch, 80);<-これ
    }
    delay(150);
    ledcWrite(ch, 0);
  } else if (!strcmp(state, "ON")) {
    if(ch==1){
      ledcWrite(ch, 105);<-これ
    }else{
      ledcWrite(ch, 105);<-これ
    }
    delay(150);
    ledcWrite(ch, 0);
  }
}

```

#最後の独り言
やっと記事にできた。
どこまで詳しく書くべきなのか難しいですね。

ここ間違ってるよ！
こうする方がいいよ！といった指摘あれば大歓迎ですのでどしどしどうぞ。

そんなことより何かいいインターンないですかねぇー。
チーム開発を学びたい。

[^1]: 動画貼るためにわざわざTwitterを使うのどうにかならんのか。
[^2]: 設置場所の都合上サーボモータ１個です。