12 KiB
Tilslut din IoT-enhed til skyen - Wio Terminal
I denne del af lektionen vil du forbinde din Wio Terminal til din IoT Hub for at sende telemetri og modtage kommandoer.
Forbind din enhed til IoT Hub
Det næste trin er at forbinde din enhed til IoT Hub.
Opgave - forbind til IoT Hub
-
Åbn projektet
soil-moisture-sensor
i VS Code. -
Åbn filen
platformio.ini
. Fjern afhængigheden af biblioteketknolleary/PubSubClient
. Dette blev brugt til at forbinde til den offentlige MQTT-broker og er ikke nødvendigt for at forbinde til IoT Hub. -
Tilføj følgende biblioteksafhængigheder:
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.2
Biblioteket
Seeed Arduino RTC
giver kode til at interagere med et realtidsur i Wio Terminal, som bruges til at holde styr på tiden. De resterende biblioteker gør det muligt for din IoT-enhed at forbinde til IoT Hub. -
Tilføj følgende til bunden af filen
platformio.ini
:build_flags = -DDONT_USE_UPLOADTOBLOB
Dette sætter et compiler-flag, der er nødvendigt, når Arduino IoT Hub-koden kompileres.
-
Åbn header-filen
config.h
. Fjern alle MQTT-indstillingerne, og tilføj følgende konstant for enhedens forbindelsesstreng:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";
Erstat
<connection string>
med forbindelsesstrengen for din enhed, som du kopierede tidligere. -
Forbindelsen til IoT Hub bruger et tidsbaseret token. Det betyder, at IoT-enheden skal kende den aktuelle tid. I modsætning til operativsystemer som Windows, macOS eller Linux synkroniserer mikrokontrollere ikke automatisk den aktuelle tid over internettet. Det betyder, at du skal tilføje kode for at hente den aktuelle tid fra en NTP-server. Når tiden er hentet, kan den gemmes i et realtidsur i Wio Terminal, så den korrekte tid kan anmodes om senere, forudsat at enheden ikke mister strøm. Tilføj en ny fil kaldet
ntp.h
med følgende kode:#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); }
Detaljerne i denne kode ligger uden for denne lektions omfang. Den definerer en funktion kaldet
initTime
, som henter den aktuelle tid fra en NTP-server og bruger den til at indstille uret på Wio Terminal. -
Åbn filen
main.cpp
, og fjern al MQTT-koden, inklusive header-filenPubSubClient.h
, deklarationen af variablenPubSubClient
, metodernereconnectMQTTClient
ogcreateMQTTClient
samt alle kald til disse variabler og metoder. Denne fil skal kun indeholde kode til at forbinde til WiFi, hente jordfugtighed og oprette et JSON-dokument med det. -
Tilføj følgende
#include
-direktiver øverst i filenmain.cpp
for at inkludere header-filer til IoT Hub-bibliotekerne og til at indstille tiden:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h"
-
Tilføj følgende kald til slutningen af funktionen
setup
for at indstille den aktuelle tid:initTime();
-
Tilføj følgende variabeldeklaration øverst i filen, lige under include-direktiverne:
IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;
Dette erklærer en
IOTHUB_DEVICE_CLIENT_LL_HANDLE
, et håndtag til en forbindelse til IoT Hub. -
Tilføj nedenunder følgende kode:
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"); } }
Dette erklærer en callback-funktion, der vil blive kaldt, når forbindelsen til IoT Hub ændrer status, såsom at forbinde eller afbryde. Statussen sendes til den serielle port.
-
Tilføj nedenunder en funktion til at forbinde til IoT Hub:
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); }
Denne kode initialiserer IoT Hub-bibliotekskoden og opretter derefter en forbindelse ved hjælp af forbindelsesstrengen i header-filen
config.h
. Denne forbindelse er baseret på MQTT. Hvis forbindelsen fejler, sendes dette til den serielle port - hvis du ser dette i outputtet, skal du tjekke forbindelsesstrengen. Endelig opsættes callback-funktionen for forbindelsesstatus. -
Kald denne funktion i funktionen
setup
under kaldet tilinitTime
:connectIoTHub();
-
Ligesom med MQTT-klienten kører denne kode på en enkelt tråd og har derfor brug for tid til at behandle meddelelser, der sendes af hubben og til hubben. Tilføj følgende øverst i funktionen
loop
for at gøre dette:IoTHubDeviceClient_LL_DoWork(_device_ll_handle);
-
Byg og upload denne kode. Du vil se forbindelsen i den serielle monitor:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothub
I outputtet kan du se, at NTP-tiden hentes, efterfulgt af, at enhedsklienten forbinder. Det kan tage et par sekunder at forbinde, så du kan se jordfugtigheden i outputtet, mens enheden forbinder.
💁 Du kan konvertere UNIX-tiden for NTP til en mere læsbar version ved hjælp af en hjemmeside som unixtimestamp.com
Send telemetri
Nu hvor din enhed er forbundet, kan du sende telemetri til IoT Hub i stedet for til MQTT-brokeren.
Opgave - send telemetri
-
Tilføj følgende funktion over funktionen
setup
: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); }
Denne kode opretter en IoT Hub-meddelelse fra en streng, der sendes som en parameter, sender den til hubben og rydder derefter op i meddelelsesobjektet.
-
Kald denne kode i funktionen
loop
, lige efter linjen, hvor telemetrien sendes til den serielle port:sendTelemetry(telemetry.c_str());
Håndter kommandoer
Din enhed skal kunne håndtere en kommando fra serverkoden for at styre relæet. Dette sendes som en direkte metodeanmodning.
Opgave - håndter en direkte metodeanmodning
-
Tilføj følgende kode før funktionen
connectIoTHub
: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); } }
Denne kode definerer en callback-metode, som IoT Hub-biblioteket kan kalde, når det modtager en direkte metodeanmodning. Den metode, der anmodes om, sendes i parameteren
method_name
. Denne funktion udskriver den kaldte metode til den serielle port og tænder eller slukker for relæet afhængigt af metodenavnet.💁 Dette kunne også implementeres i en enkelt direkte metodeanmodning, hvor den ønskede tilstand for relæet sendes i en payload, der kan sendes med metodeanmodningen og er tilgængelig fra parameteren
payload
. -
Tilføj følgende kode til slutningen af funktionen
directMethodCallback
: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 metodeanmodninger kræver et svar, og svaret består af to dele - et svar som tekst og en returkode. Denne kode opretter et resultat som følgende JSON-dokument:
{ "Result": "" }
Dette kopieres derefter ind i parameteren
response
, og størrelsen af dette svar sættes i parameterenresponse_size
. Denne kode returnerer derefterIOTHUB_CLIENT_OK
for at vise, at metoden blev håndteret korrekt. -
Tilslut callback-funktionen ved at tilføje følgende til slutningen af funktionen
connectIoTHub
:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL);
-
Funktionen
loop
vil kalde funktionenIoTHubDeviceClient_LL_DoWork
for at behandle hændelser sendt af IoT Hub. Dette kaldes kun hvert 10. sekund på grund afdelay
, hvilket betyder, at direkte metoder kun behandles hvert 10. sekund. For at gøre dette mere effektivt kan forsinkelsen på 10 sekunder implementeres som mange kortere forsinkelser, hvorIoTHubDeviceClient_LL_DoWork
kaldes hver gang. For at gøre dette skal du tilføje følgende kode over funktionenloop
:void work_delay(int delay_time) { int current = 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current += 100; } while (current < delay_time); }
Denne kode vil gentage sig gentagne gange, kalde
IoTHubDeviceClient_LL_DoWork
og forsinke i 100 ms hver gang. Den vil gøre dette så mange gange som nødvendigt for at forsinke i den tid, der gives i parameterendelay_time
. Dette betyder, at enheden højst venter 100 ms på at behandle direkte metodeanmodninger. -
I funktionen
loop
skal du fjerne kaldet tilIoTHubDeviceClient_LL_DoWork
og erstatte kaldetdelay(10000)
med følgende for at kalde denne nye funktion:work_delay(10000);
💁 Du kan finde denne kode i mappen code/wio-terminal.
😀 Dit jordfugtighedssensorprogram er nu forbundet til din IoT Hub!
Ansvarsfraskrivelse:
Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten Co-op Translator. Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.