14 KiB
Verbinden Sie Ihr IoT-Gerät mit der Cloud - Wio Terminal
In diesem Teil der Lektion verbinden Sie Ihr Wio Terminal mit Ihrem IoT Hub, um Telemetrie zu senden und Befehle zu empfangen.
Verbinden Sie Ihr Gerät mit dem IoT Hub
Der nächste Schritt besteht darin, Ihr Gerät mit dem IoT Hub zu verbinden.
Aufgabe - Verbindung mit dem IoT Hub herstellen
-
Öffnen Sie das Projekt
soil-moisture-sensorin VS Code. -
Öffnen Sie die Datei
platformio.ini. Entfernen Sie die Bibliotheksabhängigkeitknolleary/PubSubClient. Diese wurde verwendet, um eine Verbindung zu einem öffentlichen MQTT-Broker herzustellen, ist jedoch nicht erforderlich, um eine Verbindung zum IoT Hub herzustellen. -
Fügen Sie die folgenden Bibliotheksabhängigkeiten hinzu:
seeed-studio/Seeed Arduino RTC @ 2.0.0 arduino-libraries/AzureIoTHub @ 1.6.0 azure/AzureIoTUtility @ 1.6.1 azure/AzureIoTProtocol_MQTT @ 1.6.0 azure/AzureIoTProtocol_HTTP @ 1.6.0 azure/AzureIoTSocket_WiFi @ 1.0.2Die Bibliothek
Seeed Arduino RTCstellt Code bereit, um mit einer Echtzeituhr im Wio Terminal zu interagieren, die zur Zeitverfolgung verwendet wird. Die übrigen Bibliotheken ermöglichen Ihrem IoT-Gerät die Verbindung mit dem IoT Hub. -
Fügen Sie Folgendes am Ende der Datei
platformio.inihinzu:build_flags = -DDONT_USE_UPLOADTOBLOBDies setzt ein Compiler-Flag, das beim Kompilieren des Arduino IoT Hub-Codes benötigt wird.
-
Öffnen Sie die Header-Datei
config.h. Entfernen Sie alle MQTT-Einstellungen und fügen Sie die folgende Konstante für den Geräte-Verbindungsstring hinzu:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";Ersetzen Sie
<connection string>durch den Verbindungsstring für Ihr Gerät, den Sie zuvor kopiert haben. -
Die Verbindung zum IoT Hub verwendet ein zeitbasiertes Token. Das bedeutet, dass das IoT-Gerät die aktuelle Zeit kennen muss. Im Gegensatz zu Betriebssystemen wie Windows, macOS oder Linux synchronisieren Mikrocontroller die aktuelle Zeit nicht automatisch über das Internet. Daher müssen Sie Code hinzufügen, um die aktuelle Zeit von einem NTP-Server abzurufen. Sobald die Zeit abgerufen wurde, kann sie in einer Echtzeituhr im Wio Terminal gespeichert werden, sodass die korrekte Zeit zu einem späteren Zeitpunkt angefordert werden kann, vorausgesetzt, das Gerät verliert nicht die Stromversorgung. Fügen Sie eine neue Datei namens
ntp.hmit folgendem Code hinzu:#pragma once #include "DateTime.h" #include <time.h> #include "samd/NTPClientAz.h" #include <sys/time.h> static void initTime() { WiFiUDP _udp; time_t epochTime = (time_t)-1; NTPClientAz ntpClient; ntpClient.begin(); while (true) { epochTime = ntpClient.getEpochTime("0.pool.ntp.org"); if (epochTime == (time_t)-1) { Serial.println("Fetching NTP epoch time failed! Waiting 2 seconds to retry."); delay(2000); } else { Serial.print("Fetched NTP epoch time is: "); char buff[32]; sprintf(buff, "%.f", difftime(epochTime, (time_t)0)); Serial.println(buff); break; } } ntpClient.end(); struct timeval tv; tv.tv_sec = epochTime; tv.tv_usec = 0; settimeofday(&tv, NULL); }Die Details dieses Codes liegen außerhalb des Umfangs dieser Lektion. Er definiert eine Funktion namens
initTime, die die aktuelle Zeit von einem NTP-Server abruft und verwendet, um die Uhr im Wio Terminal einzustellen. -
Öffnen Sie die Datei
main.cppund entfernen Sie den gesamten MQTT-Code, einschließlich der Header-DateiPubSubClient.h, der Deklaration derPubSubClient-Variable, der MethodenreconnectMQTTClientundcreateMQTTClientsowie aller Aufrufe dieser Variablen und Methoden. Diese Datei sollte nur Code enthalten, um eine Verbindung zu WiFi herzustellen, die Bodenfeuchtigkeit abzurufen und ein JSON-Dokument damit zu erstellen. -
Fügen Sie die folgenden
#include-Direktiven oben in der Dateimain.cpphinzu, um Header-Dateien für die IoT Hub-Bibliotheken und zum Einstellen der Zeit einzubinden:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h" -
Fügen Sie am Ende der Funktion
setupden folgenden Aufruf hinzu, um die aktuelle Zeit einzustellen:initTime(); -
Fügen Sie die folgende Variablendeklaration oben in der Datei hinzu, direkt unter den Include-Direktiven:
IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;Dies deklariert ein
IOTHUB_DEVICE_CLIENT_LL_HANDLE, einen Handle für eine Verbindung zum IoT Hub. -
Fügen Sie darunter den folgenden Code hinzu:
static void connectionStatusCallback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void *user_context) { if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED) { Serial.println("The device client is connected to iothub"); } else { Serial.println("The device client has been disconnected"); } }Dies deklariert eine Callback-Funktion, die aufgerufen wird, wenn sich der Verbindungsstatus zum IoT Hub ändert, z. B. beim Verbinden oder Trennen. Der Status wird an den seriellen Port gesendet.
-
Fügen Sie darunter eine Funktion hinzu, um eine Verbindung zum IoT Hub herzustellen:
void connectIoTHub() { IoTHub_Init(); _device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(CONNECTION_STRING, MQTT_Protocol); if (_device_ll_handle == NULL) { Serial.println("Failure creating Iothub device. Hint: Check your connection string."); return; } IoTHubDeviceClient_LL_SetConnectionStatusCallback(_device_ll_handle, connectionStatusCallback, NULL); }Dieser Code initialisiert den IoT Hub-Bibliothekscode und erstellt dann eine Verbindung mithilfe des Verbindungsstrings in der Header-Datei
config.h. Diese Verbindung basiert auf MQTT. Wenn die Verbindung fehlschlägt, wird dies an den seriellen Port gesendet - wenn Sie dies in der Ausgabe sehen, überprüfen Sie den Verbindungsstring. Schließlich wird der Callback für den Verbindungsstatus eingerichtet. -
Rufen Sie diese Funktion in der Funktion
setupunterhalb des Aufrufs voninitTimeauf:connectIoTHub(); -
Genau wie beim MQTT-Client läuft dieser Code in einem einzelnen Thread und benötigt Zeit, um Nachrichten zu verarbeiten, die vom Hub gesendet und an den Hub gesendet werden. Fügen Sie Folgendes oben in der Funktion
loophinzu, um dies zu tun:IoTHubDeviceClient_LL_DoWork(_device_ll_handle); -
Bauen und laden Sie diesen Code hoch. Sie sehen die Verbindung im seriellen Monitor:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothubIn der Ausgabe können Sie sehen, wie die NTP-Zeit abgerufen wird, gefolgt von der Verbindung des Geräte-Clients. Es kann einige Sekunden dauern, bis die Verbindung hergestellt ist, sodass Sie möglicherweise die Bodenfeuchtigkeit in der Ausgabe sehen, während das Gerät sich verbindet.
💁 Sie können die UNIX-Zeit des NTP in eine lesbarere Version umwandeln, indem Sie eine Website wie unixtimestamp.com verwenden.
Telemetrie senden
Jetzt, da Ihr Gerät verbunden ist, können Sie Telemetrie an den IoT Hub senden, anstatt an den MQTT-Broker.
Aufgabe - Telemetrie senden
-
Fügen Sie die folgende Funktion oberhalb der Funktion
setuphinzu:void sendTelemetry(const char *telemetry) { IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromString(telemetry); IoTHubDeviceClient_LL_SendEventAsync(_device_ll_handle, message_handle, NULL, NULL); IoTHubMessage_Destroy(message_handle); }Dieser Code erstellt eine IoT Hub-Nachricht aus einem als Parameter übergebenen String, sendet sie an den Hub und bereinigt anschließend das Nachrichtenobjekt.
-
Rufen Sie diesen Code in der Funktion
loopdirekt nach der Zeile auf, in der die Telemetrie an den seriellen Port gesendet wird:sendTelemetry(telemetry.c_str());
Befehle verarbeiten
Ihr Gerät muss einen Befehl vom Servercode verarbeiten, um das Relais zu steuern. Dies wird als direkte Methodenanforderung gesendet.
Aufgabe - eine direkte Methodenanforderung verarbeiten
-
Fügen Sie den folgenden Code vor der Funktion
connectIoTHubhinzu:int directMethodCallback(const char *method_name, const unsigned char *payload, size_t size, unsigned char **response, size_t *response_size, void *userContextCallback) { Serial.printf("Direct method received %s\r\n", method_name); if (strcmp(method_name, "relay_on") == 0) { digitalWrite(PIN_WIRE_SCL, HIGH); } else if (strcmp(method_name, "relay_off") == 0) { digitalWrite(PIN_WIRE_SCL, LOW); } }Dieser Code definiert eine Callback-Methode, die von der IoT Hub-Bibliothek aufgerufen werden kann, wenn sie eine direkte Methodenanforderung erhält. Die angeforderte Methode wird im Parameter
method_nameübergeben. Diese Funktion gibt die aufgerufene Methode an den seriellen Port aus und schaltet das Relais je nach Methodenname ein oder aus.💁 Dies könnte auch in einer einzigen direkten Methodenanforderung implementiert werden, indem der gewünschte Zustand des Relais in einer Nutzlast übergeben wird, die mit der Methodenanforderung übergeben und im Parameter
payloadverfügbar ist. -
Fügen Sie den folgenden Code am Ende der Funktion
directMethodCallbackhinzu:char resultBuff[16]; sprintf(resultBuff, "{\"Result\":\"\"}"); *response_size = strlen(resultBuff); *response = (unsigned char *)malloc(*response_size); memcpy(*response, resultBuff, *response_size); return IOTHUB_CLIENT_OK;Direkte Methodenanforderungen benötigen eine Antwort, und die Antwort besteht aus zwei Teilen - einer Antwort als Text und einem Rückgabecode. Dieser Code erstellt ein Ergebnis als folgendes JSON-Dokument:
{ "Result": "" }Dieses wird dann in den Parameter
responsekopiert, und die Größe dieser Antwort wird im Parameterresponse_sizefestgelegt. Dieser Code gibt dannIOTHUB_CLIENT_OKzurück, um zu zeigen, dass die Methode korrekt verarbeitet wurde. -
Verkabeln Sie den Callback, indem Sie Folgendes am Ende der Funktion
connectIoTHubhinzufügen:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL); -
Die Funktion
loopruft die FunktionIoTHubDeviceClient_LL_DoWorkauf, um Ereignisse zu verarbeiten, die vom IoT Hub gesendet werden. Dies wird aufgrund desdelaynur alle 10 Sekunden aufgerufen, was bedeutet, dass direkte Methoden nur alle 10 Sekunden verarbeitet werden. Um dies effizienter zu gestalten, kann die Verzögerung von 10 Sekunden in viele kürzere Verzögerungen implementiert werden, wobeiIoTHubDeviceClient_LL_DoWorkjedes Mal aufgerufen wird. Fügen Sie dazu den folgenden Code oberhalb der Funktionloophinzu:void work_delay(int delay_time) { int current = 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current += 100; } while (current < delay_time); }Dieser Code wird wiederholt durchlaufen, ruft
IoTHubDeviceClient_LL_DoWorkauf und verzögert jedes Mal um 100 ms. Dies wird so oft wie nötig durchgeführt, um die im Parameterdelay_timeangegebene Verzögerungszeit zu erreichen. Das bedeutet, dass das Gerät höchstens 100 ms wartet, um direkte Methodenanforderungen zu verarbeiten. -
Entfernen Sie in der Funktion
loopden Aufruf vonIoTHubDeviceClient_LL_DoWorkund ersetzen Sie den Aufrufdelay(10000)durch Folgendes, um diese neue Funktion aufzurufen:work_delay(10000);
💁 Sie finden diesen Code im Ordner code/wio-terminal.
😀 Ihr Bodenfeuchtigkeitssensor-Programm ist mit Ihrem IoT Hub verbunden!
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, weisen wir darauf hin, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.