こんな箱に入った
これ。
いわゆる、Azure Certificate な IoT DevKitってやつ。
デバイス仕様はこんなかんじ。
Microsoft Azure Certified IoT DevKit (IOT-AZ3166)ja.plugable.com
一応Arduino完全互換デバイスなのだけど、既存のESP32とかArduinoとかと違ってブートローダー的なのが入ってるのがいいかんじ。
WiFiの接続とかデバイス設定を、スケッチに埋め込まずにシェルだったりネットワーク越しに設定できる。
でもって、これをIoT Hubにつなげてみようっていうのが今回のお題。
1.まずはつなげ先のIoTHubを作る。
現状なにも作ってないので、新規作成。
適当にリソースグループと名前を設定して
今回は検証なので、フリー版を使って作成。
2.デプロイできたら、次はデバイス登録
作ったIoTHubの左にあるデバイスから、
こんなかんじで作成。
次に開発環境構築。
3.いわゆるArduinoのIDEでも良いのだけど、Azureとかモニターの親和性を考えてVisual Studio Codeに環境を作るのがおすすめらしい。
というわけで、雑に上4つぐらいと、Arduino拡張をインストールする。
4.IoTHub Extensionでさっき作ったIoTHubを選択する。
選択すると、こんかなんじでIoTHubが選択されたよっていうメッセージが出力される。
5.次にArduinoのスケッチがビルドできるようにVSCodeを設定する。
残念ながらExtensionを入れても、VSCodeがArduinoをビルドできるようになるわけではなくって、公式からダウンロードしたArduinoにパスを通して使えるようにしてくれるだけ。
あとはカスタムボードの設定も入れないといけないので、最終的にはこんなかんじ。
たぶんJSONで入れるのが一番ラクだと思う。
{ "arduino.additionalUrls": ["https://raw.githubusercontent.com/VSChina/azureiotdevkit_tools/master/package_azureboard_index.json"], "arduino.path": "C:\\Program Files (x86)\\Arduino" }
6.ここまで来たらVCodeでF1押して、Arduino Board Managerを起動。
IoTDevKitをインストール。
ここでいよいよIotDevKitをPCにつなぎます。
7.PCにつないで、もしちゃんとエクスプローラーとかデバイスマネージャで見えない人はドライバが入ってないので、ドライバを入れる。
www.st.com
8.最新バージョンは2.0.0なので、IoTDevKitのファームウェアバージョンも合わせておく。
最新のファームをここからダウンロードしてきて、エクスプローラーでぽとぺた置いて、Reset。
2.0.0が表示されればOK
microsoft.github.io
ちなみに、factory reset相当のことがやりたければ、同じバージョンで構わないのでファームを焼き直すのが手っ取り早い。
9.ついでにWiFi設定もしてしまおう。
Bボタンを押したままResetでAPモードに入から、適当なデバイスから接続。
おそらくディスプレイに192.168.0.1が表示されているので、ブラウザからアクセスすればWiFiの設定を書き込める。
こっから、開発スタート。
まずはサンプルコードを取ってくるとこから。今回はこれ。
10.VSCodeのF1からAzure IoT Device Workbench: Open Examples..を開いて
「Get Started」の「Open Sample」で新しいVSCodeを開く。
こんなかんじのコードがでてくればOK。
11.F1でビルドが通るかVerifyしてみる。
ちゃんと通ればOK。
もし通らなかったら、VSCodeの右下でデバイス設定がちゃんとされてるかチェック。
12.次にIoTHubに接続するキーになる接続文字列をAZ3166に書き込む。
F1でiot confとか打てばそれっぽいのが出てくる。
Connection stringを選んで、
IoTHubのプライマリ接続文字列を見える状態にして、貼り付け。
13.最後にデプロイしよう。
コードはArduinoだけど、AZ3166は普通のArduinoではないので、Workbenchの「Upload Device Code」でビルドしてデプロイしてくれる。
こんなかんじで、Doneになればデプロイ成功。
14.でも、現状のコードだと、気温と湿度が変わったときにしかメッセージを送らないので、毎秒送るように書き換える。
utility.cppの115行目-135行目あたり
float t = readTemperature(); float h = readHumidity(); bool temperatureAlert = false; if(t != temperature) { temperature = t; *temperatureValue = t; json_object_set_number(root_object, "temperature", temperature); } if(temperature > TEMPERATURE_ALERT) { temperatureAlert = true; } if(h != humidity) { humidity = h; *humidityValue = h; json_object_set_number(root_object, "humidity", humidity); } serialized_string = json_serialize_to_string_pretty(root_value);
の前の値チェックを外して、こんなかんじ。
float t = readTemperature(); float h = readHumidity(); bool temperatureAlert = false; temperature = t; *temperatureValue = t; json_object_set_number(root_object, "temperature", temperature); if(temperature > TEMPERATURE_ALERT) { temperatureAlert = true; } humidity = h; *humidityValue = h; json_object_set_number(root_object, "humidity", humidity); serialized_string = json_serialize_to_string_pretty(root_value);
Alertのコードが毎回falseになるけど、まぁいいや。
で、もっかいデプロイ。
きちんと成功していれば、Azure接続のLEDが光って、モニターにIoTHubに気温と湿度が投げつけられる様子が確認できる。
他のサンプルコードは読んでみるといいかな、と。
ただ、このままだとIoTHubにメッセージが届いてることはわかるけど、肝心のメッセージの内容がわかんない。
15.ちょっと高いけど(月1万円しないぐらい)、StreamAnalytics Jobでメッセージを処理してみる。
適当にこんなかんじでデプロイ。
16.デプロイできたら、入力にIoTHubを選択。
17.出力はいろいろあるけど、今回はBlobで。
ストレージアカウントがなければ適当につくって、こんなかんじ。
18.入力と出力が定義できたら、最後にそれをつなぐクエリを書く。
まぁそのまま受け取ったやつを流すだけ。
SELECT * INTO blob FROM IoTHub
19.これでしばらく放っておくと、実データを使ったクエリのテストができるようになる。
20.いい感じだったら、StreamAnalyticsを開始すれば、
Blobにこんなかんじで、年月日フォルダが作られて、
中に1日ごとのJSONが作られる。
{"messageId":882,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:27.5334971Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:43:36.2700000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:43:36.2680000Z"}} {"messageId":883,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:43:42.0520000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:43:42.0350000Z"}} {"messageId":884,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:43:47.8190000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:43:47.8200000Z"}} {"messageId":885,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:43:53.5760000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:43:53.5860000Z"}} {"messageId":886,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:43:59.3460000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:43:59.3510000Z"}} {"messageId":887,"temperature":22.399999618530273,"humidity":51.200000762939453,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:05.1120000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:05.1180000Z"}} {"messageId":888,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:10.8780000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:10.8830000Z"}} {"messageId":889,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:16.6650000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:16.6520000Z"}} {"messageId":890,"temperature":22.399999618530273,"humidity":51.400001525878906,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:22.4160000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:22.4180000Z"}} {"messageId":891,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:44:28.4387169Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:28.1810000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:28.1830000Z"}} {"messageId":892,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:44:34.1943794Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:33.9630000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:33.9490000Z"}} {"messageId":893,"temperature":22.399999618530273,"humidity":51.5,"EventProcessedUtcTime":"2022-03-03T12:44:39.8849782Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:39.7320000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:39.7300000Z"}} {"messageId":894,"temperature":22.399999618530273,"humidity":51.400001525878906,"EventProcessedUtcTime":"2022-03-03T12:44:45.5875320Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:45.4980000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:45.4960000Z"}} {"messageId":895,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:44:51.4924280Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:51.2640000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:51.2620000Z"}} {"messageId":896,"temperature":22.399999618530273,"humidity":51.400001525878906,"EventProcessedUtcTime":"2022-03-03T12:44:57.1832940Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:44:57.0290000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:44:57.0280000Z"}} {"messageId":897,"temperature":22.399999618530273,"humidity":51.400001525878906,"EventProcessedUtcTime":"2022-03-03T12:45:02.9777513Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:02.7950000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:02.7960000Z"}} {"messageId":898,"temperature":22.299999237060547,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:45:08.7803588Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:08.5690000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:08.5620000Z"}} {"messageId":899,"temperature":22.399999618530273,"humidity":51.400001525878906,"EventProcessedUtcTime":"2022-03-03T12:45:14.4601878Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:14.3340000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:14.3270000Z"}} {"messageId":900,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:45:20.1493755Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:20.1000000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:20.0940000Z"}} {"messageId":901,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:45:26.0582320Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:25.8650000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:25.8640000Z"}} {"messageId":902,"temperature":22.399999618530273,"humidity":51.299999237060547,"EventProcessedUtcTime":"2022-03-03T12:45:31.8371634Z","PartitionId":1,"EventEnqueuedUtcTime":"2022-03-03T12:45:31.6310000Z","IoTHub":{"MessageId":null,"CorrelationId":null,"ConnectionDeviceId":"AZ3166","ConnectionDeviceGenerationId":"637818519466399285","EnqueuedTime":"2022-03-03T12:45:31.6300000Z"}}
今回はStreamAnalyticsでBlobに吐いたけど、Azure Data Explorerにつなげばトラディショナル大好きExcelにデータ流せるし、Power BIとかで解析してもいいし、Azure MLとかに流してもいいかも。
長々と書いたけど、ひとまずセンサーデータをファイルに書き出せるところまでできてよかったし、AZ3166だとサンプルがしっかりあってよかったかな。
参考
公式のドキュメント
microsoft.github.io
AZ3166リファレンス
microsoft.github.io