VSCodeを使ってAzureでIoT開発

以前、[AzureでIoT系のサービスをサラッと(?)使ってみよう](https://qiita.com/mstakaha1113/items/1c9b8f61452147a87640)というまったく"サラッと"使えていない記事を投稿したのですが、「VSCodeの使い方を理解するネタにできるんじゃない？」と思いまして、同じことをVSCodeからやってみたいと思います。全部やると長くなってしまうので、最初の方だけです。
という訳で、ネタは使いまわしつつ、VSCodeを使う上で基本的な部分にフォーカスしていきたいと思います。


# はじめに
以前の記事を軽くおさらいします。
詳細は上記リンクからご確認ください。
扱ったシナリオは以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/7f891a02-27cf-a864-3d1a-0317a6fc5c32.png)


シナリオ０：デバイスとIoT Hubを接続し、デバイスとAzureがやり取りできるようにします。
シナリオ１：デバイスからのデータ（テレメトリーデータ）を取得したら、それをStorageに保存します。
シナリオ２～５：今回は省略！

シナリオ０では、IoT Hubを作成し、デバイスに投入するサンプルプログラムを作成、接続しました。
シナリオ１では、IoT Hubの"Consumer Group(消費者グループ)"を使ってテレメトリーデータのコピー品を作成し、そのデータをFunctions経由でBlobに保管しました。
今回は、この２つをVSCodeでやってみます。

環境はAzure上にVMを立てました。
そのうえで日本語取り扱いの環境にしています。
開発言語はC#を選択しています。

# VSCodeを準備
## VSCodeをインストール
まずはVSCodeを準備します。
https://azure.microsoft.com/ja-jp/products/visual-studio-code/
こちらからダウンロードします。
ウィザードを信じて次へ次へとクリックしインストールが完了です。
## .Net Coreのインストール
https://dotnet.microsoft.com/download/dotnet-core
↑ここからダウンロードしてインストールします。
今回は3.1を入れます

## Azure Functions Core Toolsのインストール
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash
↑ここを参考にインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/12d426e8-ec03-cc2c-eb93-a4e5e44416db.png)


## 拡張機能のインストール
VSCodeはさまざまな拡張機能をインストールすることで、自分好みに成長してくれます。
拡張機能は画面左のアイコンから"EXTENSIONS"というものを選択してインストールしていきます。
インストールするものによってはVSCodeが再起動しますので、順番に１つずつ入れていきましょう。
拡張機能はたくさんありますので、探すヒントになる検索文字も記載しておきました。
画面上部の検索窓に打ち込んで探しながらインストールしていきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/008fa979-5fca-fc57-e497-9a6ab904027a.png)

|入れるもの|検索文字|概要|
|:--|:--|:--|
|Japanese Language Pack for VS Code|Japan|VSCodeの日本語化(必須じゃないです)|
|Azure Account|Azure|Azureのアカウントに接続する|
|Azure Storage|Azure|Azure Storageを扱う|
|Azure Functions|Azure|Azure Functionsを扱う|
|Azure IoT Tools|Azure|Azure IoT Hubを扱う、IoT Hubじゃなくて **IoT Tools** ですのでお間違えなく|
|Azure Storage Explorer|Azure Storage|Azure Storageの中を見るExplorer|
|C#|C#|今回はC#を使いますのでC#を入れます|

この拡張機能を使い、VSCodeでやれるだけやって、できない分はAzurePortalかコマンドで逃げます。


## Azureに接続
拡張機能にはグラフィカルに利用するものもありますが、コマンドパレットを活用するものが多数存在します。
コマンドパレットになれる意味も含め、まずはコマンドパレットでAzureに接続してみたいと思います。
[表示]→[コマンドパレット]でも良いですし"Ctrl+Shift+P"でも良いので、コマンドパレットを開きましょう。
開いたら、"Azure: Sign In"と入力してEnterします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/58a9d358-b13c-a192-5cb6-fb6b31e68d8c.png)
すると、ブラウザが起動しサインインを求めてきます。
ご自身のAzure環境にログインするつもりでサインインを実施しましょう。
サインインが成功したら、ブラウザは閉じても大丈夫です(まぎらわしいのでタブを閉じましょう)。

# IoT Hubの作成とサンプルプログラム(デバイス)の実行：シナリオ０
VSCodeからIoT Hubを作成し、デバイス接続文字列を取得、サンプルプログラムの実行までを行います。
## IoT Hubの作成
ここでもコマンドパレットを使います。
"Ctrl+Shift+P"でコマンドパレットを開いて、"Azure IoT Hub: Create IoT Hub"というコマンドを探して実行します。
"Azure IoT"くらい打ち込んでキーワード検索しましょう。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|サブスクリプション|任意のものを選択|
|リソースグループ|今回は"+Create～～"を選択し"iotsamplegroup"と入力しました|
|location|東日本を選択しました|
|tier|F1:Freeを選択しました|
|IoT Hub name|世界で１つの名前を付けてください。ボクは"matakahasampleiothub"としました|

