18 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
. -
Добавете следния код в края на функцията
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!
Отказ от отговорност:
Този документ е преведен с помощта на AI услуга за превод Co-op Translator. Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.