16 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 باید زمان فعلی را بداند. برخلاف سیستمعاملهایی مانند ویندوز، macOS یا لینوکس، میکروکنترلرها بهطور خودکار زمان فعلی را از طریق اینترنت همگامسازی نمیکنند. بنابراین باید کدی اضافه کنید تا زمان فعلی را از یک 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();
-
اعلان متغیر زیر را به بالای فایل، درست زیر دستورات include اضافه کنید:
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"); } }
این یک تابع callback اعلام میکند که وقتی اتصال به 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 است. اگر اتصال شکست بخورد، این موضوع به پورت سریال ارسال میشود - اگر این را در خروجی مشاهده کردید، رشته اتصال را بررسی کنید. در نهایت، callback وضعیت اتصال تنظیم میشود. -
این تابع را در تابع
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 دریافت میشود، سپس کلاینت دستگاه متصل میشود. ممکن است چند ثانیه طول بکشد تا اتصال برقرار شود، بنابراین ممکن است رطوبت خاک را در خروجی مشاهده کنید در حالی که دستگاه در حال اتصال است.
💁 میتوانید زمان یونیکس 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); } }
این کد یک متد callback تعریف میکند که کتابخانه 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
را بازمیگرداند تا نشان دهد متد بهدرستی مدیریت شده است. -
callback را با اضافه کردن مورد زیر به انتهای تابع
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
را فراخوانی کرده و هر بار 100 میلیثانیه تأخیر میاندازد. این کار را به تعداد دفعات لازم برای تأخیر به مدت زمان داده شده در پارامترdelay_time
انجام میدهد. این بدان معناست که دستگاه حداکثر 100 میلیثانیه برای پردازش درخواستهای متد مستقیم منتظر میماند. -
در تابع
loop
، فراخوانی بهIoTHubDeviceClient_LL_DoWork
را حذف کرده و فراخوانیdelay(10000)
را با مورد زیر جایگزین کنید تا این تابع جدید فراخوانی شود:work_delay(10000);
💁 میتوانید این کد را در پوشه code/wio-terminal پیدا کنید.
😀 برنامه حسگر رطوبت خاک شما به IoT Hub متصل شد!
سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما تلاش میکنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است شامل خطاها یا نادرستیها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حیاتی، ترجمه حرفهای انسانی توصیه میشود. ما مسئولیتی در قبال سوء تفاهمها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.