画面右下に作成中メッセージが出ますので、数分待ちます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/81cc23e5-b1f2-59eb-5131-cf6bcfe07f17.png)
作成が終わると、出力ウィンドウに"created"とのメッセージが出ます。
本当にできたのか心配な方は、１度AzurePortalに入って確認してみましょう。
"エラーになった"という方、表示されるログを確認しつつ、何度かトライしてみましょう。

## 接続するデバイス(のIDと接続文字列)の作成
"Ctrl+Shift+P"でコマンドパレットを開いて、"Azure IoT Hub: Create Device"というコマンドを探して実行します。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|デバイスID|任意のものを入力、ボクは"device001"にしました|

## プログラムの作成
こちらもコマンドパレットを使ってみます。
"Ctrl+Shift+P"でコマンドパレットを開いて、"Azure IoT Hub: Generate Code"というコマンドを探して実行します。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|デバイスID|先ほど作成したデバイスID|
|開発言語|今回はC#を選択します|
|サンプルのタイプ|今回はSend ～～を選択してください|
|保存場所|どこかに１つフォルダを作成した上で選択してください|
画面右下に以下のようなポップアップがくると思いますので、リストアします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/fc80de85-1819-0bb9-7efb-4620e4db5a54.png)
"メッセージ消えちゃった！！"という方は、右下のベルのマークをクリックすれば出てきます。
右下には、ほかにもアイコンがありますので、適当にクリックしてみてください。
VSCodeは開発者が普段必要じゃないものは主張しないようにできているということをご理解いただけると思います。

他にもこんなメッセージが出ていれば、"Yes"をクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/61b2c4e8-334a-a5f6-273c-944ad9bd9b31.png)

今回は.Net Core 3.1を使いますので、simulated-device.csprojファイル内のTargetFrameworkをnetcoreapp3.1に更新してください。
launch.jsonも同様に更新してください。

"F5"を押下してプログラムを実行してください。こんな画面が出てくれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/ca41a5f6-eb96-5c06-4bd6-9f6330195e4c.png)
右下の緑色で囲った部分がログです。
具体的にはSimulatedDevice.csの50行目のConsole.WriteLineが出ています。
しばらく動かしたら止めてください。画面上部中央に現れたデバッグをコントロールするパネルの中から赤い四角をクリックしてデバッグを停止します。(もしくは"Shift+F5")

これでシナリオ０は終了です。


# テレメトリーデータをStorageに保存(Functions)：シナリオ１
続きまして、IoT Hubに収集されているデータをFunctions経由でBlobに保存したいと思います。
## Blobの作成
まずはBlobを作成します。
コマンドパレットから作成してみます。"Ctrl+Shift+P"で開いて、"Azure Storage: Create Storage Account...(Advanced)"というコマンドを探して実行します。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|Storage Account name|世界で１つの名前を付けてください。ボクは"matakahasampleblob"としました。|
|リソースグループ|IoT Hubと同じ"iotsamplegroup"と入力しました|
|static website hosting|Noを選択しました|
|リージョン|東日本を選択しました|

ふたたびコマンドパレットを使って保存用のコンテナを生成します。
"Ctrl+Shift+P"で開いて、"Azure Storage: Create Blob Container..."というコマンドを探して実行します。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|Subscription|今まで使ってたサブスクリプション|
|Storage Account name|先ほど作成したStorage Account|
|Blob Container name|任意の名前を付けてください。ボクは"cold"としました|

## Consumer Groupの作成
IoT Hubに新たなConsumer Groupを作成します。
詳細は割愛しますが、IoT Hubはテレメトリーデータを複数のサービスが読めるようにコピー品を保持することができます(ちょっと嘘だけど外から見たらそういうこと)。
この各々の外部サービスがテレメトリーデータを利用(消費：Consume)するためにConsumer Groupを作成します。
コマンドパレットでやりたかったのですが、見つけられなかったので普通にコマンドを打ちたいと思います。
Azure CLIが必要ですので、入っていない場合は、こちらからインストールしてください。
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-windows?tabs=azure-cli
よくわからない場合、`az version`とコマンドプロンプトで打ち込んでみましょう。

"Ctrl+@"でターミナルが起動すると思いますので起動します。
まずはAzureにログインします
`az login`
続きましてIoT Hub用のExtensionをインストール
`az extension add --name azure-iot`
こちらを参考にConsumer Groupを作成します。
https://docs.microsoft.com/en-us/cli/azure/iot/hub/consumer-group?view=azure-cli-latest#az_iot_hub_consumer_group_create
`az iot hub consumer-group create --hub-name matakahasampleiothub --name coldpath`
**--hub-nameはご自身のIoT Hubの名前を付与してください。--nameも任意の名前をご利用ください。**


