تحسين عمليات الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية وتأمينها

لمحة عن هذا الدرس التطبيقي حول الترميز
schedule50 دقيقة
subjectتاريخ التعديل الأخير: 20 نوفمبر 2024
account_circleتأليف موظف Google

تستخدِم عمليات الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية أنواع الأجهزة لإعلام "مساعد Google" بقواعد النحو التي يجب استخدامها مع جهاز معيّن. تحدِّد سمات الجهاز إمكانات نوع الجهاز. يكتسب الجهاز حالات كل سمة جهاز تمت إضافتها إلى عملية دمج.

dc8dce0dea87cd5c.png

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

بالإضافة إلى إمكانية التحكّم الأساسية التي يوفّرها النوع والصفات، تتضمّن Smart Home API ميزات إضافية لتحسين تجربة المستخدم. تقدّم الردود على الأخطاء ملاحظات مفصّلة من المستخدمين عندما لا تنجح النوايا. تؤدي ميزة "إثبات هوية المستخدم الثانوي" إلى توسيع نطاق هذه الردود وإضافة مستوى أمان إضافي إلى سمة الجهاز التي تختارها. من خلال إرسال ردود خطأ محدّدة إلى مجموعات التحدي الصادرة من "مساعد Google"، يمكن أن يتطلّب دمج السحابة الإلكترونية إلى السحابة الإلكترونية إذنًا إضافيًا لإكمال أحد الطلبات.

المتطلبات الأساسية

ما ستُنشئه

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

المُعطيات

  • كيفية إضافة سمتَي "الأوضاع" و"عناصر التحكّم" إلى عملية الدمج
  • كيفية الإبلاغ عن الأخطاء والاستثناءات
  • كيفية تطبيق إجراء ثانوي لإثبات هوية المستخدم

المتطلبات

2. الخطوات الأولى

تفعيل "عناصر التحكّم في النشاط"

لاستخدام "مساعد Google"، عليك مشاركة بيانات نشاط معيّنة مع Google. يحتاج "مساعد Google" إلى هذه البيانات لكي يعمل بشكلٍ سليم، ولكنّ شرط مشاركة البيانات ليس خاصًا بحزمة تطوير البرامج (SDK). لمشاركة هذه البيانات، عليك إنشاء حساب على Google إذا لم يكن لديك حساب. يمكنك استخدام أي حساب على Google، ولا يُشترط أن يكون حساب المطوِّر الخاص بك.

افتح صفحة "عناصر التحكّم في النشاط" لحساب Google الذي تريد استخدامه مع "مساعد Google".

تأكَّد من تفعيل مفاتيح التبديل التالية:

  • النشاط على الويب وفي التطبيقات: بالإضافة إلى ذلك، تأكَّد من وضع علامة في مربّع الاختيار تضمين سجلّ Chrome والأنشطة من المواقع الإلكترونية والتطبيقات والأجهزة التي تستخدم خدمات Google.
  • معلومات الجهاز
  • التفاعل الصوتي مع الجهاز

إنشاء مشروع دمج من السحابة الإلكترونية إلى السحابة الإلكترونية

  1. انتقِل إلى Play Console.
  2. انقر على إنشاء مشروع، وأدخِل اسمًا للمشروع، ثم انقر على إنشاء مشروع.

اسم المشروع

اختيار الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية

في صفحة المشروع الرئيسية في "وحدة تحكّم المطوّر"، اختَر إضافة عملية دمج من السحابة الإلكترونية إلى السحابة الإلكترونية ضمن من السحابة الإلكترونية إلى السحابة الإلكترونية.

إضافة عملية دمج من السحابة الإلكترونية إلى السحابة الإلكترونية

تثبيت Firebase CLI

ستسمح لك واجهة سطر أوامر Firebase (CLI) بعرض تطبيقات الويب محليًا ونشر تطبيق الويب في استضافة Firebase.

لتثبيت واجهة برمجة التطبيقات، شغِّل الأمر npm التالي من الوحدة الطرفية:

npm install -g firebase-tools

للتحقّق من تثبيت واجهة برمجة التطبيقات بشكل صحيح، يمكنك تنفيذ ما يلي:

firebase --version

