Azure IoT Hub へのデータ送信と Azure Stream Analytics による可視化の下準備を試す（公式ドキュメントやサンプルをピックアップしつつ）

公式ドキュメント等を見ながら、Azure IoT Hub を試していきます。
（参照した公式ドキュメント・サンプルの情報は、記事の中に記載していきます）

## リソースの作成とデバイス登録
以下の公式ドキュメントの「IoT Hub の作成」・「IoT ハブに新しいデバイスを登録する」の項目の内容を進めていきます。

●Azure Portal を使用して IoT Hub を作成する | Microsoft Docs
　https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-create-through-portal

以下は、IoT Hub のリソース作成が完了した後です。
<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">そして、試していく。 <a href="https://t.co/TJAPpocM28">pic.twitter.com/TJAPpocM28</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1454791421139963927?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そして、デバイスの新規登録を行った後の画面です。
![デバイスの新規登録の後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/48b0eb9f-f730-fcca-95da-cd6cd0f715e0.jpeg)

## Node.js のサンプルを見ていく
公式のドキュメントやサンプルを見ていくと、以下のページがあり、その中に [GitHub のリポジトリへのリンク](https://github.com/azure-samples/azure-iot-samples-node/tree/master/)が掲載されていました。

●Azure IoT Samples for Node.js - Code Samples | Microsoft Docs
　https://docs.microsoft.com/ja-jp/samples/azure-samples/azure-iot-samples-node/azure-iot-samples-for-nodejs/

### 送受信用のそれぞれのサンプル
#### 受信側
受信側のプログラムについては、上記のリポジトリを見ていくと、以下のものが見つかりました。

●azure-iot-samples-node/receive_methods.js at master · Azure-Samples/azure-iot-samples-node
　https://github.com/Azure-Samples/azure-iot-samples-node/blob/master/iot-hub/Samples/device/receive_methods.js

```javascript
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

'use strict';

var Protocol = require('azure-iot-device-mqtt').Mqtt;
var Client = require('azure-iot-device').Client;

// String containing Hostname, Device Id & Device Key in the following formats:
//  "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
var connectionString = process.env.DEVICE_CONNECTION_STRING;
if (!connectionString) {
  console.log('Please set the DEVICE_CONNECTION_STRING environment variable.');
  process.exit(-1);
}

// fromConnectionString must specify a transport constructor, coming from any transport package.
var client = Client.fromConnectionString(connectionString, Protocol);

client.open(function (err) {
  if (err) {
    console.error(err.toString());
    process.exit(-1);
  } else {
    console.log('client successfully connected');
    client.on('error', function (err) {
      console.error(err.toString());
      process.exit(-1);
    });

    // register handler for 'methodName1'
    client.onDeviceMethod('methodName1', function (request, response) {
      console.log('received a request for methodName1');
      console.log(JSON.stringify(request.payload, null, 2));
      var fakeResponsePayload = {
        key: 'value'
      };

      response.send(200, fakeResponsePayload, function (err) {
        if (err) {
          console.error('Unable to send method response: ' + err.toString());
          process.exit(-1);
        } else {
          console.log('response to methodName1 sent.');
          process.exit(0);
        }
      });
    });

    // register handler for 'methodName2'
    client.onDeviceMethod('methodName2', function () {
      // ...
    });
  }
});
```

#### 送信側
送信側の例としては、以下のものが見つかりました。

●azure-iot-samples-node/send_telemetry.js at master · Azure-Samples/azure-iot-samples-node
　https://github.com/Azure-Samples/azure-iot-samples-node/blob/master/iot-hub/Samples/device/send_telemetry.js

```javascript
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

'use strict';

var uuid = require('uuid');
var Protocol = require('azure-iot-device-mqtt').Mqtt;
// Uncomment one of these transports and then change it in fromConnectionString to test other transports
// var Protocol = require('azure-iot-device-amqp').AmqpWs;
// var Protocol = require('azure-iot-device-http').Http;
// var Protocol = require('azure-iot-device-amqp').Amqp;
// var Protocol = require('azure-iot-device-mqtt').MqttWs;
var Client = require('azure-iot-device').Client;
var Message = require('azure-iot-device').Message;

// String containing Hostname, Device Id & Device Key in the following formats:
//  "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
var connectionString = process.env.DEVICE_CONNECTION_STRING;
if (!connectionString) {
  console.log('Please set the DEVICE_CONNECTION_STRING environment variable.');
  process.exit(-1);
}

// fromConnectionString must specify a transport constructor, coming from any transport package.
var client = Client.fromConnectionString(connectionString, Protocol);

client.open(function (err) {
  if (err) {
    console.error('Could not connect: ' + err.message);
  } else {
    console.log('Client connected');

    client.on('error', function (err) {
      console.error(err.message);
      process.exit(-1);
    });

    // any type of data can be sent into a message: bytes, JSON...but the SDK will not take care of the serialization of objects.
    var message = new Message(JSON.stringify({
      key: 'value',
      theAnswer: 42
    }));
    // A message can have custom properties that are also encoded and can be used for routing
    message.properties.add('propertyName', 'propertyValue');

    // A unique identifier can be set to easily track the message in your application
    message.messageId = uuid.v4();

    console.log('Sending message: ' + message.getData());
    client.sendEvent(message, function (err) {
      if (err) {
        console.error('Could not send: ' + err.toString());
        process.exit(-1);
      } else {
        console.log('Message sent: ' + message.messageId);
        process.exit(0);
      }
    });
  }
});
```

### その他のサンプル（クイックスタート）
さらにリポジトリ内を見ていくと、クイックスタートもありました。

●azure-iot-samples-node/iot-hub/Quickstarts at master · Azure-Samples/azure-iot-samples-node
　https://github.com/Azure-Samples/azure-iot-samples-node/tree/master/iot-hub/Quickstarts
![クイックスタート.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e205e9bb-96e7-2e3e-1cfc-7924a012a753.jpeg)

その中の 1つである「simulated-device」を見てみます。

●azure-iot-samples-node/iot-hub/Quickstarts/simulated-device at master · Azure-Samples/azure-iot-samples-node
　https://github.com/Azure-Samples/azure-iot-samples-node/tree/master/iot-hub/Quickstarts/simulated-device

その中には、以下のサンプルが置かれていました。

```javascript
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

'use strict';

// The device connection string to authenticate the device with your IoT hub.
//
// NOTE:
// For simplicity, this sample sets the connection string in code.
// In a production environment, the recommended approach is to use
// an environment variable to make it available to your application
// or use an HSM or an x509 certificate.
// https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-security
//
// Using the Azure CLI:
// az iot hub device-identity show-connection-string --hub-name {YourIoTHubName} --device-id MyNodeDevice --output table
var connectionString = '{Your device connection string here}';

// Using the Node.js Device SDK for IoT Hub:
//   https://github.com/Azure/azure-iot-sdk-node
// The sample connects to a device-specific MQTT endpoint on your IoT Hub.
var Mqtt = require('azure-iot-device-mqtt').Mqtt;
var DeviceClient = require('azure-iot-device').Client
var Message = require('azure-iot-device').Message;

var client = DeviceClient.fromConnectionString(connectionString, Mqtt);

// Create a message and send it to the IoT hub every second
setInterval(function(){
  // Simulate telemetry.
  var temperature = 20 + (Math.random() * 15);
  var message = new Message(JSON.stringify({
    temperature: temperature,
    humidity: 60 + (Math.random() * 20)
  }));

  // Add a custom application property to the message.
  // An IoT hub can filter on these properties without access to the message body.
  message.properties.add('temperatureAlert', (temperature > 30) ? 'true' : 'false');

  console.log('Sending message: ' + message.getData());

  // Send the message.
  client.sendEvent(message, function (err) {
    if (err) {
      console.error('send error: ' + err.toString());
    } else {
      console.log('message sent');
    }
  });
}, 1000);
```

## Node.js のサンプルを試す
上で見てきたサンプルの一部を使って、実際に試していきます。

以下の部分に出てくる `azure-iot-device-mqtt` と `azure-iot-device` が必要そうなので、これを準備します。

```javascript
var Mqtt = require('azure-iot-device-mqtt').Mqtt;
var DeviceClient = require('azure-iot-device').Client
var Message = require('azure-iot-device').Message;
```

`npm i azure-iot-device-mqtt azure-iot-device` を実行します。
そして、クイックスタートにあったプログラムの `'{Your device connection string here}'` の部分は Azureポータルで取得した、デバイスの接続文字列を記載します。

プログラムはサンプルほぼそのままです（コメントを削除したり var で宣言されている部分を少し変えたりした程度）。

```javascript
"use strict";

const connectionString = '{Your device connection string here}';

const Mqtt = require("azure-iot-device-mqtt").Mqtt;
const DeviceClient = require("azure-iot-device").Client;
const Message = require("azure-iot-device").Message;

const client = DeviceClient.fromConnectionString(connectionString, Mqtt);

setInterval(function () {
  const temperature = 20 + Math.random() * 15;
  const message = new Message(
    JSON.stringify({
      temperature: temperature,
      humidity: 60 + Math.random() * 20,
    })
  );

  message.properties.add(
    "temperatureAlert",
    temperature > 30 ? "true" : "false"
  );

  console.log("Sending message: " + message.getData());

  client.sendEvent(message, function (err) {
    if (err) {
      console.error("send error: " + err.toString());
    } else {
      console.log("message sent");
    }
  });
}, 1000);

```

以下は実行結果です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Node.js のプログラムで Azure IoT Hub にデータを送る。<br><br>以下の公式サンプルを使っています。<br><br>●azure-iot-samples-node/iot-hub/Quickstarts/simulated-device at master · Azure-Samples/azure-iot-samples-node<br>　<a href="https://t.co/QxpcJYqjZ2">https://t.co/QxpcJYqjZ2</a> <a href="https://t.co/N5UHCcz2PI">pic.twitter.com/N5UHCcz2PI</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1454801202147848203?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そして、Azureポータルの画面を見にいくと、何らかデータを受信できていそうな表示が確認できました。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">Azureポータルを見たら、データの受信はできているっぽい。 <a href="https://t.co/9UqR4KqcF9">pic.twitter.com/9UqR4KqcF9</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1454802603083120641?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 他のデバイスシミュレータ
上記は、Node.js のプログラムがデバイスの代替となっていましたが、他に「[Raspberry Pi Azure IoT Online Simulator](https://azure-samples.github.io/raspberry-pi-web-simulator/)」というものもあるようです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Raspberry Pi Azure IoT Online Simulator というのがあるのか！<a href="https://t.co/hEUN0oABKZ">https://t.co/hEUN0oABKZ</a> <a href="https://t.co/PYNUnlBawL">pic.twitter.com/PYNUnlBawL</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1454805647606702087?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## データの可視化の下準備
### まずは情報のチェック
#### Azure App Service を使うパターン
Azure IoT Hub にデータを送ることができたようなので、あとは可視化してみます。

公式ドキュメントを見ていくと、ちょうど以下の内容のものがありました。

●Web アプリでの IoT Hub データのリアルタイム データの視覚化 | Microsoft Docs
　https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-live-data-visualization-in-web-apps

関連するソースコードは、以下になるようです。

●Azure-Samples/web-apps-node-iot-hub-data-visualization: web application for visualization data from IoT Hub
　https://github.com/Azure-Samples/web-apps-node-iot-hub-data-visualization

上記の方法を使った話の記事として、以下があったりしました。

●Azure IoT Hubに送信したデータを可視化する（App Service編） - Qiita
　https://qiita.com/Yokogawa_Mita/items/e060d8413b65d8ebd166

#### Power BI を使うパターン
可視化の方法として、他に以下のようなやり方もありました。

●Azure IoT Hub から取得したデータのリアルタイム データの視覚化 – Power BI | Microsoft Docs
　https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-live-data-visualization-in-power-bi

上記の方法を使った話の記事として、以下があったりしました。

●Azure IoT Hubに送信したデータを可視化する（Power BI編） - Qiita
　https://qiita.com/Yokogawa_Mita/items/13c0fcf92c4802473d02

### Azure Stream Analytics と連携させる
[上記の公式ドキュメントのほう](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-live-data-visualization-in-power-bi)を見ながら準備を進めていきます。

ドキュメント中の以下を試しました。

- Azure IoT Hub関連
   - IoT Hub へのコンシューマー グループの追加
- Azure Stream Analytics関連
   - Stream Analytics のジョブの作成
   - Stream Analytics ジョブへの入力の追加

この後、 [Stream Analytics ジョブへの出力の追加](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-live-data-visualization-in-power-bi#add-an-output-to-the-stream-analytics-job)などをやっていく必要があるのですが、内容が長くなったので、いったんここまでで区切ろうと思います。

ちなみに、出力先として Power BI以外にも、以下のものが選べるようです。
![出力の種類](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/aa648c0e-9bf4-7aaa-572d-093b1647fe7b.jpeg)
関連する公式ドキュメントは以下になるようです。

●Azure Stream Analytics からの出力 | Microsoft Docs
　https://docs.microsoft.com/ja-jp/azure/stream-analytics/stream-analytics-define-outputs

## おわりに
Node.js のプログラムを使った Azure IoT Hub へのデータ送信と、Azure Stream Analytics との連携を試していきました。
Azure Stream Analytics は可視化のための下準備で、Power BI との連携を試そうと思っていたりしますが、Azure Stream Analytics とつなげられる他の出力先で何か進めやすそうなものがあれば、それを試せればと思います。