13 KiB
Verbind je IoT-apparaat met de cloud - Wio Terminal
In dit deel van de les verbind je je Wio Terminal met je IoT Hub om telemetrie te verzenden en opdrachten te ontvangen.
Verbind je apparaat met IoT Hub
De volgende stap is om je apparaat te verbinden met IoT Hub.
Taak - verbinden met IoT Hub
-
Open het
soil-moisture-sensor
project in VS Code. -
Open het bestand
platformio.ini
. Verwijder de afhankelijkheid van deknolleary/PubSubClient
bibliotheek. Deze werd gebruikt om verbinding te maken met de openbare MQTT-broker en is niet nodig om verbinding te maken met IoT Hub. -
Voeg de volgende bibliotheekafhankelijkheden toe:
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
De
Seeed Arduino RTC
bibliotheek biedt code om te communiceren met een real-time klok in de Wio Terminal, die wordt gebruikt om de tijd bij te houden. De overige bibliotheken maken het mogelijk dat je IoT-apparaat verbinding maakt met IoT Hub. -
Voeg het volgende toe aan de onderkant van het bestand
platformio.ini
:build_flags = -DDONT_USE_UPLOADTOBLOB
Dit stelt een compiler-vlag in die nodig is bij het compileren van de Arduino IoT Hub-code.
-
Open het headerbestand
config.h
. Verwijder alle MQTT-instellingen en voeg de volgende constante toe voor de apparaatverbindingsreeks:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";
Vervang
<connection string>
door de verbindingsreeks voor je apparaat die je eerder hebt gekopieerd. -
De verbinding met IoT Hub gebruikt een op tijd gebaseerd token. Dit betekent dat het IoT-apparaat de huidige tijd moet weten. In tegenstelling tot besturingssystemen zoals Windows, macOS of Linux synchroniseren microcontrollers niet automatisch de huidige tijd via internet. Dit betekent dat je code moet toevoegen om de huidige tijd op te halen van een NTP server. Zodra de tijd is opgehaald, kan deze worden opgeslagen in een real-time klok in de Wio Terminal, zodat de juiste tijd later kan worden opgevraagd, mits het apparaat niet zonder stroom komt te zitten. Voeg een nieuw bestand toe genaamd
ntp.h
met de volgende code:#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); }
De details van deze code vallen buiten de scope van deze les. Het definieert een functie genaamd
initTime
die de huidige tijd ophaalt van een NTP-server en deze gebruikt om de klok op de Wio Terminal in te stellen. -
Open het bestand
main.cpp
en verwijder alle MQTT-code, inclusief het headerbestandPubSubClient.h
, de declaratie van dePubSubClient
-variabele, de methodenreconnectMQTTClient
encreateMQTTClient
, en alle oproepen naar deze variabelen en methoden. Dit bestand mag alleen code bevatten om verbinding te maken met WiFi, de bodemvochtigheid op te halen en een JSON-document ermee te maken. -
Voeg de volgende
#include
-directives toe aan de bovenkant van het bestandmain.cpp
om headerbestanden voor de IoT Hub-bibliotheken en voor het instellen van de tijd op te nemen:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h"
-
Voeg de volgende oproep toe aan het einde van de
setup
-functie om de huidige tijd in te stellen:initTime();
-
Voeg de volgende variabeledeclaratie toe aan de bovenkant van het bestand, net onder de include-directives:
IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;
Dit declareert een
IOTHUB_DEVICE_CLIENT_LL_HANDLE
, een handle naar een verbinding met de IoT Hub. -
Voeg hieronder de volgende code toe:
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"); } }
Dit declareert een callbackfunctie die wordt aangeroepen wanneer de verbinding met de IoT Hub van status verandert, zoals verbinden of verbreken. De status wordt naar de seriële poort gestuurd.
-
Voeg hieronder een functie toe om verbinding te maken met 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); }
Deze code initialiseert de IoT Hub-bibliotheekcode en maakt vervolgens een verbinding met behulp van de verbindingsreeks in het headerbestand
config.h
. Deze verbinding is gebaseerd op MQTT. Als de verbinding mislukt, wordt dit naar de seriële poort gestuurd - als je dit in de uitvoer ziet, controleer dan de verbindingsreeks. Ten slotte wordt de callback voor de verbindingsstatus ingesteld. -
Roep deze functie aan in de
setup
-functie onder de oproep naarinitTime
:connectIoTHub();
-
Net zoals bij de MQTT-client, draait deze code op een enkele thread en heeft tijd nodig om berichten te verwerken die door de hub worden verzonden en naar de hub worden verzonden. Voeg het volgende toe aan de bovenkant van de
loop
-functie om dit te doen:IoTHubDeviceClient_LL_DoWork(_device_ll_handle);
-
Bouw en upload deze code. Je zult de verbinding zien in de seriële monitor:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothub
In de uitvoer kun je zien dat de NTP-tijd wordt opgehaald, gevolgd door het verbinden van de apparaatclient. Het kan enkele seconden duren om verbinding te maken, dus je kunt de bodemvochtigheid in de uitvoer zien terwijl het apparaat verbinding maakt.
💁 Je kunt de UNIX-tijd van de NTP omzetten naar een meer leesbare versie met een website zoals unixtimestamp.com.
Telemetrie verzenden
Nu je apparaat is verbonden, kun je telemetrie naar de IoT Hub verzenden in plaats van naar de MQTT-broker.
Taak - telemetrie verzenden
-
Voeg de volgende functie toe boven de
setup
-functie: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); }
Deze code maakt een IoT Hub-bericht van een string die als parameter wordt doorgegeven, verzendt het naar de hub en ruimt vervolgens het berichtobject op.
-
Roep deze code aan in de
loop
-functie, net na de regel waar de telemetrie naar de seriële poort wordt verzonden:sendTelemetry(telemetry.c_str());
Opdrachten verwerken
Je apparaat moet een opdracht van de servercode verwerken om het relais te bedienen. Dit wordt verzonden als een directe methodeaanvraag.
Taak - een directe methodeaanvraag verwerken
-
Voeg de volgende code toe vóór de functie
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); } }
Deze code definieert een callbackmethode die de IoT Hub-bibliotheek kan aanroepen wanneer deze een directe methodeaanvraag ontvangt. De methode die wordt aangevraagd, wordt verzonden in de parameter
method_name
. Deze functie print de aangeroepen methode naar de seriële poort en schakelt het relais in of uit afhankelijk van de methode naam.💁 Dit kan ook worden geïmplementeerd in een enkele directe methodeaanvraag, waarbij de gewenste status van het relais wordt doorgegeven in een payload die kan worden doorgegeven met de methodeaanvraag en beschikbaar is vanuit de parameter
payload
. -
Voeg de volgende code toe aan het einde van de functie
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;
Directe methodeaanvragen hebben een antwoord nodig, en het antwoord bestaat uit twee delen - een antwoord als tekst en een retourcode. Deze code maakt een resultaat als het volgende JSON-document:
{ "Result": "" }
Dit wordt vervolgens gekopieerd naar de parameter
response
, en de grootte van dit antwoord wordt ingesteld in de parameterresponse_size
. Deze code retourneert vervolgensIOTHUB_CLIENT_OK
om aan te geven dat de methode correct is afgehandeld. -
Koppel de callback door het volgende toe te voegen aan het einde van de functie
connectIoTHub
:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL);
-
De
loop
-functie roept de functieIoTHubDeviceClient_LL_DoWork
aan om gebeurtenissen te verwerken die door IoT Hub worden verzonden. Dit wordt slechts om de 10 seconden aangeroepen vanwege dedelay
, wat betekent dat directe methoden slechts om de 10 seconden worden verwerkt. Om dit efficiënter te maken, kan de vertraging van 10 seconden worden geïmplementeerd als veel kortere vertragingen, waarbijIoTHubDeviceClient_LL_DoWork
elke keer wordt aangeroepen. Voeg hiervoor de volgende code toe boven deloop
-functie:void work_delay(int delay_time) { int current = 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current += 100; } while (current < delay_time); }
Deze code zal herhaaldelijk in een lus draaien,
IoTHubDeviceClient_LL_DoWork
aanroepen en elke keer 100ms vertragen. Het zal dit zo vaak doen als nodig is om te vertragen voor de hoeveelheid tijd die wordt gegeven in de parameterdelay_time
. Dit betekent dat het apparaat maximaal 100ms wacht om directe methodeaanvragen te verwerken. -
Verwijder in de
loop
-functie de oproep naarIoTHubDeviceClient_LL_DoWork
en vervang de oproepdelay(10000)
door het volgende om deze nieuwe functie aan te roepen:work_delay(10000);
💁 Je kunt deze code vinden in de code/wio-terminal map.
😀 Je bodemvochtigheidssensorprogramma is verbonden met je IoT Hub!
Disclaimer:
Dit document is vertaald met behulp van de AI-vertalingsservice Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in zijn oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.