17 KiB
Повежите ваш IoT уређај са облаком - Wio Terminal
У овом делу лекције, повезаћете ваш Wio Terminal са IoT Hub-ом, како бисте слали телеметрију и примали команде.
Повежите ваш уређај са IoT Hub-ом
Следећи корак је повезивање вашег уређаја са IoT Hub-ом.
Задатак - повезивање са IoT Hub-ом
-
Отворите пројекат
soil-moisture-sensorу VS Code-у. -
Отворите датотеку
platformio.ini. Уклоните зависност од библиотекеknolleary/PubSubClient. Ова библиотека је коришћена за повезивање са јавним MQTT брокером, али није потребна за повезивање са IoT Hub-ом. -
Додајте следеће зависности од библиотека:
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Библиотека
Seeed Arduino RTCпружа код за интеракцију са реалним временским сатом у Wio Terminal-у, који се користи за праћење времена. Преостале библиотеке омогућавају вашем IoT уређају да се повеже са IoT Hub-ом. -
Додајте следеће на крај датотеке
platformio.ini:build_flags = -DDONT_USE_UPLOADTOBLOBОво поставља заставицу компајлера која је потребна приликом компајлирања кода за Arduino IoT Hub.
-
Отворите заглавну датотеку
config.h. Уклоните сва подешавања за MQTT и додајте следећу константу за стринг за повезивање уређаја:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";Замените
<connection string>стрингом за повезивање вашег уређаја који сте раније копирали. -
Повезивање са IoT Hub-ом користи токен заснован на времену. То значи да IoT уређај мора знати тренутно време. За разлику од оперативних система као што су Windows, macOS или Linux, микроконтролери не синхронизују аутоматски тренутно време преко интернета. То значи да морате додати код за добијање тренутног времена са NTP сервера. Када се време преузме, може се чувати у реалном временском сату у Wio Terminal-у, омогућавајући да се исправно време затражи касније, под условом да уређај не изгуби напајање. Додајте нову датотеку под називом
ntp.hса следећим кодом:#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); }Детаљи овог кода су ван оквира ове лекције. Он дефинише функцију
initTimeкоја добија тренутно време са NTP сервера и користи га за подешавање сата на Wio Terminal-у. -
Отворите датотеку
main.cppи уклоните сав MQTT код, укључујући заглавну датотекуPubSubClient.h, декларацију променљивеPubSubClient, методеreconnectMQTTClientиcreateMQTTClient, као и све позиве ових променљивих и метода. Ова датотека треба да садржи само код за повезивање на WiFi, добијање влажности земљишта и креирање JSON документа са тим подацима. -
Додајте следеће
#includeдирективе на врх датотекеmain.cppкако бисте укључили заглавне датотеке за IoT Hub библиотеке и за подешавање времена:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h" -
Додајте следећи позив на крај функције
setupкако бисте подесили тренутно време:initTime(); -
Додајте следећу декларацију променљиве на врх датотеке, одмах испод директива за укључивање:
IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;Ово декларише
IOTHUB_DEVICE_CLIENT_LL_HANDLE, ручицу за повезивање са IoT Hub-ом. -
Испод овога, додајте следећи код:
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"); } }Ово декларише функцију повратног позива која ће бити позвана када се статус повезивања са IoT Hub-ом промени, као што је повезивање или прекид везе. Статус се шаље на серијски порт.
-
Испод овога, додајте функцију за повезивање са 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); }Овај код иницијализује IoT Hub библиотеку, а затим креира везу користећи стринг за повезивање у заглавној датотеци
config.h. Ова веза се заснива на MQTT-у. Ако веза не успе, то се шаље на серијски порт - ако то видите у излазу, проверите стринг за повезивање. На крају се поставља повратни позив за статус везе. -
Позовите ову функцију у функцији
setupиспод позива функцијеinitTime:connectIoTHub(); -
Као и код MQTT клијента, овај код ради на једном ниту, па му је потребно време за обраду порука које шаље хабу и које хаб шаље њему. Додајте следеће на врх функције
loopкако бисте то омогућили:IoTHubDeviceClient_LL_DoWork(_device_ll_handle); -
Компилирајте и отпремите овај код. Видећете повезивање у серијском монитору:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothubУ излазу можете видети како се преузима NTP време, а затим како се клијент уређаја повезује. Може потрајати неколико секунди да се повежете, па можете видети влажност земљишта у излазу док се уређај повезује.
💁 Можете конвертовати UNIX време за NTP у читљивију верзију користећи веб сајт као што је unixtimestamp.com
Слање телеметрије
Сада када је ваш уређај повезан, можете слати телеметрију IoT Hub-у уместо MQTT брокеру.
Задатак - слање телеметрије
-
Додајте следећу функцију изнад функције
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); }Овај код креира IoT Hub поруку из стринга који се прослеђује као параметар, шаље је хабу, а затим чисти објекат поруке.
-
Позовите овај код у функцији
loop, одмах након линије где се телеметрија шаље на серијски порт:sendTelemetry(telemetry.c_str());
Обрада команди
Ваш уређај треба да обради команду са серверског кода за контролу релеја. Ово се шаље као захтев за директну методу.
Задатак - обрада захтева за директну методу
-
Додајте следећи код пре функције
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); } }Овај код дефинише функцију повратног позива коју IoT Hub библиотека може позвати када прими захтев за директну методу. Метода која се захтева шаље се у параметру
method_name. Ова функција исписује позвану методу на серијски порт, а затим укључује или искључује релеј у зависности од имена методе.💁 Ово би могло бити имплементирано и у једној директној методи, прослеђујући жељено стање релеја у payload који се може проследити са захтевом за методу и доступан је из параметра
payload. -
Додајте следећи код на крај функције
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;Захтеви за директне методе захтевају одговор, а одговор је у два дела - одговор као текст и код повратка. Овај код ће креирати резултат као следећи JSON документ:
{ "Result": "" }Ово се затим копира у параметар
response, а величина овог одговора се поставља у параметарresponse_size. Овај код затим враћаIOTHUB_CLIENT_OKкако би показао да је метода успешно обрађена. -
Повежите повратни позив додавањем следећег на крај функције
connectIoTHub:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL); -
Функција
loopће позвати функцијуIoTHubDeviceClient_LL_DoWorkкако би обрадила догађаје које шаље IoT Hub. Ово се позива само сваких 10 секунди збогdelay, што значи да се директне методе обрађују само сваких 10 секунди. Да би ово било ефикасније, 10-секундно кашњење може бити имплементирано као много краћих кашњења, позивајућиIoTHubDeviceClient_LL_DoWorkсваки пут. Да бисте то урадили, додајте следећи код изнад функцијеloop:void work_delay(int delay_time) { int current = 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current += 100; } while (current < delay_time); }Овај код ће се понављати, позивајући
IoTHubDeviceClient_LL_DoWorkи одлажући за 100ms сваки пут. То ће радити онолико пута колико је потребно да се одложи за време дато у параметруdelay_time. То значи да уређај чека највише 100ms да обради захтеве за директне методе. -
У функцији
loop, уклоните позив функцијеIoTHubDeviceClient_LL_DoWork, и замените позивdelay(10000)следећим како бисте позвали ову нову функцију:work_delay(10000);
💁 Овај код можете пронаћи у фолдеру code/wio-terminal.
😀 Ваш програм за сензор влажности земљишта је повезан са вашим IoT Hub-ом!
Одрицање од одговорности:
Овај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције Co-op Translator. Иако се трудимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.