فوِّض واجهة Firebase CLI باستخدام حسابك على Google من خلال تنفيذ:

firebase login

إنشاء مشروع على Firebase

  1. انتقِل إلى Firebase.
  2. انقر على إنشاء مشروع وأدخِل اسم مشروعك.
  3. ضَع علامة في مربّع الاختيار الخاص بالاتفاقية وانقر على متابعة. إذا لم يكن هناك مربّع اختيار للاتفاقية، يمكنك تخطّي هذه الخطوة.
    إنشاء مشروع Firebase
  4. بعد إنشاء مشروعك على Firebase، ابحث عن رقم تعريف المشروع. انتقِل إلى نظرة عامة على المشروع وانقر على رمز الإعدادات > إعدادات المشروع.
    فتح إعدادات المشروع
  5. يظهر مشروعك ضمن علامة التبويب عام.
    الإعدادات العامة للمشروع

تفعيل HomeGraph API

تتيح HomeGraph API تخزين الأجهزة وحالاتها وإجراء طلبات بحث عنها ضمن Home Graph الخاص بالمستخدم. لاستخدام واجهة برمجة التطبيقات هذه، عليك أولاً فتح وحدة تحكّم Google Cloud وتفعيل HomeGraph API.

في Google Cloud Console، احرص على اختيار المشروع الذي يتطابق مع "المهام". <firebase-project-id>. بعد ذلك، في شاشة "مكتبة واجهات برمجة التطبيقات" لواجهة برمجة التطبيقات HomeGraph API، انقر على تفعيل.

ee198858a6eac112.png

3- تشغيل التطبيق النموذجي

بعد إعداد بيئة التطوير، يمكنك نشر المشروع الأوّلي للتأكّد من ضبط كل الإعدادات بشكلٍ صحيح.

الحصول على رمز المصدر

انقر على الرابط التالي لتنزيل نموذج هذا الدليل التعليمي على جهاز التطوير:

...أو يمكنك استنساخ مستودع GitHub من سطر الأوامر:

git clone https://github.com/google-home/smarthome-traits.git

فكِّ ضغط ملف ZIP الذي تم تنزيله.

لمحة عن المشروع

يحتوي المشروع الأوّلي على الأدلة الفرعية التالية:

  • public: واجهة مستخدم أمامية للتحكّم بسهولة في حالة الغسالة الذكية ومراقبتها
  • functions: خدمة سحابة إلكترونية مُنفَّذة بالكامل تدير الغسالة الذكية باستخدام وظائف السحابة الإلكترونية لبرنامج Firebase و"قاعدة بيانات Firebase الآنية الاستجابة"

تتضمّن ميزة توفير المحتوى من السحابة الإلكترونية الوظائف التالية في index.js:

  • fakeauth: نقطة نهاية التفويض لربط الحساب
  • faketoken: نقطة نهاية الرمز المميّز لربط الحسابات
  • smarthome: نقطة نهاية تلبية طلبات المنزل الذكي
  • reportstate: يتمّ استدعاء Home Graph API عند تغيير حالة الجهاز.
  • requestsync: يتيح هذا الخيار تحديثات أجهزة المستخدمين بدون الحاجة إلى إعادة ربط الحساب.

الربط بمنصّة Firebase

انتقِل إلى الدليل washer-start، ثمّ أعدّ واجهة Firebase CLI مع مشروع الدمج:

cd washer-start
firebase use <firebase-project-id>

ضبط مشروع Firebase

ابدأ مشروعًا على Firebase.

firebase init

اختَر ميزات سطر الأوامر وقاعدة البيانات الآنية الاستجابة والدوالّ وميزة الاستضافة التي تتضمّن "استضافة Firebase".

? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then
 Enter to confirm your choices.
❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance
 ◯ Firestore: Configure security rules and indexes files for Firestore
 ◉ Functions: Configure a Cloud Functions directory and its files
 ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
 ◯ Hosting: Set up GitHub Action deploys
 ◯ Storage: Configure a security rules file for Cloud Storage
 ◯ Emulators: Set up local emulators for Firebase products
 ◯ Remote Config: Configure a template file for Remote Config
 ◯ Extensions: Set up an empty Extensions manifest

