12 KiB
Koble IoT-enheten din til skyen - Wio Terminal
I denne delen av leksjonen skal du koble Wio Terminal til IoT Hub for å sende telemetri og motta kommandoer.
Koble enheten til IoT Hub
Neste steg er å koble enheten til IoT Hub.
Oppgave - koble til IoT Hub
-
Åpne prosjektet
soil-moisture-sensor
i VS Code. -
Åpne filen
platformio.ini
. Fjern bibliotekavhengighetenknolleary/PubSubClient
. Dette ble brukt for å koble til en offentlig MQTT-broker og er ikke nødvendig for å koble til IoT Hub. -
Legg til følgende bibliotekavhengigheter:
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
gir kode for å bruke en sanntidsklokke i Wio Terminal, som brukes til å holde styr på tiden. De andre bibliotekene lar IoT-enheten din koble til IoT Hub. -
Legg til følgende nederst i filen
platformio.ini
:build_flags = -DDONT_USE_UPLOADTOBLOB
Dette setter et kompilatorflagg som er nødvendig når Arduino IoT Hub-koden kompileres.
-
Åpne header-filen
config.h
. Fjern alle MQTT-innstillingene og legg til følgende konstant for enhetens tilkoblingsstreng:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";
Erstatt
<connection string>
med tilkoblingsstrengen for enheten din som du kopierte tidligere. -
Tilkoblingen til IoT Hub bruker en tidsbasert token. Dette betyr at IoT-enheten må vite gjeldende tid. I motsetning til operativsystemer som Windows, macOS eller Linux, synkroniserer ikke mikrokontrollere automatisk tiden over Internett. Dette betyr at du må legge til kode for å hente gjeldende tid fra en NTP-server. Når tiden er hentet, kan den lagres i en sanntidsklokke i Wio Terminal, slik at korrekt tid kan hentes senere, forutsatt at enheten ikke mister strøm. Legg til en ny fil kalt
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); }
Detaljene i denne koden er utenfor omfanget av denne leksjonen. Den definerer en funksjon kalt
initTime
som henter gjeldende tid fra en NTP-server og bruker den til å stille klokken på Wio Terminal. -
Åpne filen
main.cpp
og fjern all MQTT-kode, inkludert header-filenPubSubClient.h
, deklarasjonen av variabelenPubSubClient
, metodenereconnectMQTTClient
ogcreateMQTTClient
, og alle kall til disse variablene og metodene. Denne filen skal kun inneholde kode for å koble til WiFi, hente jordfuktighet og lage et JSON-dokument med det. -
Legg til følgende
#include
-direktiver øverst i filenmain.cpp
for å inkludere header-filer for IoT Hub-bibliotekene og for å stille inn tiden:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h"
-
Legg til følgende kall på slutten av
setup
-funksjonen for å stille inn gjeldende tid:initTime();
-
Legg til følgende variabeldeklarasjon øverst i filen, rett under
include
-direktivene:IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;
Dette deklarerer en
IOTHUB_DEVICE_CLIENT_LL_HANDLE
, et håndtak for en tilkobling til IoT Hub. -
Under dette, legg til 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 deklarerer en callback-funksjon som vil bli kalt når tilkoblingen til IoT Hub endrer status, for eksempel ved tilkobling eller frakobling. Statusen sendes til seriellporten.
-
Under dette, legg til en funksjon for å koble 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 koden initialiserer IoT Hub-bibliotekskoden og oppretter deretter en tilkobling ved hjelp av tilkoblingsstrengen i header-filen
config.h
. Denne tilkoblingen er basert på MQTT. Hvis tilkoblingen mislykkes, sendes dette til seriellporten - hvis du ser dette i utdataene, sjekk tilkoblingsstrengen. Til slutt settes callback-funksjonen for tilkoblingsstatus opp. -
Kall denne funksjonen i
setup
-funksjonen under kallet tilinitTime
:connectIoTHub();
-
Akkurat som med MQTT-klienten, kjører denne koden på en enkelt tråd og trenger tid til å behandle meldinger som sendes av huben og til huben. Legg til følgende øverst i
loop
-funksjonen for å gjøre dette:IoTHubDeviceClient_LL_DoWork(_device_ll_handle);
-
Bygg og last opp denne koden. Du vil se tilkoblingen i seriellmonitoren:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothub
I utdataene kan du se at NTP-tiden hentes, etterfulgt av at enhetsklienten kobler til. Det kan ta noen sekunder å koble til, så du kan se jordfuktigheten i utdataene mens enheten kobler til.
💁 Du kan konvertere UNIX-tiden for NTP til en mer lesbar versjon ved å bruke et nettsted som unixtimestamp.com
Send telemetri
Nå som enheten din er koblet til, kan du sende telemetri til IoT Hub i stedet for MQTT-brokeren.
Oppgave - send telemetri
-
Legg til følgende funksjon over
setup
-funksjonen: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 koden oppretter en IoT Hub-melding fra en streng som sendes som en parameter, sender den til huben, og rydder deretter opp i meldingsobjektet.
-
Kall denne koden i
loop
-funksjonen, rett etter linjen der telemetrien sendes til seriellporten:sendTelemetry(telemetry.c_str());
Håndtere kommandoer
Enheten din må håndtere en kommando fra serverkoden for å kontrollere reléet. Dette sendes som en direkte metodeforespørsel.
Oppgave - håndtere en direkte metodeforespørsel
-
Legg til følgende kode før funksjonen
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 koden definerer en callback-metode som IoT Hub-biblioteket kan kalle når det mottar en direkte metodeforespørsel. Metoden som forespørres, sendes i parameteren
method_name
. Denne funksjonen skriver metoden som ble kalt til seriellporten, og slår deretter reléet av eller på avhengig av metodenavnet.💁 Dette kan også implementeres i en enkelt direkte metodeforespørsel, der ønsket tilstand for reléet sendes i en nyttelast som kan sendes med metodeforespørselen og er tilgjengelig fra parameteren
payload
. -
Legg til følgende kode på slutten av funksjonen
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 metodeforespørsler trenger et svar, og svaret består av to deler - et svar som tekst og en returkode. Denne koden vil opprette et resultat som følgende JSON-dokument:
{ "Result": "" }
Dette kopieres deretter inn i parameteren
response
, og størrelsen på dette svaret settes i parameterenresponse_size
. Denne koden returnerer deretterIOTHUB_CLIENT_OK
for å vise at metoden ble håndtert korrekt. -
Koble opp callback-funksjonen ved å legge til følgende på slutten av funksjonen
connectIoTHub
:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL);
-
Funksjonen
loop
vil kalle funksjonenIoTHubDeviceClient_LL_DoWork
for å behandle hendelser sendt av IoT Hub. Dette kalles bare hvert 10. sekund på grunn avdelay
, noe som betyr at direkte metoder bare behandles hvert 10. sekund. For å gjøre dette mer effektivt kan 10-sekunders forsinkelsen implementeres som mange kortere forsinkelser, derIoTHubDeviceClient_LL_DoWork
kalles hver gang. For å gjøre dette, legg til følgende kode over funksjonenloop
: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 koden vil loope gjentatte ganger, kalle
IoTHubDeviceClient_LL_DoWork
og forsinke i 100 ms hver gang. Den vil gjøre dette så mange ganger som nødvendig for å forsinke i den tiden som er gitt i parameterendelay_time
. Dette betyr at enheten venter maksimalt 100 ms for å behandle direkte metodeforespørsler. -
I funksjonen
loop
, fjern kallet tilIoTHubDeviceClient_LL_DoWork
, og erstatt kallet tildelay(10000)
med følgende for å kalle denne nye funksjonen:work_delay(10000);
💁 Du finner denne koden i mappen code/wio-terminal.
😀 Programmet for jordfuktighetssensoren din er nå koblet til IoT Hub!
Ansvarsfraskrivelse:
Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.