[Azure x IoT]Azure IoTHubにメッセージを送ろう

# Azure IoT Hubとは

AzureのIoT関連サービスの１つです。物理デバイスから受信したメッセージを他のAzureリソースに連携することができます。

リソース連携の例

- Azure FunctionとDBサービス  
受信したメッセージをDBへ保存
- Azure FunctionとSignalR(Azureのリアルタイム通知サービス)   
メッセージの受信をトリガーに、フロントエンドアプリケーションへリアルタイム通知


[IoT Hub | Microsoft Azure](https://azure.microsoft.com/ja-jp/services/iot-hub/)

今回はそんな便利なAzure IoTHubにHTTPS,MQTTの２つのプロトコルでメッセージを送信する方法を紹介します。

**本記事のゴール**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/1d5571b3-cb3a-977b-0c04-7a32c73a3806.png)



# 事前準備

## Azure CLIをインストールする

以下を参考にAzure cliをインストールしてください

[https://docs.microsoft.com/en-us/cli/azure/install-azure-cli](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)

Macの場合は以下です

```bash
brew update && brew install azure-cli
```

## 以下の値をPortalまたコマンドで取得しておく

- iothubの名前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/d842923d-1ffa-b82e-e6cf-54656da6514b.png)
    
- デバイス名
IoTHubに登録したデバイス名です。もしまだ登録してなければ登録しましょう。今回は物理デバイスは不要ですが、本来はIoTHubにメッセージを送るIoTデバイスを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/583aafbd-4c16-7553-ebad-a51e044dd968.png)

    
- Event Hub-compatible endpoint
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/83b78851-2fb4-3445-ec40-4da4ca4ba681.png)

    
- SAS(Shared Access Signiture)
az iot コマンドを使って取得します。
先にinstallしたazコマンドに対し拡張機能を追加インストールする必要があり、以下のコマンドで行います([参考](https://github.com/Azure/azure-iot-cli-extension))
    
    ```bash
    az extension add --name azure-iot
    ```
    
    トークン発行コマンド([コマンドリファレンス](https://docs.microsoft.com/en-us/cli/azure/iot?view=azure-cli-latest))
    
    ```bash
    az iot hub generate-sas-token -n $IOTHUB_NAME
    ```
    
    寿命を指定したい場合
    
    —duオプションをつけて、秒[s]単位で指定可能
    
    ```bash
    # 60秒で寿命が切れるトークンを作成するとき
    az iot hub generate-sas-token -n $IOTHUB_NAME --du 60
    ```
    

## 受信環境を用意する

AzureIoTHubで受信したメッセージの中身が意図したものになってるかを確認する環境を作成します。
一番簡単なのはAzureCLIの`az iot hub monitor-events`を利用することですが、こちらはM1Mac上ではうまく動かないのでNode.jsの受信環境を構築します.

(自分は大抵IoTHub連携するFunctionもサクッとデプロイしてしまってそこで中身を確認することもあります)

1. 公式のサンプルをcloneまたはコピペする
    
    利用するのは[https://github.com/Azure-Samples/azure-iot-samples-node](https://github.com/Azure-Samples/azure-iot-samples-node)のうち,[`azure-iot-samples-node/iot-hub/Quickstarts/read-d2c-messages`](https://github.com/Azure-Samples/azure-iot-samples-node/tree/234607/iot-hub/Quickstarts/read-d2c-messages)です。
    
2. 利用するサンプルに接続情報を渡す
    1. SampleCodeの38行目`connectionString`に準備で用意した`Event Hub-compatible endpoint`をコピペします。
    サンプルコードは複数の情報をテンプレートリテラルに埋め込んでますが、結局上記の`Event Hub-compatible endpoint`を作っているだけなので右辺を全部削除して代入してしまってOKです。
    下記の形式を見ても、Portalから取得できる値と一致していることがわかるかと思います。
        
        サンプルの実装
        
        ```jsx
        const connectionString = `Endpoint=${eventHubsCompatibleEndpoint};EntityPath=${eventHubsCompatiblePath};SharedAccessKeyName=service;SharedAccessKey=${iotHubSasKey}`;
        ```
        
        おすすめ
        
        ```jsx
        const connectionString = ここに丸ごと代入
        ```
        
    2. プログラムを実行
        
        ```bash
        node ReadDeviceToCloudMessages.js
        ```
        

あとはメッセージを送れば以下のような形でメッセージを確認できます

```bash
xxxx@xxx read-d2c-messages % node ReadDeviceToCloudMessages.js
IoT Hub Quickstarts - Read device to cloud messages.
Telemetry received: 
{"value":"okay"}
Properties (set by device): 
undefined
System properties (set by IoT Hub): 
{"iothub-connection-device-id":"device0","iothub-connection-auth-method":"{\"scope\":\"hub\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}","iothub-connection-auth-generation-id":"637769437000012500","iothub-enqueuedtime":1645585954048,"iothub-message-source":"Telemetry","contentType":"application/json","contentEncoding":""}
```

# メッセージを送る

さて準備もできたので実際にメッセージを送っていきます


## HTTPSで送る

以下の形式で送ればOK

```bash
IOTHUB_NAME=xxxxx
DEVICE_NAME=xxxxx
SAS=xxxx
curl -i -X POST \
-H "Content-Type:application/json" \
-H "Authorization:$SAS" \
-d '{"value":"hello,world with https"}' \
'https://$IOTHUBNAME.azure-devices.net/devices/$DEVICE_NAME/messages/events?api-version=2018-06-30'
```
以下の記事を参考にしました。
[Azure IoT HubにHTTP POSTでメッセージを送信するメモ - Qiita](https://qiita.com/mitsuoka0423/items/bfcc91d50cd0fe312f6c)

受信スクリプト側で以下のようなログが見れればOK

```bash
Telemetry received: 
{"value":"hello,world with https"}
Properties (set by device): 
undefined
System properties (set by IoT Hub): 
{"iothub-connection-device-id":"device0","iothub-connection-auth-method":"{\"scope\":\"hub\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}","iothub-connection-auth-generation-id":"637769437000012500","iothub-enqueuedtime":1645587259557,"iothub-message-source":"Telemetry","contentType":"application/json","contentEncoding":""}
```

# MQTTで送る

## MQTTとは？

http,httpsのような通信プロトコルの一種です。なぜこれがIoT界隈で使われているのかというと以下のような理由があるみたいです.

> ****「MQTT」は、シンプル、軽量、省電力****
> 

> また「MQTT」のトラフィックは、HTTPに比べると10分の1になります。すなわち通信量やCPU負荷、電力消費量などを、従来の10分の1に抑えることができるのです。
> 

[MQTTとは | かもめエンジニアリング](https://kfep.jp/solution/iot-mqtt/mqtt)

確かに、途方もない数の物理デバイスからデータを収集するのであれば軽量で省電力なのはメリットが大きそうですね。

## 送り方

今回はmosquittoというMQTTクライアントを利用する

1. mosquittoのインストール
    
    [Download](https://mosquitto.org/download/)
    
2. メッセージの送信
MQTTメッセージからIoTHubにメッセージを送るときにcontent-typeとencodingを設定する場合はトピックの末尾に以下をつける必要があるので注意です([参考](https://stackoverflow.com/questions/57297853/how-do-you-set-azure-iot-hub-system-properties-using-native-mqtt))
    
    ```bash
    $.ct=application%2Fjson&$.ce=utf-8
    ```
    
    ```bash
    IOTHUB_NAME=xxxx
    DEVICE_NAME=xxxx
    SAS=xxxx
    mosquitto_pub -d -q 1 \
      -V mqttv311 \
      -p 8883 \
      -h "$IOTHUB_NAME.azure-devices.net" \
      -i $DEVICE_NAME \
      -u "$IOTHUB_NAME.azure-devices.net/$DEVICE_NAME/api-version=2016-11-14" \
      -P $SAS \
      -t "devices/$DEVICE_NAME/messages/events/$.ct=application%2Fjson&$.ce=utf-8" \
      -m '{"value":"Hello,world with MQTT"}'
    ```
    

受信スクリプト側で以下のようなログが見れればOK

```bash
Telemetry received: 
{"value":"Hello,world with MQTT"}
Properties (set by device): 
undefined
System properties (set by IoT Hub): 
{"iothub-connection-device-id":"device0","iothub-connection-auth-method":"{\"scope\":\"hub\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}","iothub-connection-auth-generation-id":"637769437000012500","iothub-enqueuedtime":1645588086679,"iothub-message-source":"Telemetry","contentType":"application/json","contentEncoding":"utf-8"}
```

# 終わりに

いかがでしたでしょうか。これでデバイス→IoTHubへメッセージを送ることはできるようになったのではないでしょうか。

この次はIoTHubに届いたメッセージを加工、保存等したくなりますよね。そんな方向けにAzureIoTHubとAzureFunction,DBを連携する方法を紹介する記事も執筆予定です。お楽しみに!