سيؤدي ذلك إلى بدء واجهات برمجة التطبيقات والميزات اللازمة لمشروعك.

ابدأ قاعدة بيانات Realtime Database عندما يُطلب منك ذلك. يمكنك استخدام الموقع الجغرافي التلقائي لمثيل قاعدة البيانات.

? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up?
Yes

? Please choose the location for your default Realtime Database instance:
us-central1

بما أنّك تستخدم رمز المشروع الأوّلي، اختَر الملف التلقائي لقواعد الأمان، وتأكَّد من عدم استبدال ملف قواعد قاعدة البيانات الحالي.

? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console?
No

إذا كنت بصدد إعادة بدء مشروعك، اختَر استبدال عندما يُطلب منك تحديد ما إذا كنت تريد بدء قاعدة بيانات أو استبدالها.

? Would you like to initialize a new codebase, or overwrite an existing one?
Overwrite

عند ضبط Functions، يجب استخدام الملفات التلقائية والتأكّد من عدم استبدال الملفَين الحاليَين index.js وpackage.json في نموذج المشروع.

? What language would you like to use to write Cloud Functions?
JavaScript

? Do you want to use ESLint to catch probable bugs and enforce style?
No

? File functions/package.json already exists. Overwrite?
No

? File functions/index.js already exists. Overwrite?
No

إذا كنت بصدد إعادة بدء مشروعك، اختَر لا عندما يُطلب منك تحديد ما إذا كنت تريد بدء أو استبدال functions/.gitignore.

? File functions/.gitignore already exists. Overwrite?
No
? Do you want to install dependencies with npm now?
Yes

أخيرًا، اضبط إعدادات الاستضافة لاستخدام دليل public في رمز المشروع، واستخدِم الملف الحالي index.html. اختَر لا عندما يُطلب منك استخدام ESLint.

? What do you want to use as your public directory?
public

? Configure as a single-page app (rewrite all urls to /index.html)?
Yes

? Set up automatic builds and deploys with GitHub?
No

? File public/index.html already exists. Overwrite?
 No

إذا تم تفعيل ESLint عن طريق الخطأ، تتوفّر طريقتان لإيقافه:

  1. باستخدام واجهة المستخدم الرسومية، انتقِل إلى مجلد ../functions ضمن المشروع، واختَر الملف المخفي .eslintrc.js واحذِفه. لا تخلط بينه وبين .eslintrc.json الذي يحمل اسمًا مشابهًا.
  2. باستخدام سطر الأوامر:
    cd functions
    rm .eslintrc.js
    

النشر على Firebase

بعد تثبيت التبعيات وضبط مشروعك، أصبحت جاهزًا لتشغيل التطبيق للمرّة الأولى.

firebase deploy

في ما يلي نتائج وحدة التحكّم التي من المفترض أن تظهر لك:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<firebase-project-id>/overview
Hosting URL: https://<firebase-project-id>.web.app

ينشر هذا الأمر تطبيق ويب، بالإضافة إلى العديد من وظائف السحابة الإلكترونية لبرنامج Firebase.