## Functionsの作成
現在のVSCodeはIoT Hubのデバイスとして出来上がっていますので、Functionsは別のウィンドウで作成します。
どうでも良いTipsですが、コマンドプロンプトからVSCodeを起動したいときは"code"と入力します。
コマンドプロンプトで任意の場所に新たなフォルダを作成して、VSCodeを起動します。
`mkdir samplefunction`
`cd samplefunction`
`code .`←ピリオドも打ちましょう
現在のフォルダをルートとして、VSCodeが起動すると思います。
コマンドパレットを"Ctrl+Shift+P"で開いて、"Azure Functions: Create Function App in Azure...(Advanced)"というコマンドを探して実行します。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|Function app name|世界で１つの名前を付けてください。ボクは"matakahasamplefunciot"としました|
|runtime stack|.NET Core 3.1を選択|
|OS|Windowsを選択|
|ホスティングプラン|Consumptionを選択|
|resource group|先ほど作成したリソースグループを選択|
|storage account|先ほど作成したStorage Accountを選択|
|Application Insights|今回は"Skip for now"|

画面右下に作成中メッセージが出ますので待ちます。
入れ物ができたので、中身を作成したいと思います。
コマンドパレットを"Ctrl+Shift+P"で開いて、"Azure Functions: Create Function..."というコマンドを探して実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/f37d799b-30ed-4c98-a4c7-fad9d4d782eb.png)
このようなメッセージが出ますので"Yes"をクリックしてください。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|開発言語|C#を選択|
|テンプレート|IoTHubTriggerを選択|
|Function name|任意の名前を付けてください。ボクは"coldpath"としました|
|event hub namespace|今回は"Skip for now"|
|messages/events|デフォルトのままEnter|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/9e11cd24-92c4-37b5-e552-bb413e5a6f3f.png)

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|Storage Account|Select storage accountをクリックして、先ほど作成したBlobを選択|

FunctionsからはBlobに出力しますので、ここでBlob出力に必要なパッケージをインストールします。
ターミナルで
`dotnet add package Microsoft.Azure.WebJobs.Extensions.Storage`
と打ちます。

今回はこちらをベースにBlobへ出力しています。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-add-output-binding-storage-queue-vs-code?pivots=programming-language-csharp


できたソースコードcoldpath.csの17行目に"EventHubConnectionAppSetting"を追記、Consumer Groupの追記、またBlobへの接続を追記します。

~~~CS
public static void Run([IoTHubTrigger("messages/events", Connection = "EventHubConnectionAppSetting")]EventData message,
                       [Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg, ILogger log)

~~~

元のソースコードはログ出力しかしていませんので、Blobへの出力も追記します。

~~~CS
log.LogInformation($"C# IoT Hub trigger function processed a message: {Encoding.UTF8.GetString(message.Body.Array)}");
msg.Add(Encoding.UTF8.GetString(message.Body.Array));
~~~

また、Azure PortalでIoT Hubを開き、イベントハブ互換エンドポイントの文字列をコピーし、local.settings.jsonに追記します。
EventHubConnectionAppSettingの行が追記した行です。前の行に,(カンマ)も書いて、JSONとして成立させてください。

~~~JSON
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=matakahasampleblob;AccountKey=sIOMGVV/XgzxNv8RUk7DQfQDg==;EndpointSuffix=core.windows.net",
    "EventHubConnectionAppSetting": "Endpoint=sb://ihsuprodkwres035dednamespace.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=dS0hEvvM=;EntityPath=iothub-ehub-matakahasa-5837130-06aae86ff9",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
  }
}
~~~

実行すると、とりあえずBlob Queueに出力されます。Storageに出力したい場合は、こちらを参考に出力バインドを変更してください。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-storage-blob-output?tabs=csharp

## Functionsをデプロイする
ローカルで実行できましたので、Azure上にデプロイしたいと思います。
最後はせっかくなので、VSCodeにインストールされた拡張機能のGUIを利用したいと思います。
今まで放置してますが、画面左側にAzureのアイコンがあります。
ここをクリックしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/5df3fd88-88f8-97d1-1081-fa6383b09ba2.png)
FUNCTIONSという項目があると思います。
ここにフォーカスをあてると、次のイメージのように"Deploy to Function App"という上矢印的なマークが出ますのでクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/0af36cf1-6c37-c1f1-f906-1ba5c76b336d.png)
するとコマンドパレットが開きます。

|聞かれるもの|入れる情報のヒント|
|:--|:--|
|Function app name|先ほど作成したFunctionsを選択|

上書きOK？メッセージが出ますので許可します。
デプロイはこれで終了です。
実際に動作させるには、local.setting.jsonに記載したEventHubConnectionAppSettingの情報をFunctionsのアプリケーション設定に追加してください。


# まとめ
今回は、IoTをベースにしてVSCodeの基本的な使い方を紹介しました。
・VSCodeのインストール
・必要な拡張機能をインストールする(日本語化もここ)
・コマンドパレットはよく使う(Ctrl+Shift+P)
・VSCodeの画面は、普段コーディングに集中できるように画面の右下とか左下に機能がアイコン化されて配置されている
・コマンドプロンプトから起動するときは"Code"
・Functionsボタン1つでデプロイできた

ここで説明していないVSCodeで基本的に知っていただきたいこととしてGitとの連携がありますが、こちらはいっぱい記事がありますので省略しています。

エディタでこれだけAzureと親和性高く使えるなら十分じゃないかなと思いました。