27
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

M5Stackとクラウドを直接連携してみる(Azure IoT hub入門)

Last updated at Posted at 2020-05-24

 エッジデバイスをクラウドへつなぐ方法はいろいろとあると思います。今回はクラウドサービスを直結する方法を試しました。

 クラウドサービスにはMicroSoftのAzureの「Azure IoT Hub」を使用しました。こちらとM5Stack(ESP32デバイスなら何でもOK?)を連携する記事を見つけたので、こちらを参考に進めていきます。

やることは次の3つです。

  1. 開発環境構築
  2. Azure IoT Hubの準備
  3. M5Stackからデータを送る

#用意するもの

  • M5Stack(ESP32デバイス)
  • Windows10 or MAC OS 10(今回はWindows)
  • Azureのアカウント(サブスクリプション)
  • Arduino IDE
  • Visual Studio Code

#1.開発環境構築
 ESP32の開発環境をVisual Studio Code(VS Code)上に作っていきます。本家の解説にはArduino IDEとVisual Studio Codeのインストールが書かれています。私の場合は用意が済んでいたので省きました。

##1-1.VS CODEの拡張機能「Azure IoT Workbench」をインストール
 本家の解説でAzure IoT Hubが推奨されていたので拡張機能から検索してインストールします。
 image.png

##1-2.VS CodeにArduino IDEの設定をする
 VS Codeの、File > Preference > Settingsを開きます。Azure Functions ConfigurationのArduino設定を開きます。(本家の説明では分かりづらかった...。)
image.png

 setting.jsonを開いて、次のようにします。Arduinoは実態があるパスに読み替えてください。
・Windowsの場合

{
    "arduino.path": "C:\\Program Files (x86)\\Arduino",
    "arduino.additionalUrls": "https://dl.espressif.com/dl/package_esp32_index.json",
}

・MACの場合

{
  "arduino.path": "/Application",
  "arduino.additionalUrls": "https://dl.espressif.com/dl/package_esp32_index.json"
}

・Ubuntuの場合

{
  "arduino.path": "/home/{username}/Downloads/arduino-1.8.5",
  "arduino.additionalUrls": "https://dl.espressif.com/dl/package_esp32_index.json"
}

ここで、”arduino.path”がハイライトされておらず、認識されていない状況が発生しました。どうやら「Visual Studio Code extension for Arduino」が必要そうなので、VS Codeの拡張機能一覧から追加します。

注意!
似たようなのがいますが、間違えずに!
image.png
image.png

##1-3.Arduino IDEのボードマネージャにESP32を設定
 キーボードの「F1」を押してコマンドパレットを開き、次のコマンドを入力してEnterします。

Arduino: Board Manager

 次のような画面が表示されるので、ESP32と入力し、最新バージョンのボードファイルをインストールします。
image.png

 インストールに成功すると次のようにメッセージが表示されます。
image.png

#2.Azure IoT Hubの準備
 それではAzure側の準備を進めていきます。次の2点が前提です。

  • Azureのアカウント(サブスクリプション)を持っている
  • Azure IoT Hubのリソースは作成していない

##2-1. Azure IoT Hubと連携するサンプルコードを開く
 キーボードのF1キーを押し、コマンドパレットを表示します。次のように入力し、「Open Examples...」を選択します。
image.png

 次の図のようにESP32のサンプルコードを選択します。
image.png

 ESP32のサンプルコード一覧が次のように表示されるので、「ESP32 Get Started」の「Open Sample」を選択します。
image.png

##2-2. Azure IoT Hubの設定
 Azure IoT Hubの設定をVS Codeから進めます。コマンドパレットを開き、次のようにプロビジョンコマンドを実行します。
image.png

 ブラウザが自動で立ち上がるので、Azureアカウントの認証を行います。
image.png

 Azure PortalからすでにAzure IoT Hubのリソースを作成している場合、ここでの操作が異なるようです。
今回は、Azure IoT Hubのリソースを作成していない状態で進めます。

 前の手順からの続きで、サブスクリプションを選択します。
