الجمعة، 13 نوفمبر 2020

تحكم في مصباح LED عبر الإنترنت من هاتفك المحمول باستخدام Raspberry Pi

 الأشياء المستخدمة في هذا المشروع

مكونات الأجهزة

رازبيري باي 4 موديل بي

بطاقة ذاكرة فلاش ، بطاقة SD

ثنائي ضوئي ليد

اسلاك التوصيل مع لوحة الربط


تطبيقات البرمجيات والخدمات عبر الإنترنت

سحابة العظمة

Raspberry Pi Raspbian


قصة

ستوحاة من البرنامج التعليمي Internet Switch من Talha الذي كان يعتمد على ESP8266 ، فكرت في فعل الشيء نفسه على Raspberry Pi بدلاً من ذلك.

إذن هذا ما سنفعله في هذا البرنامج التعليمي. سنستخدم Raspberry Pi و Grandeur Cloud لبناء مفتاح إنترنت. بعبارة أخرى ، سوف نتحكم في مؤشر LED متصل بدبوس GPIO الخاص بـ RPi من تطبيق الويب الخاص بنا والذي سنقوم ببنائه باستخدام Grandeur Cloud كخلفية لدينا. سيرسل تطبيق الويب الخاص بنا أمر التشغيل / الإيقاف إلى السحابة الذي سيستمع إليه RPi وبالتالي يقوم بتحديث الجهد على دبوس LED الخاص به.

لماذا سحابة Grandeur؟

إذا لم نستخدم خلفية مُدارة ، فسيتعين علينا دمج خادم MQTT وواجهة برمجة تطبيقات للعميل بين تطبيقنا وجهازنا (RPi) للسماح بإجراء الاتصالات في الوقت الفعلي بينهما. وإذا كان لدينا عدة RPis ونريد الإشارة إلى بعضها لتشغيل مصابيح LED الخاصة بهم والبعض الآخر للبقاء في وضع إيقاف التشغيل ، فإن حانة / فرع MQTT سيفعل ذلك من أجلنا.

ولكن إذا احتجنا إلى تخزين السجلات أيضًا ، دعنا نقول متى تم تشغيل أو إيقاف تشغيل LED الخاص بـ RPi1 ومن فعل ذلك ، فسنحتاج إلى دمج قاعدة بيانات (mySQL أو mongoDB) مع نظامنا أيضًا. وبالمثل ، فإن إضافة تخزين الملفات ، و OTA ، وغيرها من الميزات المماثلة ستؤدي إلى زيادة عدد عمليات الدمج التي نحتاج إلى القيام بها وبالتالي تعقيد نظامنا.


يوفر Grandeur Cloud كل هذه الأشياء في تكامل واحد ، ويمنحنا واجهة برمجة تطبيقات واحدة متوفرة بلغة python و javascript و C لـ RPis و ESPs وجميع Arduinos. لهذا السبب يُفضل عادةً كخلفية في إنترنت الأشياء ، باعتباره التكامل الفردي لمعظم حالات استخدام إنترنت الأشياء.

دعونا نتعمق في مشروعنا الآن.

إعداد نظام Raspberry Pi OS الخاص بنا

بادئ ذي بدء ، لنقم بإعداد Raspberry Pi الخاص بنا مع نظام التشغيل. يمكنك اتباع هذه الخطوات لإعداد RPi الجديد الخاص بك:

قم بتنزيل Raspberry Pi Imager من هنا وقم بتثبيته.

قم بتوصيل بطاقة SD بجهاز الكمبيوتر الخاص بك وقم بتشغيل مصور RPi.

اختر نظام التشغيل الذي تريد تشغيل RPi عليه. كنت أرغب في استخدام RPi في الوضع بدون رأس بدون واجهة المستخدم الرسومية لسطح المكتب لإبقاء الأشياء خفيفة قدر الإمكان وعدم توصيل شاشة بـ RPi. لذلك قمت بتثبيت Raspbian Lite.

اختر بطاقة SD الخاصة بك وانقر فوق كتابة.

بمجرد اكتمال الكتابة ، قم بإزالة بطاقة SD وإدخالها مرة أخرى ، إذا كانت على نظام Mac ، أو اتركها على windows.

افتح بطاقة SD (المسماة التمهيد) من المستكشف ، وأنشئ ملفًا جديدًا باسم wpa_supplicant.conf وضع ما يلي فيه واستبدل أقواس الزاوية بالمعلمات المقابلة

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=<Insert 2 letter ISO 3166-1 country code here>

network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
}