افتح عنوان URL للاستضافة في المتصفّح (https://<firebase-project-id>.web.app) لعرض تطبيق الويب. ستظهر لك الواجهة التالية:

5845443e94705557.png

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

حان الآن وقت ربط خدمة السحابة الإلكترونية التي تم نشرها بخدمة "مساعد Google" باستخدام وحدة تحكّم المطوّر.

ضبط مشروعك على Developer Console

في علامة التبويب تطوير، أضِف اسمًا معروضًا للتفاعل. سيظهر هذا الاسم في تطبيق Google Home.

إضافة اسم معروض

ضمن علامة التطبيق التجارية، حمِّل ملف png لرمز التطبيق بحجم 144 × 144 بكسل واسمه .png.

إضافة رمز تطبيق

لتفعيل ميزة ربط الحساب، استخدِم إعدادات ربط الحساب التالية:

معرِّف العميل

ABC123

سر العميل

DEF456

عنوان URL للترخيص

https://us-central1-
.cloudfunctions.net/fakeauth

عنوان URL للرمز المميّز

https://us-central1-
.cloudfunctions.net/faketoken

تعديل عناوين URL لربط الحساب

ضمن عنوان URL لتنفيذ الإجراءات في السحابة الإلكترونية، أدخِل عنوان URL لوظيفة السحابة الإلكترونية التي توفّر إجراءات تنفيذ طلبات المنزل الذكي.

https://us-central1--cloudfunctions.net/smarthome

إضافة عنوان URL للدالة السحابية

انقر على حفظ لحفظ إعدادات مشروعك، ثمّ انقر على التالي: اختبار لتفعيل الاختبار في مشروعك.

اختبار عملية الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية

يمكنك الآن البدء في تنفيذ وحدات ربط الويب اللازمة لربط حالة الجهاز بخدمة "مساعد Google".

لاختبار عملية الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية، عليك ربط مشروعك بحساب Google. يتيح ذلك إجراء الاختبار من خلال مساحات عرض "مساعد Google" وتطبيق Google Home اللذَين تم تسجيل الدخول إلى الحساب نفسه من خلالهما.

  1. على هاتفك، افتح إعدادات "مساعد Google". يُرجى العلم أنّه يجب تسجيل الدخول باستخدام الحساب نفسه المستخدَم في وحدة التحكّم.
  2. انتقِل إلى مساعد Google > الإعدادات > التحكّم في المنزل (ضمن "مساعد Google").
  3. انقر على رمز البحث في أعلى يسار الصفحة.
  4. ابحث عن تطبيقك التجريبي باستخدام البادئة [test] للعثور على تطبيقك التجريبي المحدّد.
  5. اختَر هذا العنصر. سيصلك بعد ذلك طلب من "مساعد Google" لإثبات هويتك من خلال خدمتك، وسيطلب من خدمتك تقديم قائمة بالأجهزة للمستخدم.SYNC

افتح تطبيق Google Home وتأكَّد من ظهور غسّالة الملابس.

ae252220753726f6.png

تأكَّد من أنّه يمكنك التحكّم في الغسالة باستخدام الطلبات الصوتية في تطبيق Google Home. من المفترض أيضًا أن تلاحظ تغيير حالة الجهاز في واجهة مستخدم الويب الأمامية لخدمة السحابة الإلكترونية.

بعد نشر غسّالة أساسية، يمكنك تخصيص الأوضاع المتاحة على جهازك.

4. إضافة أوضاع

تتيح السمة action.devices.traits.Modes للجهاز الحصول على عدد عشوائي من الإعدادات لأحد الأوضاع، ولا يمكن ضبط سوى إعداد واحد في كل مرة. ستضيف وضعًا إلى الغسالة لتحديد حجم حمولة الغسيل: صغير أو متوسط أو كبير.

تعديل استجابة SYNC

عليك إضافة معلومات عن السمة الجديدة إلى ردّك على SYNC في functions/index.js. تظهر هذه البيانات في صفيف traits وعنصر attributes كما هو موضّح في المقتطف البرمجي التالي.

index.js

app.onSync(body => {
 
return {
    requestId
: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    payload
: {
      agentUserId
: USER_ID,
      devices
: [{
        id
: 'washer',
        type
: 'action.devices.types.WASHER',
        traits
: [
         
'action.devices.traits.OnOff',
         
'action.devices.traits.StartStop',
         
'action.devices.traits.RunCycle',
         
// Add Modes trait
         
'action.devices.traits.Modes',
       
],
        name
: { ... },
        deviceInfo
: { ... },
        attributes
: {
          pausable
: true,
         
//Add availableModes
          availableModes
: [{
            name
: 'load',
            name_values
: [{
              name_synonym
: ['load'],
              lang
: 'en',
           
}],
            settings
: [{
              setting_name
: 'small',
              setting_values
: [{
                setting_synonym
: ['small'],
                lang
: 'en',
             
}]
           
}, {
              setting_name
: 'medium',
              setting_values
: [{
                setting_synonym
: ['medium'],
                lang
: 'en',
             
}]
           
}, {
              setting_name
: 'large',
              setting_values
: [{
                setting_synonym
: ['large'],
                lang
: 'en',
             
}]
           
}],
            ordered
: true,
         
}],
       
},
     
}],
   
},
 
};
});

إضافة أوامر جديدة لطلب التنفيذ

في نية EXECUTE، أضِف الأمر action.devices.commands.SetModes كما هو موضّح في مقتطف التعليمة البرمجية التالي.

index.js

const updateDevice = async (execution,deviceId) => {
 
const {params,command} = execution;
  let state
, ref;
 
switch (command) {
   
case 'action.devices.commands.OnOff':
      state
= {on: params.on};
     
ref = firebaseRef.child(deviceId).child('OnOff');
     
break;
   
case 'action.devices.commands.StartStop':
      state
= {isRunning: params.start};
     
ref = firebaseRef.child(deviceId).child('StartStop');
     
break;
   
case 'action.devices.commands.PauseUnpause':
      state
= {isPaused: params.pause};
     
ref = firebaseRef.child(deviceId).child('StartStop');
     
Break;
   
// Add SetModes command
   
case 'action.devices.commands.SetModes':
      state
= {load: params.updateModeSettings.load};
     
ref = firebaseRef.child(deviceId).child('Modes');
     
break;
}

تعديل استجابة QUERY

بعد ذلك، عدِّل ردّك على QUERY للإبلاغ عن الحالة الحالية للغسالة.

أضِف التغييرات المعدَّلة إلى الدالتَين queryFirebase وqueryDevice للحصول على الحالة كما تم تخزينها في "قاعدة بيانات في الوقت الفعلي".

index.js

const queryFirebase = async (deviceId) => {
 
const snapshot = await firebaseRef.child(deviceId).once('value');
 
const snapshotVal = snapshot.val();
 
return {
    on
: snapshotVal.OnOff.on,
    isPaused
: snapshotVal.StartStop.isPaused,
    isRunning
: snapshotVal.StartStop.isRunning,
   
// Add Modes snapshot
    load
: snapshotVal.Modes.load,
 
};
}

const queryDevice = async (deviceId) => {
 
const data = await queryFirebase(deviceId);
 
return {
    on
: data.on,
    isPaused
: data.isPaused,
    isRunning
: data.isRunning,
    currentRunCycle
: [{ ... }],
    currentTotalRemainingTime
: 1212,
    currentCycleRemainingTime
: 301,
   
// Add currentModeSettings
    currentModeSettings
: {
      load
: data.load,
   
},
 
};
};

تعديل حالة التقرير

أخيرًا، عدِّل دالة reportstate للإبلاغ عن إعداد الحمولة الحالي للغسالة في "الرسم البياني للمنزل".

index.js

const requestBody = {
  requestId
: 'ff36a3cc', /* Any unique ID */
  agentUserId
: USER_ID,
  payload
: {
    devices
: {
      states
: {
       
/* Report the current state of your washer */
       
[context.params.deviceId]: {
          on
: snapshot.OnOff.on,
          isPaused
: snapshot.StartStop.isPaused,
          isRunning
: snapshot.StartStop.isRunning,
         
// Add currentModeSettings
          currentModeSettings
: {
            load
: snapshot.Modes.load,
         
},
       
},
     
},
   
},
 
},
};

النشر على Firebase

شغِّل الأمر التالي لنشر عملية الدمج المعدَّلة:

firebase deploy --only functions

بعد اكتمال عملية النشر، انتقِل إلى واجهة مستخدم الويب وانقر على الزر إعادة تحميل ae8d3b25777a5e30.png في شريط الأدوات. يؤدي ذلك إلى بدء عملية مزامنة الطلبات كي يتلقّى "مساعد Google" بيانات ردّ SYNC المعدَّلة.

bf4f6a866160a982.png

يمكنك الآن توجيه طلب لضبط وضع الغسالة، مثل:

"Ok Google، أريد ضبط حمولة الغسالة على "كبيرة"."

بالإضافة إلى ذلك، يمكنك طرح أسئلة حول غسالتك، مثل:

"Ok Google، ما هو حجم الحمولة في الغسالة؟"

5- إضافة مفاتيح تبديل

تمثّل السمة action.devices.traits.Toggles جوانب مُسمّاة للجهاز لها حالة صحيحة أو خطأ، مثل ما إذا كانت الغسالة في وضع Turbo.

تعديل استجابة SYNC

في ردّك على SYNC، عليك إضافة معلومات عن سمة الجهاز الجديدة. وسيظهر في صفيف traits وعنصر attributes كما هو موضّح في المقتطف التالي من الرمز البرمجي.

index.js

app.onSync(body => {
 
return {
    requestId
: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    payload
: {
      agentUserId
: USER_ID,
      devices
: [{
        id
: 'washer',
        type
: 'action.devices.types.WASHER',
        traits
: [
         
'action.devices.traits.OnOff',
         
'action.devices.traits.StartStop',
         
'action.devices.traits.RunCycle',
         
'action.devices.traits.Modes',
         
// Add Toggles trait
         
'action.devices.traits.Toggles',
       
],
        name
: { ... },
        deviceInfo
: { ... },
        attributes
: {
          pausable
: true,
          availableModes
: [{
            name
: 'load',
            name_values
: [{
              name_synonym
: ['load'],
              lang
: 'en'
           
}],
            settings
: [{ ... }],
            ordered
: true,
         
}],
         
//Add availableToggles
          availableToggles
: [{
            name
: 'Turbo',
            name_values
: [{
              name_synonym
: ['turbo'],
              lang
: 'en',
           
}],
         
}],
       
},
     
}],
   
},
 
};
});

إضافة أوامر تنفيذ جديدة

في نية EXECUTE، أضِف الأمر action.devices.commands.SetToggles كما هو موضّح في مقتطف التعليمة البرمجية التالي.

index.js

const updateDevice = async (execution,deviceId) => {
 
const {params,command} = execution;
  let state
, ref;
 
switch (command) {
   
case 'action.devices.commands.OnOff':
      state
= {on: params.on};
     
ref = firebaseRef.child(deviceId).child('OnOff');
     
break;
   
case 'action.devices.commands.StartStop':
      state
= {isRunning: params.start};
     
ref = firebaseRef.child(deviceId).child('StartStop');
     
break;
   
case 'action.devices.commands.PauseUnpause':
      state
= {isPaused: params.pause};
     
ref = firebaseRef.child(deviceId).child('StartStop');
     
break;
   
case 'action.devices.commands.SetModes':
      state
= {load: params.updateModeSettings.load};
     
ref = firebaseRef.child(deviceId).child('Modes');
     
break;
   
// Add SetToggles command
   
case 'action.devices.commands.SetToggles':
      state
= {Turbo: params.updateToggleSettings.Turbo};
     
ref = firebaseRef.child(deviceId).child('Toggles');
     
break;
 
}

تعديل استجابة QUERY

أخيرًا، عليك تعديل ردّك على QUERY للإبلاغ عن وضع الغسيل السريع في الغسالة. أضِف التغييرات المعدَّلة إلى الدالتَين queryFirebase وqueryDevice للحصول على حالة التبديل كما تم تخزينها في "قاعدة بيانات الوقت الفعلي".

index.js

const queryFirebase = async (deviceId) => {
 
const snapshot = await firebaseRef.child(deviceId).once('value');
 
const snapshotVal = snapshot.val();
 
return {
    on
: snapshotVal.OnOff.on,
    isPaused
: snapshotVal.StartStop.isPaused,
    isRunning
: snapshotVal.StartStop.isRunning,
    load
: snapshotVal.Modes.load,
   
// Add Toggles snapshot
   
Turbo: snapshotVal.Toggles.Turbo,
 
};
}

const queryDevice = async (deviceId) => {
 
const data = queryFirebase(deviceId);
 
return {
    on
: data.on,
    isPaused
: data.isPaused,
    isRunning
: data.isRunning,
    currentRunCycle
: [{ ... }],
    currentTotalRemainingTime
: 1212,
    currentCycleRemainingTime
: 301,
    currentModeSettings
: {
      load
: data.load,
   
},
   
// Add currentToggleSettings
    currentToggleSettings
: {
     
Turbo: data.Turbo,
   
},
 
};
};

تعديل حالة التقرير

أخيرًا، عدِّل دالة reportstate للإبلاغ إلى "رسم بياني للمنزل" عمّا إذا تم ضبط الغسالة على وضع "التربو".

index.js

const requestBody = {
  requestId
: 'ff36a3cc', /* Any unique ID */
  agentUserId
: USER_ID,
  payload
: {
    devices
: {
      states
: {
       
/* Report the current state of your washer */
       
[context.params.deviceId]: {
          on
: snapshot.OnOff.on,
          isPaused
: snapshot.StartStop.isPaused,
          isRunning
: snapshot.StartStop.isRunning,
          currentModeSettings
: {
            load
: snapshot.Modes.load,
         
},
         
// Add currentToggleSettings
          currentToggleSettings
: {
           
Turbo: snapshot.Toggles.Turbo,
         
},
       
},
     
},
   
},
 
},
};

النشر على Firebase

شغِّل الأمر التالي لنشر الدوالّ المعدَّلة:

firebase deploy --only functions

انقر على الزر إعادة تحميل ae8d3b25777a5e30.png في واجهة مستخدم الويب لبدء مزامنة الطلبات بعد اكتمال عملية النشر.

يمكنك الآن توجيه أمر لضبط الغسالة على وضع "التربو" من خلال قول:

"Ok Google، أريد تفعيل وضع Turbo في الغسالة".

يمكنك أيضًا التحقّق ممّا إذا كانت الغسّالة في وضع "التوربو" من خلال طرح الأسئلة التالية:

"Ok Google، هل الغسالة في وضع Turbo؟"

6- الإبلاغ عن الأخطاء والاستثناءات

تتيح لك معالجة الأخطاء في عملية الدمج من السحابة إلى السحابة الإبلاغ للمستخدمين عندما تؤدي المشاكل إلى تعذُّر تلقّي ردود EXECUTE وQUERY. توفّر الإشعارات تجربة إيجابية أكثر للمستخدمين عند تفاعلهم مع جهازك الذكي وعملية الدمج.

في حال تعذّر إرسال طلب EXECUTE أو QUERY، من المفترض أن يعرض عملية الدمج رمز خطأ. على سبيل المثال، إذا أردت عرض خطأ عندما يحاول المستخدم تشغيل الغسالة مع فتح الغطاء، سيظهر ردّ EXECUTE على النحو التالي:

{
 
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
 
"payload": {
   
"commands": [
     
{
       
"ids": [
         
"456"
       
],
       
"status": "ERROR",
       
"errorCode": "deviceLidOpen"
     
}
   
]
 
}
}

الآن، عندما يطلب أحد المستخدمين تشغيل الغسالة، يردّ "مساعد Google" بالقول:

"غطاء الغسالة مفتوح. يُرجى إغلاق التطبيق وإعادة المحاولة."

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

في مقتطف الرمز البرمجي التالي، يمكنك الاطّلاع على مثال على استجابة تتضمّن استثناءً:

{
 
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
 
"payload": {
   
"commands": [{
     
"ids": ["123"],
     
"status": "SUCCESS",
     
"states": {
       
"online": true,
       
"isPaused": false,
       
"isRunning": false,
       
"exceptionCode": "runCycleFinished"
     
}
   
}]
 
}
}

يردّ "مساعد Google" بالقول:

"انتهى وقت تشغيل الغسالة"

لإضافة ميزة الإبلاغ عن الأخطاء في غسّالتك، افتح functions/index.js وأضِف تعريف فئة الخطأ كما هو موضّح في المقتطف التالي من الرمز البرمجي:

index.js

app.onQuery(async (body) => {...});

// Add SmartHome error handling
class SmartHomeError extends Error {
  constructor
(errorCode, message) {
   
super(message);
   
this.name = this.constructor.name;
   
this.errorCode = errorCode;
 
}
}

عدِّل استجابة التنفيذ لعرض رمز الخطأ وحالة الخطأ:

index.js

const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
 
for (const device of command.devices) {
   
for (const execution of command.execution) {
      executePromises
.push(
        updateDevice
(execution, device.id)
       
.then((data) => {
         
...
       
})
       
//Add error response handling
       
.catch((error) => {
          functions
.logger.error('EXECUTE', device.id, error);
          result
.ids.push(device.id);
         
if (error instanceof SmartHomeError) {
            result
.status = 'ERROR';
            result
.errorCode = error.errorCode;
         
}
       
})
     
);
   
}
 
}
}

يمكن الآن لـ "مساعد Google" إبلاغ المستخدمين بأي رمز خطأ تُبلغ عنه. سيظهر لك مثال محدّد في القسم التالي.

7- إضافة إجراء ثانوي لإثبات هوية المستخدم

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

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

هناك ثلاثة أنواع من طلبات التحقّق المتاحة:

  • No challenge: طلب واستجابة لا يستخدمان طلب مصادقة (هذا هو السلوك التلقائي)
  • ackNeeded: إجراء ثانوي لإثبات هوية المستخدم يتطلّب تأكيدًا صريحًا (نعم أو لا)
  • pinNeeded: إثبات هوية المستخدم الثانوي الذي يتطلّب رقم تعريف شخصي (PIN)

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

افتح functions/index.js وأضِف تعريفًا لفئة الأخطاء يعرض رمز الخطأ ونوع الطلب كما هو موضّح في مقتطف الرمز البرمجي التالي:

index.js

class SmartHomeError extends Error { ... }

// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
 
/**
   * Create a new ChallengeNeededError
   * @param {string} suvType secondary user verification challenge type
   */

  constructor
(suvType) {
   
super('challengeNeeded', suvType);
   
this.suvType = suvType;
 
}
}

عليك أيضًا تعديل استجابة التنفيذ لعرض الخطأ challengeNeeded على النحو التالي:

index.js

const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
 
for (const device of command.devices) {
   
for (const execution of command.execution) {
      executePromises
.push(

        updateDevice
(execution, device.id)
       
.then((data) => {
         
...
       
})
       
.catch((error) => {
          functions
.logger.error('EXECUTE', device.id, error);
          result
.ids.push(device.id);
         
if (error instanceof SmartHomeError) {
            result
.status = 'ERROR';
            result
.errorCode = error.errorCode;
           
//Add error response handling
           
if (error instanceof ChallengeNeededError) {
              result
.challengeNeeded = {
                type
: error.suvType
             
};
           
}
         
}
       
})
     
);
   
}
 
}
}