image.png

 次にリソースグループ名を決めます。
image.png

 今回は次のように分かりやすい名前にしました。決めたらEnterを押して次に進みます。
image.png

 次にリソースグループのロケーションを決めます。特に気にせずJpanならいいかと思い、今回は次のように選択しました。
image.png

 次のようになるので、選択してEnterを押します。
image.png

 IoT Hubの設定を新規に作成します。
image.png

IoT Hubのロケーションを選択します。
image.png

 IoT Hubのスケール(料金体系)を選択します。今回は無料枠を選択しています。
image.png

 次にIoT Hubの名前を付けます。今回は次のようにしました。
image.png

 ターミナルのOUTPUTコンソールを見ると。Azure IoT Hubのリソースを作成している状態を確認できます。
リソースの作成まで時間が少々かかるようです。
image.png

 次のように表示されるので、選択してEnterを押します。
image.png

 プロビジョン(準備)を行うデバイスを新規作成します。
image.png
 
 分かりやすい名前を入力し、Enterを押します。
次のように、TerminalのOUTPUTにkey情報が表示されれば完了です。
image.png

#3.M5Stackの準備
サンプルコードの足りない個所を埋めていきます。

##3-1. Wi-Fi設定を追記する
 サンプルコードの11行目辺りに次のような記述があるので、M5Stackが接続するWi-Fiのアクセスポイント情報を入力します。
image.png

##3-2.認証キーを追記する
 コマンドパレットを開き、次のようにDevice Settingsを開きます。
image.png

 次のようなが麺が表示されるので、Copy~を選択します。
image.png

 ここで、次のようなエラーが発生しました。

System Error:  Failed to get Azure configuration iotHubDeviceConnectionString.}

または次のエラー。

Command failed: c:\Users\ユーザ名\.vscode\extensions\vsciot-vscode.vscode-iot-workbench-0.14.0\fallbacks\windows\clipboard_x86_64.exe --copy

 回避策として、コマンドパレットから次のように「Get Device info」を実行。
image.png

 ターミナルの最下行に表示される「connectionString」の値をコピーします。そして、ソースコードの「connectionString」に追記します。

image.png

3-3. M5Stackへの書き込み
 M5Stackを接続し、動作確認していきます。

 コマンドパレットを開き、Upload Device Codeを選択します。
image.png

 これでエラーが発生しましたので、トラブルシューティングとして残します。

 まずはコマンドパレットを開き、Arduino Borad Configを選択します。
 次のようにボードをを選択できているか確認します。

image.png

 次のようにProgrammerが選択されていない場合、
image.png

 Arduino Board configからprogrammerをUSBaspに設定します。
image.png

 書き込みに成功すると、次のメッセージが表示されます。
image.png

##3-4.動作確認

 シリアルモニタを開きます。コマンドパレットから次のようにコマンドを実行するか、
image.png

 次のように画面下部のコネクトボタンを押すとシリアルモニタを開くことができます。
image.png
 
 うまくプログラムが動いていると、1秒おきくらいにAzure ioT Hubへデータを送信している様子が見られます。
image.png

 次に、Azureからデータを送信して確認します。Azure Porttalを開き、Azure ioT Hubのリーソースを開いてIoTデバイスを選択します。
image.png

 「デバイスへのメッセージ」を選択します。
image.png

 メッセージの本文を書いて送信します。
image.png

 VS Codeのターミナルを見ると次のように送信したデータが表示されていれば成功です!
image.png

#おわりに
 ここまで読んでくださいましてありがとうございます。お疲れさまでした。

 ネットに情報が少なく、ここまで動かすのはとても苦労しました(~_~;)

 M5Stackをクラウドで監視できる等になると、センサー端末をばらまいて広域のセンシングが可能となりそうですね。

#参考
Micro Soft Learn Azure IoT Hub
Azure ESP32 IoT DevKit Get Started
IoT Hub で device-to-cloud および cloud-to-device メッセージを送信する
Run a simple C sample on M5Stack IoT Kit device running RTOS

#ソースコード

