15 KiB
قم بتوصيل جهاز إنترنت الأشياء الخاص بك بالسحابة - 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 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 على رمز مميز يعتمد على الوقت. هذا يعني أن جهاز إنترنت الأشياء يحتاج إلى معرفة الوقت الحالي. على عكس أنظمة التشغيل مثل 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، يعمل هذا الكود على خيط واحد لذا يحتاج إلى وقت لمعالجة الرسائل التي يتم إرسالها من وإلى IoT Hub. أضف ما يلي إلى أعلى وظيفة
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 من سلسلة يتم تمريرها كمعامل، ويرسلها إلى 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
ومؤخرًا لمدة 100 مللي ثانية في كل مرة. سيقوم بذلك بقدر ما هو مطلوب للتأخير للمدة الزمنية المحددة في معاملdelay_time
. هذا يعني أن الجهاز ينتظر بحد أقصى 100 مللي ثانية لمعالجة طلبات الطريقة المباشرة. -
في وظيفة
loop
، قم بإزالة استدعاءIoTHubDeviceClient_LL_DoWork
، واستبدل استدعاءdelay(10000)
بما يلي لاستدعاء هذه الوظيفة الجديدة:work_delay(10000);
💁 يمكنك العثور على هذا الكود في مجلد code/wio-terminal.
😀 برنامج مستشعر رطوبة التربة الخاص بك متصل بـ IoT Hub!
إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.