قم بإنشاء ملف فارغ باسم ssh في التمهيد. سيسمح لك ذلك بالاتصال بمحطة RPi الخاصة بك من جهاز الكمبيوتر الخاص بك من خلال ssh (غلاف آمن) ، دون الحاجة إلى شاشة منفصلة.

قم بإخراج بطاقة SD وإزالتها من جهاز الكمبيوتر الخاص بك. أدخله في RPi وقم بتشغيله. سيتصل RPi بشبكة WiFi الخاصة بك باستخدام تكوينات WiFi التي قدمتها في ملف wpa_supplicant.conf.

في جهاز الكمبيوتر الخاص بك ، افتح Terminal وقم بتشغيل الأمر ping للتحقق مما إذا كان RPi قد وصل عبر الإنترنت باستخدام SSID و PSK اللذين قدمتهما في ملف wpa_supplicant.conf:

    ping raspberrypi.local

    إذا نجح الأمر ping ، فهذا يعني أن RPi متصل بنقطة وصول جهاز التوجيه الخاص بك. يمكنك الآن إدراج RPi الخاص بك. pi هو حساب المستخدم الافتراضي في Raspbian والذي يمكنك تسجيل الدخول إليه عن طريق تشغيل:

    ssh pi@raspberrypi.local

    إذا طلبت كلمة المرور ، فاستخدم "Raspberry".

    الآن بعد أن أصبحت متصلاً بمحطة Raspbian ، قم بتحديث مستودعاتها وإصدار python الذي تريد استخدامه

    sudo apt-get update
    sudo apt-get install python3 python3-env

    الخطوة الأولى: البدء

    أنشئ مشروعًا جديدًا من خلال زيارة تطبيق الويب Grandeur Cloud dashboard.

    قم بزيارة صفحة الإعدادات ، واحصل على مفتاح API الخاص بمشروعك ، وقم بإنشاء بيانات اعتماد الوصول كما هو موضح أدناه. سنحتاج إلى مفتاح API وبيانات اعتماد الوصول أثناء إنشاء تطبيقنا.

    قم بإنشاء حساب مستخدم جديد من علامة التبويب الحسابات. سنقوم لاحقًا بتسجيل الدخول إلى تطبيقنا باستخدام البريد الإلكتروني وكلمة المرور اللذين ننشئهما الآن. هذه ميزة رائعة أخرى لـ Grandeur Cloud: يمكن لعدة مستخدمين استخدام تطبيقك من خلال تسجيل الدخول باستخدام رسائل البريد الإلكتروني وكلمات المرور الخاصة بهم. يمكن لكل مستخدم الاقتران والتفاعل مع أجهزته الخاصة. تم بناء المصادقة في قلب Grandeur Cloud. يتم توضيح إنشاء المستخدم

    الآن قم بإنشاء جهاز جديد من خلال صفحة الأجهزة. تنشئ هذه العملية معرف جهاز جديدًا سنستخدمه أثناء كتابة رمز لجهازنا. لذلك من الناحية الفنية ، يحتاج كل جهاز يتصل بالسحابة إلى معرف فريد. يشبه جهازك الأصول الرقمية بمعرّف فريد وستستخدم هذا المعرّف متى اتصلت بجهازك من تطبيقك. ينشئ تسجيل الجهاز أيضًا رمز وصول. لا تنس نسخها لأنها مطلوبة في كود الجهاز لتأكيد صحة المصدر لطلبات الجهاز. لن يكون الوصول إليها بعد إغلاق مربع الحوار. يتم توضيح إنشاء الجهاز أدناه:

    لا يمكن للمستخدم التفاعل مع جهاز ما لم يتم إقرانه به. يجعل إقران جهاز المستخدم هو المسؤول عن الجهاز - مما يعني أنه يمكن للمستخدم جلب / تحديث متغيرات أجهزته المقترنة. هناك طريقتان يمكنك من خلالهما إقران جهازك: 1) باستخدام Cloud Dashboard ، أو 2) من خلال تطبيق الويب باستخدام وظيفة pairDevice () لواجهة برمجة تطبيقات الجهاز. هذه الطريقة الثانية لها أهمية كبيرة إذا نظرت إليها من وجهة نظر الإنتاج. مثلما يمكنك الآن شحن منتجات أجهزتك ، ويمكن للمستخدمين تسجيل الدخول إلى تطبيقك والمطالبة بملكية جهاز يشترونه من متجرك عن طريق إقرانه. إليك كيفية إقران جهازك بمستخدم باستخدام Cloud Dashboard:

    هذه هي. يمكنك متابعة البرنامج التعليمي hello world الخاص بـ Grandeur Cloud للحصول على مزيد من التفاصيل حول كل خطوة.

    الخطوة الثانية: برنامج الأجهزة

    نظرًا لأننا حددنا متغير حالة في النماذج أثناء إنشاء نموذج أجهزتنا من Cloud Dashboard ، فسنطلب من السحابة أن ترسل إلينا أي تحديثات في نماذج أجهزتنا على نهاية RPi الخاصة بنا والتي ستوفر لنا بالتالي تحديثًا للحالة. لهذا الغرض ، سنستخدم Py SDK لـ Grandeur Cloud. الهدف هو عندما يتم تشغيل برنامجنا ، فإنه يستمع إلى أي تغيير في متغير الحالة. إذا تغيرت القيمة إلى 1 ، يقوم هذا البرنامج بتشغيل مؤشر LED الخاص بنا في GPIO17 ، وإلا سيتم إيقاف تشغيله. لنفعلها.

    بعد إجراء ssh في RPi الخاص بنا ، فلنقم بإنشاء بيئة افتراضية أولاً لبرنامج الجهاز الخاص بمشروعنا للحفاظ على حزمه ومكتباته معزولة عن المكتبات العالمية:

    python3 -m venv "Pi Switch"

    نقوم بتثبيت حزمة GPIO الخاصة بـ RPi للمساعدة في التحكم في دبابيس GPIO الخاصة بـ RPi وحزمة grandeurcloud للتواصل مع السحابة.

    تثبيت python -m pip RPI.GPIO grandeurcloud

    ثم نقوم بإنشاء ملف Hardware.py جديد وكتابة برنامج الجهاز فيه.

    هذا هو كود برنامج بايثون الخاص بنا

    # Import the library
    import grandeurcloud.apollo.device as apollo
    from gpiozero import LED
    led = LED(17)
    # Define the apiKey and Auth token
    apiKey = "YOUR-API-KEY"
    token = "YOUR-DEVICE-TOKEN"
    deviceID = "YOUR-DEVICE-ID"
    # Event listener on connection state
    def onConnection(state):
    # Print the current state
    print(state)
    # Callback function to handle state change event
    def handleEvent(data):
    # Print
    print(data)
    led.value = data["state"]
    # Callback function to handle current state
    def handleParms(data):
    # Print
    print(data["deviceParms"])
    led.value = data["deviceParms"]["state"]
    # Init the SDK and get reference to the project
    project = apollo.init(apiKey, token)
    # Place listener
    project.onConnection(onConnection)
    # Get a reference to device class
    device = project.device(deviceID)
    # Subscribe to state change event
    device.onParms(handleEvent)
    # Get current state
    device.getParms(handleParms)
    # Block main thread
    while 1:
    pass



    المنطق بسيط جدا. نحدد وظائف معالج الحدث أولاً.

    يتم استدعاء onConnection عندما ينجح البرنامج في إنشاء اتصال آمن بالسحابة.

    يتم استدعاء handleParmsUpdate عندما تقوم السحابة بإخطار RPi بتحديث في متغير parms (الحالة في هذه الحالة).

    يتم استدعاء handleParms عندما ترسل السحابة جميع متغيرات parms استجابةً لاستدعاء دالة getParms.

    بمجرد تحديد معالجات الأحداث ، نبدأ في إعداد الاتصال عن طريق استدعاء وظيفة apollo.init باستخدام مفتاح API الخاص بمشروعنا والرمز المميز للجهاز ، ثم تحديد جهازنا عن طريق تمرير معرف الجهاز إلى project.device. قمنا بإعداد معالجات الأحداث المحددة مسبقًا الخاصة بنا للأحداث المناسبة عن طريق استدعاء project.onConnection ، device.onParms ، device.getParms على التوالي.

    تمنع الحلقة while 1 البرنامج من الخروج. يمكنك هنا كتابة الكود الذي تريد تنفيذه بشكل متكرر - مثل قراءة GPIO بعد كل 5 ثوانٍ.

    ما يفعله هذا البرنامج هو عند تشغيله ، يبدأ في إنشاء قناة في الوقت الفعلي مع السحابة. عندما يتم إنشاء الاتصال بالكامل ، فإنه يحصل على برامز الجهاز من السحابة لتهيئة دبوس LED RPi بالحالة (انظر وظيفة handleParms). استدعاء onParms يجعله يستمع لأي تحديثات مستقبلية في متغيرات parms. بمجرد حدوث أي تحديث من هذا القبيل ، ترسله السحابة إلى RPi الذي يقوم بتحديث حالة دبوس LED الخاص به (انظر وظيفة handleParmsUpdate).

    الخطوة 3: تطبيق الويب

    يحتوي تطبيقنا على ملفين index.html حيث نصمم تخطيط الصفحة و main.js حيث نبني منطق الصفحة. سنستخدم JavaScript SDK لدمج Grandeur Cloud في تطبيقنا.

    <!-- Index.html -->
    <!DOCTYPE html>
    <html>
    <!-- Head block of our page-->
    <head>
    <!-- Let's give our page a title-->
    <title>Pi Switch</title>
    <!-- Link SDK with CDN -->
    <script src="https://unpkg.com/@grandeurcloud/apollo"></script>
    <!-- Add CSS styles -->
    <link rel="stylesheet" href="src/styles.css">
    </head>
    <!-- Body block of our page-->
    <body>
    <!-- The loader page, will be displayed while we will verify the user auth status -->
    <div class="page center" id="loader">
    <!-- We are using a svg -->
    <img src="src/loader.svg" class="loader" />
    </div>
    <!-- The login page of our app -->
    <div id="login" class="page center" style="display: none;">
    <!-- Card holds the form -->
    <div class="card">
    <!-- The form to get email and passwordfrom users -->
    <input type="email" name="email" id="email" placeholder="Email" />
    <input type="password" name="password" id="password" placeholder="Password" />
    <!-- Button to submit the form-->
    <button id="submitLogin">Login</button>
    </div>
    </div>
    <!-- The page to hold the tiles -->
    <div id="devices" class="page" style="display: none;">
    <!-- The header of the page -->
    <div class="header">
    <!-- Add title of the page -->
    <div>Paired Devices</div>
    <!-- Add logout icon -->
    <button id="logout" class="inline">Logout</button>
    </div>
    <!-- Holder for tiles -->
    <div class="tiles" id="tiles">
    <!-- Each div represents a tile -->
    <!--
    <div class="tile">
    <div class="inner">
    <div>Title</div>
    <img src="src/fan.svg" />
    </div>
    </div>
    -->
    </div>
    </div>
    <!-- Main script file -->
    <script src="main.js"></script>
    </body>
    </html>
    view raw
    index.html hosted with ❤ by GitHub
    /**
    * @file: main.js
    * Initialize the SDK and get
    * a reference to the project
    */
    var project = apollo.init("YOUR-API-KEY", "YOUR-ACCESS-KEY", "YOUR-ACCESS-TOKEN");
    /**
    * This function uses the sdk to validate
    * that if the user is authenticated or not
    */
    async function start() {
    /** Use sdk auth class to check auth status */
    var res = await project.auth().isAuthenticated();
    /** Then if the user isn't authorized then show the login screen */
    if (res.code === "AUTH-UNAUTHORIZED") {
    return displayLogin();
    }
    /** Display devices screen */
    displayDevices();
    }
    /** Listener on login form button to authenticate a user */
    document.getElementById("submitLogin").addEventListener("click", async () => {
    /** Get email and password from inputs */
    var email = document.getElementById("email").value;
    var password = document.getElementById("password").value;
    /** Display laoder */
    displayLoader();
    /** Use the sdk auth class to login the user */
    var res = await project.auth().login(email, password);
    /** If the operation was successful */
    if (res.code === "AUTH-ACCOUNT-LOGGEDIN") {
    /** Reset the login page */
    document.getElementById("email").value = "";
    document.getElementById("password").value = "";
    /** Display devices screen */
    return displayDevices();
    }
    /** otherwise display the login screen again */
    displayLogin();
    });
    /** Function to get devices list from server and populate the ui*/
    async function getDevicesList() {
    /** Use sdk devices class */
    var devices = await project.devices();
    var res = await devices.list();
    /** Variable to hold the ui */
    var content = "";
    /** Then loop over the devices list returned in response and populate the ui */
    res.devices.forEach(device => {
    /** Add tile to the ui */
    content += `
    <div class="tile" onclick="updateState('${device.deviceID}')">
    <div class="inner" id="${device.deviceID}" data-state="${device.parms.state}">
    <div>${device.name}</div>
    <img src="src/button-${device.parms.state? "on" : "off"}.svg" />
    </div>
    </div>
    `
    /** Then also subscribe to the state update event of the device */
    devices.device(device.deviceID).onParms( parms => {
    /** Update the tile color to represent that the device is on*/
    document.getElementById(device.deviceID).getElementsByTagName("img")[0].src = `src/button-${parms.state? "on" : "off"}.svg`;
    /** Update local attribute and store the latest state in it */
    document.getElementById(device.deviceID).setAttribute("data-state", parms.state);
    })
    });
    /** Assign content to ui */
    document.getElementById("tiles").innerHTML = content;
    }
    /** Function to update the state of a device */
    async function updateState(deviceID) {
    /** Create new state */
    var newState = document.getElementById(deviceID).getAttribute("data-state") === "1" ? 0 : 1;
    /** Use the devices class of sdk to report the upgrade */
    await project.devices().device(deviceID).setParms({
    state: newState
    });
    }
    /** Add event handler on logout icon */
    document.getElementById("logout").addEventListener("click", async () => {
    /** Show the loader */
    displayLoader();
    /** and use the auth class of sdk to logout the user */
    await project.auth().logout();
    /** Then call start again */
    start();
    });
    /** Function to show laoder screen */
    function displayLoader() {
    /** Display loader */
    document.getElementById("loader").style.display = "flex";
    /** Hide login screen */
    document.getElementById("login").style.display = "none";
    /** Hide devices screen */
    document.getElementById("devices").style.display = "none";
    }
    /** Function to show login screen */
    function displayLogin() {
    /** Hide loader */
    document.getElementById("loader").style.display = "none";
    /** Display login screen */
    document.getElementById("login").style.display = "flex";
    }
    /** Function to show devices screen */
    function displayDevices() {
    /** Hide loader */
    document.getElementById("loader").style.display = "none";
    /** Display devices screen */
    document.getElementById("devices").style.display = "flex";
    /** Get devices list */
    getDevicesList();
    }
    /** Start the app */
    start();


    عندما يتم تحميل التطبيق فإنه يعرض شاشة تسجيل الدخول. عندما يقوم المستخدم بإدخال بيانات اعتماد الحساب وتسجيل الدخول ، ينشئ التطبيق قناة الاتصال في الوقت الفعلي مع السحابة باستخدام مفتاح API ومفتاح الوصول والرمز المميز الذي حصلنا عليه في قسم "البدء". عند تسجيل الدخول ، يحصل التطبيق على قائمة بجميع الأجهزة المقترنة بحساب المستخدم هذا من السحابة. وعندما ينقر المستخدم على زر الجهاز ، يستدعي التطبيق وظيفة toggleLED المقابلة ويرسل طلبًا إلى السحابة لتحديث متغير الحالة إلى القيمة التي تم تبديلها.


    الخطوة 4: الاختبار محليًا

    ها نحن أخيرًا. دعونا نختبر ما قمنا ببنائه. لهذا الغرض ، أثناء وجودك في ssh في RPi لدينا وتم تنشيط بيئة مشروعنا ، نقوم بتشغيل ملف Hardware.py الخاص بنا بالأمر التالي:

    python hardware.py

    أجهزة بيثون

    نبدأ في رؤية الإخراج المباشر في المحطة أسفل قيادتنا. ولكن يتعين علينا تشغيل تطبيق الويب الخاص بنا لتبديل حالة جهاز RPi. لذلك نقوم بتشغيل خادم محلي مع Grandeur Cloud CLI. تساعدنا واجهة سطر الأوامر في الاختبار عن طريق تشغيل خادم محلي. ما عليك سوى تنزيله من npm (تحتاج إلى nodejs ، في الوقت الحالي). قم بتشغيل الأمر التالي في جهازك الطرفي:


    npm install grandeurcloud -g # تثبيت cli في جهاز الكمبيوتر الخاص بك

    ثم انتقل إلى دليل تطبيق الويب الخاص بك وقم بتشغيل الأوامر التالية في جهازك:

    npm install grandeurcloud -g     # Installs the cli in your computer

    يربط grandeurcloud init # Command دليلك بمشروعك

    وأخيرًا قم بتشغيل الخادم:

    grandeurcloud init     # Command associates your directory with your project
    grandeurcloud serve

    تم توثيق هذا جيدًا في البرنامج التعليمي الرسمي.

    هناك إجراء أمني. لا يمكنك إرسال البيانات من تطبيقك إلى السحابة إلا إذا أضفت نطاقك إلى القائمة البيضاء (العنوان الذي يظهر في شريط عنوان URL للمتصفح عند فتح التطبيق - http: // localhost: 8000/8001 إذا كنت تقوم بتشغيل أمر خدمة grandeurcloud) من لوحة التحكم السحابية. يمنع هذا جميع المصادر غير المحددة من الوصول إلى بيانات مشروع Cloud في حالة فقد مفتاح الوصول الخاص بك.

    هذا هو 💥. يمكنك الآن تسجيل الدخول إلى تطبيقك ، والنقر على زر التبديل بجهازك ، ومشاهدة مؤشر LED على RPi يتابعك في الوقت الفعلي.

    Woohoo تطبيق الويب الخاص بنا للتحكم في LED RPi الخاص بنا

    كود البرنامج