demo.ino
/**
 * A simple Azure IoT example for sending telemetry to Iot Hub.
 */

#include <WiFi.h>
#include "Esp32MQTTClient.h"

#define INTERVAL 10000
#define MESSAGE_MAX_LEN 256
// Please input the SSID and password of WiFi
const char *ssid = "";            // Wi-FiのSSID
const char *password = "";              // Wi-Fiのパスワード

/*String containing Hostname, Device Id & Device Key in the format:                         */
/*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"                */
/*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessSignature=<device_sas_token>"    */
static const char* connectionString = "";
const char *messageData = "{\"messageId\":%d, \"Temperature\":%f, \"Humidity\":%f}";
static bool hasIoTHub = false;
static bool hasWifi = false;
int messageCount = 1;
static bool messageSending = true;
static uint64_t send_interval_ms;

static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result)
{
  if (result == IOTHUB_CLIENT_CONFIRMATION_OK)
  {
    Serial.println("Send Confirmation Callback finished.");
  }
}

static void MessageCallback(const char* payLoad, int size)
{
  Serial.println("Message callback:");
  Serial.println(payLoad);
}

static void DeviceTwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char *payLoad, int size)
{
  char *temp = (char *)malloc(size + 1);
  if (temp == NULL)
  {
    return;
  }
  memcpy(temp, payLoad, size);
  temp[size] = '\0';
  // Display Twin message.
  Serial.println(temp);
  free(temp);
}

static int  DeviceMethodCallback(const char *methodName, const unsigned char *payload, int size, unsigned char **response, int *response_size)
{
  LogInfo("Try to invoke method %s", methodName);
  const char *responseMessage = "\"Successfully invoke device method\"";
  int result = 200;

  if (strcmp(methodName, "start") == 0)
  {
    LogInfo("Start sending temperature and humidity data");
    messageSending = true;
  }
  else if (strcmp(methodName, "stop") == 0)
  {
    LogInfo("Stop sending temperature and humidity data");
    messageSending = false;
  }
  else
  {
    LogInfo("No method %s found", methodName);
    responseMessage = "\"No method found\"";
    result = 404;
  }

  *response_size = strlen(responseMessage) + 1;
  *response = (unsigned char *)strdup(responseMessage);

  return result;
}



void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 Device");
  Serial.println("Initializing...");
  Serial.println(" > WiFi");
  Serial.println("Starting connecting WiFi.");

  delay(10);
  WiFi.mode(WIFI_AP);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    hasWifi = false;
  }
  hasWifi = true;
  
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println(" > IoT Hub");
  if (!Esp32MQTTClient_Init((const uint8_t*)connectionString, true))
  {
    hasIoTHub = false;
    Serial.println("Initializing IoT hub failed.");
    return;
  }
  hasIoTHub = true;
  Esp32MQTTClient_SetSendConfirmationCallback(SendConfirmationCallback);
  Esp32MQTTClient_SetMessageCallback(MessageCallback);
  Esp32MQTTClient_SetDeviceTwinCallback(DeviceTwinCallback);
  Esp32MQTTClient_SetDeviceMethodCallback(DeviceMethodCallback);
  Serial.println("Start sending events.");
  randomSeed(analogRead(0));
  send_interval_ms = millis();

}

void loop() {
if (hasWifi && hasIoTHub)
  {
    if (messageSending && 
        (int)(millis() - send_interval_ms) >= INTERVAL)
    {
      // Send teperature data
      char messagePayload[MESSAGE_MAX_LEN];
      float temperature = (float)random(0,500)/10;
      float humidity = (float)random(0, 1000)/10;
      snprintf(messagePayload, MESSAGE_MAX_LEN, messageData, messageCount++, temperature, humidity);
      Serial.println(messagePayload);
      EVENT_INSTANCE* message = Esp32MQTTClient_Event_Generate(messagePayload, MESSAGE);
      Esp32MQTTClient_SendEventInstance(message);
      send_interval_ms = millis();
    }
    else
    {
      Esp32MQTTClient_Check();
    }
  }
  delay(10);
}
27
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?