AWSIoTをC#から操作する方法(Windowsアプリ)

# はじめに
[AWSIoT](https://aws.amazon.com/jp/iot/) は便利。
マイコンやラズパイからクラウドにセンサーデータを送信したり、
AWSのサイトからモーターを制御する、ということがお手軽に出来る。

技術記事も充実しており、マイコンやラズパイからAWSIoTのモノ（クラウド）と通信して何かを実現する記事は溢れている。
[Raspberry pi + AWSで温度をスマホに出力させる](https://qiita.com/yanbou893/items/d5706dfbfd8cf5bf3bf0#raspberry-pi%E3%81%A8aws-iot![2021-09-26_18h34_55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/53557340-a2e3-8c42-fac2-a60d6a905df6.jpeg)
%E3%82%92%E7%B9%8B%E3%81%90)
[Raspberry PiとAWS IoTでLチカしてみた](https://dev.classmethod.jp/articles/raspberry-pi-aws-iot-l-chika/)
[RaspberryPiとAWS IoT CoreでMQTT通信をしてみた](https://qiita.com/pega/items/93ee469103b920477f72)

一方、スマホやPCからAWSIoTに接続してみた、という記事は少ない。
（AWSIoTを使いたい層のメインが組み込みだから？）

しかし、センサーデータはアプリやWEBで見られる必要があるし、
モーターは(遠隔の)PCから操作できなければならない。
マイコン側だけでは片手落ちで、クライアント側アプリも一緒に開発する必要がある。

AWSIoTを使ったIoTシステムの例を構成図にした。
この図の右側を開発したい。

![AWSIoTCS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/737aefd7-8e2b-4118-2df7-8a1a4a4093d0.jpeg)

sundarnarasimanさんが作成されたC#＋AWSIoTの[サンプル](https://github.com/aws-samples/iot-dotnet-publisher-consumer)があったため、これをベースに作っていく。

# 目次
## やりたいこと
C#のデスクトップアプリからAWSIoTに対してMQTT通信（送受信）を行う。

## 環境
Windows10
VisualStudio2019
作成済のAWSアカウント

## 手順
### モノづくり
お決まりの日本伝統モノづくり。
最近、UIが変わったみたいだが気にしない。

① AWSの準備
下記の記事の「AWSの準備」章に従ってAWSIoTでモノを作成する。
[Raspberry PiでAWS IoT Coreと接続し、GPIO制御をしてみた]
(https://qiita.com/gnk263/items/a7937259746c81a6b052)

注意点

+ ポリシーの設定(下記)を忘れないこと！ ここで許可されていないと通信できない。
![2021-09-26_18h34_55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/2dbc1263-7fc5-6a2b-9fcf-36420acecde3.jpeg)
+ 証明書とキー(下記)をすべてダウンロードする。ダウンロードしたファイルは1つのフォルダにまとめて保存する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/2aa69f3c-a7c8-4d6d-3f61-a7ac42895b82.png)


② PKCS12にする
.NetAPIでは.pemファイルは扱うことができないため、.pfx形式に変更する必要がある。コマンドプロンプトからOpenSSLを使用して変換する。

コマンドは下記
（.pem .key .crtファイルはダウンロードしたファイル名、.pfxは任意のファイル名）

```aws.bat
openssl pkcs12 -export -in certificate.cert.pem -inkey certificate.private.key -out certificate.cert.pfx -certfile AmazonRootCA1.crt
```
パスワードを入力する必要があるが、後で使うのでメモしておく。

sundarnarasimanさんが作成された[サンプル](https://github.com/aws-samples/iot-dotnet-publisher-consumer)ではより詳しく解説している。

WindowsだとデフォルトでOpenSSLコマンドが使えないため、[記事](https://oji-cloud.net/2021/03/26/post-6040/)を参考にインストールする。

### アプリケーションの作成
① デスクトップアプリケーションの作成
Visual Studio2019を起動して「Windowsフォールアプリケーション(.Net Framework) 」を選択し、プロジェクトを作成する。

② MQTTパッケージの追加
Visual Studio > プロジェクト名を右クリック > Nugetパッケージの管理 から　M2mqtt をインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/90bed337-cd33-391d-2c8a-6c9c41786464.png)

③ソースコードを作成する

```AwsComm.cs
internal class AwsComm : IAwsiot
    {
        public string endpoint => "xxxxx.amazonaws.com";
        public string topic => "xxxx";
        public string caname => "xxx.crt";
        public string pfxname => "xxx.pfx";
        public string pfxpassword => "xxxxxx";

        private MqttClient client;

        public void Connect()
        {
            var caCert = X509Certificate.CreateFromCertFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, caname));
            var clientCert = new X509Certificate2(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pfxname), pfxpassword);
            this.client = new MqttClient(endpoint, 8883, true, caCert, clientCert, MqttSslProtocols.TLSv1_2);
            this.client.MqttMsgPublishReceived += PublishReceived;

            string clientId = Guid.NewGuid().ToString();
            this.client?.Connect(clientId);
            this.client.Subscribe(new string[] { topic }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE });
        }

        public void Disconnect()
        {
            this.client?.Disconnect();
        }

        public void Publish(string message)
        {
            this.client.Publish(topic, Encoding.UTF8.GetBytes($"{message}"));
        }

        public void PublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            var awsdata = new AwsData(e);
            awsdata.DataChangeFlag = true;
        }
    }
```

ソースコード全文は以下
https://github.com/ikenohotori/AWSIoTSample

下記は自分で作成した値を入力する。
endpoint => "xxxxx.amazonaws.com";
public string topic => "xxxx";
public string caname => "xxx.crt";
public string pfxname => "xxx.pfx";
public string pfxpassword => "xxxxxx";

endpoint→
AWS IoTコンソール > 設定 で確認する。
topic→
好きな値で問題ない。※AWSコンソールで確認する時に使用する。
caname、pfxname、pfxpassword→
作成した各ファイル・パスワード名。ファイルを格納した場所にパスを合わせる。
## 動作確認
AWSコンソール>テスト>MQTTテストクライアント を使ってアプリの動作を確認する。
![2021-10-10_19h11_07.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/91c15135-5a7d-ef49-a7d1-dcdc565d366a.gif)
前半：アプリからawsトピックに「test!!」を送信
後半：AWSコンソールからawsトピックに「OK!!」を送信

# 最後に
送受信はすごく簡単に出来た！！
課題としては、受信処理が100msごとにクラウド上のトピックに対して確認を行っているため、アプリの処理が重くなる＆送受信の間で遅延(約200ms)が発生している。デバイスシャドウを利用して、トピック更新後に即アプリに通知される仕組みを実装していきたい。