F端r die Microsoft Azure Beispiele werde ich in Zukunft den Espressif ESP32 (ca. 5,00 bei Amazon bei Abnahme von 5 St端ck) und das MXChip AZ3166 IOT Developer Kit Board (ca. 43,00 bei Amazon) verwenden. Der Grund ist, dass der Azure IoT Hub Support (/MQTT Prokotoll Implementierung) f端r den ESP32, aber vor allem f端r den MXChip, viel robuster und in der Anwendung und Programmierung viel einfacher ist (insbesondere Dokumentation und Beispiele sind gen端gend vorhanden). Zudem ist der ESP32, genauso wie der MXChip AZ3166, Azure Zertifiziert!

Ich habe es auch mit dem ESP8266 versucht und an sich l辰sst sich die Kommunikation mit dem IoT Hub nach langer Fehlersuche, Debuggen und Probieren zwar l旦sen, aber ein gutes Gef端hl hinterl辰sst es nicht.

Der ESP32 in ein SoC (System-on-a-Chip) f端r IoT-Projekte. Der Chip ist ca. 25% gr旦er als der ESP8266 und fast doppelt so teuer (wobei wir hier von Betr辰gen um die 5,00 reden). Es wurde 2016 durch die Firma Espressif vorgestellt und besitzt integrierte WLAN und Bluetooth Unterst端tzung, CPU mit ein oder zwei Kernen, 532 KB Arbeitsspeicher und 448 KB ROM (Bootloader), 8 MHz interner Oszillator, 34 GPIOs, 2x 8-bit-DAC, 3x UART, 2x I族C, 2x SPI, 2x I族S, … (siehe auch das Datasheet von Espressif).

Das MXChip AZ3166 hingegen wurde von MXCHIP gemeinsam mit der Microsoft Development Platform Division entwickelt und ist folglich ebenfalls Microsoft Azure Zertifiziert. Es bietet von Hause aus 2 Taster, ein Display, einen Temperatur- und Feuchtigkeitssensor sowie weitere Sensoren f端r Druck, Bewegung (Beschleunigungssensor und Gyroskop) und ein Magnetometer. Das Ganze ist eine Kombination aus ST Microelectronics STM32F412 mit dem MXChip EMW3166

F端r das MXChip AZ3166 IOT Developer Kit gibt es auch einen Simulator :) Einfach den Connection String zum IoT Hub angeben und schon kann man den Code ausf端hren und zwei Beispielprojekte testen.

Wir fokussieren uns in diesem Artikel auf den ESP32 und starten damit, die Entwicklungsumgebung aufzusetzen und anschlieend simulierte Daten an den IoT Hub zu senden.

Arduino IDE

Wir verwenden die Arduino IDE f端r das Kompilieren und Hochladen des Codes. Dazu laden wir die entsprechende Version von der Seite herunter und installieren es einfach.

Wir starten die Arduino IDE und f端gen unter Datei > Voreinstellungen im Reiter Einstellungen in Zus辰tzliche Boardverwalter-URLs die nachfolgende Url ein:

https://dl.espressif.com/dl/package_esp32_index.json

Anschlieend 旦ffnen wir den Boardverwalter unter Werkzeuge > Board: “…” > Boardverwalter. Geben im Suchfeld esp32 ein und klicken bei esp32 by Espressif Systems Version 1.04 auf Install.

Nun w辰hlen wir als Board den Eintrag ESP32 Dev Module unter Werkzeuge > Board: “ESP32 Dev Module > ESP32 Arduino > ESP32 Dev Module.

Um das WLAN und die IoT Hub Konnektivit辰t zu 端berpr端fen erstellen wir eine neue Datei via Datei > Neu und kopieren nachfolgenden Code in die Datei.

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>

/**
 * 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     = "XXXXXXXX";
const char* password = "XXXXXXXXXX";

/*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 = "HostName=XXXXXXXX.azure-devices.net;DeviceId=XXXXXX;SharedAccessKey=XXXXXXXX";
const char *messageData = "{\"messageId\":%d, \"Temperature\":%f, \"Humidity\":%f, \"target\":\"storage\"}";
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_Event_AddProp(message, "target", "storage");
      Esp32MQTTClient_SendEventInstance(message);
      send_interval_ms = millis();
    }
    else
    {
      Esp32MQTTClient_Check();
    }
  }
  delay(10);
}

Wichtig dabei sind folgende Zeilen im Code:

// Please input the SSID and password of WiFi
const char* ssid     = "XXXXXXXX";
const char* password = "XXXXXXXXXX";

Bei ssid und password geben wir die WLAN SSID an mit dem sich der ESP32 verbinden soll und das dazugeh旦rige Passwort. Der n辰chste wichtige Eintrag ist der connectionString.

static const char* connectionString = "HostName=XXXXXXXX.azure-devices.net;DeviceId=XXXXXX;SharedAccessKey=XXXXXXXX";

Das ist der Connection String von unserem IoT-Ger辰t im Azure IoT Hub was wir zuvor erstellt haben. Diesen finden wir im Azure Portal. Dort 旦ffnen wir unseren IoT Hub mit dem Namen iotghub und w辰hlen in der linken Men端leiste den Eintrag Explorer > IoT-Ger辰te.

Wir klicken auf das IoT-Ger辰t ESP3201 und kopieren die Prim辰re Verbindungszeichenfolge in die Zwischenablage und f端gen diese in die Konstante ein.

Danach w辰hlen wir im Men端 Sketch > berpr端fen/Kompilieren und nach erfolgreichem Kompilieren Sketch > Hochladen. Um zu sehen was passiert, 旦ffnen wir den Seriellen Monitor unter Werkzeuge > Serieller Monitor.

Jetzt sollten Nachrichten an den IoT Hub gesendet werden. Um wiederum zu pr端fen ob die Nachrichten im Event Hub kompatiblen Endpunkt des IoT Hubs ankommen, 旦ffnen wir unseren C# Client den wir im Artikel Ein IoT Ger辰t in C# simulieren und den IoT Hub testen entwickelt haben. Beide Fenster positionieren wir nebeneinander und k旦nnen sehr sch旦n sehen wie die Nachrichten vom IoT-Ger辰t verschickt und binnen einer Sekunde im IoT Hub ankommen.

Da die vom IoT-Ger辰t verschickten Nachrichten mit der Eigenschaft target = “storage” versehen werden, sollten sie auch von unserem im IoT Hub erstellten Route an das Data Lake weitergeroutet werden. Das k旦nnen wir pr端fen in dem wir im Azure Portal unser Azure Speicherkonto iotgstorage 旦ffnen und im linken Men端 auf Storage Explorer “Vorschau” klicken. Danach klicken wir auf Container > iotgdatalake und in meinem Fall 旦ffnen wir das Verzeichnis iotghub > 02 > 2021 > 02 > 15 > 13 (es muss das aktuelle Datum und die aktuelle Uhrzeit in Form einer Verzeichnisstruktur sein). Dort sollte sich eine JSON Datei befinden. Wenn wir diese Datei herunterladen und 旦ffnen, sollten wir alle Nachrichten sehen welche vom IoT-Ger辰t in den letzten Minuten verschickt wurden.

Ein anderes Mal richten wir uns Microsoft Visual Studio Code als Entwicklungsumgebung f端r die ESP32 und MXChip AZ3166 Projekte ein.