أخيرًا، عدِّل updateDevice لطلب تأكيد صريح لتفعيل الغسالة أو إيقافها.

index.js

const updateDevice = async (execution,deviceId) => {
 
const {challenge,params,command} = execution; //Add secondary user challenge
  let state
, ref;
 
switch (command) {
   
case 'action.devices.commands.OnOff':
     
//Add secondary user verification challenge
     
if (!challenge || !challenge.ack) {
       
throw new ChallengeNeededError('ackNeeded');
     
}
      state
= {on: params.on};
     
ref = firebaseRef.child(deviceId).child('OnOff');
     
break;
   
...
 
}

 
return ref.update(state)
     
.then(() => state);
};

النشر على Firebase

شغِّل الأمر التالي لنشر الدالة المعدَّلة:

firebase deploy --only functions

بعد نشر الرمز المعدَّل، عليك تأكيد الإجراء شفهيًا عند طلب تشغيل الغسالة أو إيقافها من خلال "مساعد Google"، على النحو التالي:

أنت: "Ok Google، أريد تشغيل الغسالة".

مساعد Google: "هل أنت متأكّد من أنّك تريد تشغيل الغسالة؟"

أنت: "نعم".

يمكنك أيضًا الاطّلاع على ردّ تفصيلي لكل خطوة من خطوات عملية إثبات هوية المستخدم الثانوي من خلال فتح سجلّات Firebase.

289dbe48f4bb8106.png

8. تهانينا

674c4f4392e98c1.png

تهانينا! لقد وسّعت ميزات عمليات الدمج من السحابة الإلكترونية إلى السحابة الإلكترونية من خلال سمتَي Modes وToggles، وأمنّت تنفيذها من خلال إثبات ملكية المستخدم الثانوي.

مزيد من المعلومات

في ما يلي بعض الأفكار التي يمكنك تنفيذها للتوغّل أكثر في الموضوع:

  • إضافة إمكانات التنفيذ على الجهاز إلى أجهزتك
  • استخدِم نوعًا مختلفًا من تحدّيات التحقّق الثانوي من المستخدم لتعديل حالة جهازك.
  • عدِّل استجابة RunCycle QUERY للسمة من أجل التعديل بشكل ديناميكي.
  • اطّلِع على نموذج GitHub هذا.