Android पर Home API का इस्तेमाल करके ऑटोमेशन बनाना

1. शुरू करने से पहले

यह Google Home API का इस्तेमाल करके Android ऐप्लिकेशन बनाने के बारे में सीरीज़ का दूसरा कोडलैब है. इस कोडलैब में, हम आपको घर के ऑटोमेशन बनाने का तरीका बताएंगे. साथ ही, एपीआई इस्तेमाल करने के सबसे सही तरीकों के बारे में कुछ सुझाव देंगे. अगर आपने अब तक पहला कोडलैब, Android पर Home API का इस्तेमाल करके मोबाइल ऐप्लिकेशन बनाना पूरा नहीं किया है, तो हमारा सुझाव है कि आप इस कोडलैब को शुरू करने से पहले उसे पूरा कर लें.

Google Home API, Android डेवलपर के लिए लाइब्रेरी का एक सेट उपलब्ध कराते हैं. इनकी मदद से, Google Home के इकोसिस्टम में मौजूद स्मार्ट होम डिवाइसों को कंट्रोल किया जा सकता है. इन नए एपीआई की मदद से, डेवलपर स्मार्ट होम के लिए ऑटोमेशन सेट कर पाएंगे. इससे पहले से तय की गई शर्तों के आधार पर, डिवाइस की सुविधाओं को कंट्रोल किया जा सकेगा. Google, Discovery API भी उपलब्ध कराता है. इसकी मदद से, डिवाइसों से क्वेरी की जा सकती है. इससे यह पता चलता है कि डिवाइस किन एट्रिब्यूट और कमांड के साथ काम करते हैं.

ज़रूरी शर्तें

आपको क्या सीखने को मिलेगा

  • Home API का इस्तेमाल करके, स्मार्ट होम डिवाइसों के लिए ऑटोमेशन बनाने का तरीका.
  • डिवाइस की सुविधाओं के बारे में जानने के लिए, Discovery API का इस्तेमाल कैसे करें.
  • Home API की मदद से ऐप्लिकेशन बनाते समय, सबसे सही तरीकों का इस्तेमाल कैसे करें.

2. प्रोजेक्ट सेट अप करना

इस डायग्राम में, Home APIs ऐप्लिकेशन का आर्किटेक्चर दिखाया गया है:

Android ऐप्लिकेशन के लिए Home API का आर्किटेक्चर

  • ऐप्लिकेशन कोड: यह वह कोड होता है जिस पर डेवलपर काम करते हैं. इसकी मदद से, ऐप्लिकेशन का यूज़र इंटरफ़ेस बनाया जाता है. साथ ही, Home APIs SDK के साथ इंटरैक्ट करने के लिए लॉजिक तैयार किया जाता है.
  • Home APIs SDK: Google की ओर से उपलब्ध कराया गया Home APIs SDK, GMSCore में मौजूद Home APIs Service के साथ काम करता है. इससे स्मार्ट होम डिवाइसों को कंट्रोल किया जा सकता है. डेवलपर, Home APIs SDK को Home APIs के साथ बंडल करके, ऐसे ऐप्लिकेशन बनाते हैं जो Home APIs के साथ काम करते हैं.
  • Android पर GMSCore: GMSCore को Google Play services के नाम से भी जाना जाता है. यह Google का एक प्लैटफ़ॉर्म है, जो सिस्टम से जुड़ी मुख्य सेवाएं उपलब्ध कराता है. इससे, सर्टिफ़ाइड Android डिवाइसों के सभी मुख्य फ़ंक्शन सही ढंग से काम करते हैं. Google Play services के होम मॉड्यूल में, ऐसी सेवाएं शामिल होती हैं जो Home API के साथ इंटरैक्ट करती हैं.

इस कोडलैब में, हम Android पर Home API का इस्तेमाल करके मोबाइल ऐप्लिकेशन बनाना में बताई गई बातों को आगे बढ़ाएंगे.

पक्का करें कि आपके पास कम से कम दो ऐसे डिवाइसों वाला स्ट्रक्चर हो जो खाते के साथ काम करते हों और सेट अप किए गए हों. इस कोडलैब में हम ऑटोमेशन सेट अप करने जा रहे हैं. इसका मतलब है कि एक डिवाइस की स्थिति में बदलाव होने पर, दूसरे डिवाइस पर कोई कार्रवाई ट्रिगर होगी. इसलिए, आपको नतीजे देखने के लिए दो डिवाइसों की ज़रूरत होगी.

नमूना ऐप्लिकेशन डाउनलोड करना

सैंपल ऐप्लिकेशन का सोर्स कोड, GitHub पर google-home/google-home-api-sample-app-android रिपॉज़िटरी में उपलब्ध है.

यह कोडलैब, सैंपल ऐप्लिकेशन की codelab-branch-2 ब्रांच के उदाहरणों का इस्तेमाल करता है.

उस जगह पर जाएं जहां आपको प्रोजेक्ट सेव करना है और codelab-branch-2 ब्रांच को क्लोन करें:

$ git clone -b codelab-branch-2 https://github.com/google-home/google-home-api-sample-app-android.git

ध्यान दें कि यह Android पर Home API का इस्तेमाल करके मोबाइल ऐप्लिकेशन बनाना में इस्तेमाल की गई ब्रांच से अलग है. कोडबेस की यह ब्रांच, पहले कोडलैब के बाद से शुरू होती है. इस बार, उदाहरणों में आपको ऑटोमेशन बनाने का तरीका बताया गया है. अगर आपने पिछला कोडलैब पूरा कर लिया है और सभी सुविधाएं काम कर रही हैं, तो इस कोडलैब को पूरा करने के लिए, codelab-branch-2 का इस्तेमाल करने के बजाय, उसी Android Studio प्रोजेक्ट का इस्तेमाल किया जा सकता है.

जब आपके पास सोर्स कोड कंपाइल हो जाए और वह आपके मोबाइल डिवाइस पर चलने के लिए तैयार हो जाए, तो अगले सेक्शन पर जाएं.

3. ऑटोमेशन के बारे में जानकारी

ऑटोमेशन, "अगर ऐसा है, तो ऐसा करो" स्टेटमेंट का एक सेट होता है. यह चुने गए फ़ैक्टर के आधार पर, डिवाइस की स्थितियों को अपने-आप कंट्रोल कर सकता है. डेवलपर, ऑटोमेशन का इस्तेमाल करके अपने एपीआई में बेहतर इंटरैक्टिव सुविधाएं बना सकते हैं.

ऑटोमेशन में तीन तरह के कॉम्पोनेंट होते हैं. इन्हें नोड कहा जाता है: स्टार्टर, ऐक्शन, और शर्तें. ये नोड, स्मार्ट होम डिवाइसों का इस्तेमाल करके, व्यवहारों को अपने-आप करने के लिए एक साथ काम करते हैं. आम तौर पर, इनका आकलन इस क्रम में किया जाता है:

  1. स्टार्टर — यह उन शुरुआती शर्तों के बारे में बताता है जिनकी वजह से ऑटोमेशन शुरू होता है. जैसे, किसी एट्रिब्यूट की वैल्यू में बदलाव होना. किसी भी ऑटोमेशन में स्टार्टर होना ज़रूरी है.
  2. शर्त — ऑटोमेशन ट्रिगर होने के बाद, आकलन करने के लिए कोई भी अतिरिक्त शर्त. ऑटोमेशन की कार्रवाइयों को लागू करने के लिए, शर्त में मौजूद एक्सप्रेशन का आकलन 'सही' के तौर पर होना चाहिए.
  3. कार्रवाई — सभी शर्तें पूरी होने पर की जाने वाली कार्रवाइयां या अपडेट.

उदाहरण के लिए, आपके पास ऐसा ऑटोमेशन सेट करने का विकल्प होता है कि जब कमरे में टीवी चालू हो, तब स्विच को टॉगल करने पर कमरे की लाइटें अपने-आप धीमी हो जाएं. इस उदाहरण में:

  • Starter — कमरे में मौजूद स्विच को टॉगल किया जाता है.
  • शर्त— टीवी के चालू/बंद होने की स्थिति का आकलन किया जाता है.
  • कार्रवाई — स्विच वाले कमरे की लाइटें धीमी हो जाती हैं.

इन नोड का आकलन, ऑटोमेशन इंजन करता है. यह आकलन, क्रमवार या समानांतर तरीके से किया जाता है.

image5.png

सीक्वेंशियल फ़्लो में ऐसे नोड होते हैं जो क्रम से काम करते हैं. आम तौर पर, ये स्टार्टर, शर्त, और कार्रवाई होती हैं.

image6.png

पैरलल फ़्लो में एक साथ कई ऐक्शन नोड काम कर सकते हैं. जैसे, एक साथ कई लाइटें चालू करना. पैरलल फ़्लो को फ़ॉलो करने वाले नोड, तब तक एक्ज़ीक्यूट नहीं होंगे, जब तक पैरलल फ़्लो की सभी शाखाएं पूरी नहीं हो जातीं.

ऑटोमेशन स्कीमा में अन्य तरह के नोड भी होते हैं. इनके बारे में ज़्यादा जानने के लिए, Home APIs की डेवलपर गाइड के नोड सेक्शन पर जाएं. इसके अलावा, डेवलपर अलग-अलग तरह के नोड को मिलाकर, जटिल ऑटोमेशन बना सकते हैं. जैसे:

image13.png

डेवलपर, इन नोड को ऑटोमेशन इंजन को उपलब्ध कराते हैं. इसके लिए, वे खास तौर पर Google Home के ऑटोमेशन के लिए बनाई गई डोमेन-स्पेसिफ़िक लैंग्वेज (डीएसएल) का इस्तेमाल करते हैं.

ऑटोमेशन डीएसएल के बारे में जानें

डोमेन के हिसाब से बनाई गई लैंग्वेज (डीएसएल) एक ऐसी लैंग्वेज होती है जिसका इस्तेमाल, कोड में सिस्टम के व्यवहार को कैप्चर करने के लिए किया जाता है. कंपाइलर, डेटा क्लास जनरेट करता है. इन्हें प्रोटोकॉल बफ़र JSON में क्रम से लगाया जाता है. इनका इस्तेमाल, Google की ऑटोमेशन सेवाओं को कॉल करने के लिए किया जाता है.

डीएसएल, इस स्कीमा को खोजता है:

automation {
name = "AutomationName"
  description = "An example automation description."
  isActive = true
    sequential {
    val onOffTrait = starter<_>(device1, OnOffLightDevice, OnOff)
    condition() { expression = onOffTrait.onOff equals true }
    action(device2, OnOffLightDevice) { command(OnOff.on()) }
  }
}

ऊपर दिए गए उदाहरण में, ऑटोमेशन की मदद से दो लाइट बल्ब सिंक किए गए हैं. जब device1 का OnOff स्टेटस बदलकर On (onOffTrait.onOff equals true) हो जाता है, तब device2 का OnOff स्टेटस बदलकर On (command(OnOff.on()) हो जाता है.

ऑटोमेशन का इस्तेमाल करते समय, ध्यान रखें कि संसाधन की सीमाएं होती हैं.

ऑटोमेशन, स्मार्ट होम में ऑटोमेटेड सुविधाएं बनाने के लिए एक बहुत ही उपयोगी टूल है. सबसे बुनियादी इस्तेमाल के मामले में, किसी ऑटोमेशन को खास डिवाइसों और सुविधाओं का इस्तेमाल करने के लिए कोड किया जा सकता है. हालांकि, इसका ज़्यादातर इस्तेमाल ऐसे मामलों में होता है जहां ऐप्लिकेशन, उपयोगकर्ता को ऑटोमेशन के डिवाइसों, कमांड, और पैरामीटर को कॉन्फ़िगर करने की सुविधा देता है. अगले सेक्शन में, ऐसा ऑटोमेशन एडिटर बनाने का तरीका बताया गया है जिससे उपयोगकर्ता को ये काम करने की सुविधा मिलती है.

4. ऑटोमेशन एडिटर बनाना

हम सैंपल ऐप्लिकेशन में एक ऑटोमेशन एडिटर बनाएंगे. इसकी मदद से उपयोगकर्ता, डिवाइसों और उन सुविधाओं (कार्रवाइयों) को चुन सकते हैं जिनका उन्हें इस्तेमाल करना है. साथ ही, वे यह भी चुन सकते हैं कि स्टार्टर का इस्तेमाल करके ऑटोमेशन कैसे ट्रिगर किए जाएं.

img11-01.png img11-02.png img11-03.png img11-04.png

स्टार्टर सेट अप करना

ऑटोमेशन स्टार्टर, ऑटोमेशन के लिए एंट्री पॉइंट होता है. किसी इवेंट के होने पर, स्टार्टर ऑटोमेशन को ट्रिगर करता है. सैंपल ऐप्लिकेशन में, हम StarterViewModel क्लास का इस्तेमाल करके ऑटोमेशन स्टार्टर कैप्चर करते हैं. यह StarterViewModel.kt सोर्स फ़ाइल में मौजूद होता है. साथ ही, हम StarterView (StarterView.kt) का इस्तेमाल करके एडिटर व्यू दिखाते हैं.

स्टार्टर नोड में ये एलिमेंट होने चाहिए:

  • डिवाइस
  • विशेषता
  • कार्रवाई
  • मान

डिवाइस और ट्रेट को Devices API से मिले ऑब्जेक्ट में से चुना जा सकता है. हर डिवाइस के लिए कमांड और पैरामीटर काफ़ी जटिल होते हैं. इसलिए, इन्हें अलग से मैनेज करना होता है.

ऐप्लिकेशन में, पहले से तय की गई कार्रवाइयों की सूची तय की जाती है:

   // List of operations available when creating automation starters:
enum class Operation {
  EQUALS,
  NOT_EQUALS,
  GREATER_THAN,
  GREATER_THAN_OR_EQUALS,
  LESS_THAN,
  LESS_THAN_OR_EQUALS
    }

इसके बाद, हर ट्रेट के लिए, इन कार्रवाइयों को ट्रैक करता है:

// List of operations available when comparing booleans:
 object BooleanOperations : Operations(listOf(
     Operation.EQUALS,
     Operation.NOT_EQUALS
 ))
// List of operations available when comparing values:
object LevelOperations : Operations(listOf(
    Operation.GREATER_THAN,
    Operation.GREATER_THAN_OR_EQUALS,
    Operation.LESS_THAN,
    Operation.LESS_THAN_OR_EQUALS
))

इसी तरह, सैंपल ऐप्लिकेशन, ट्रेट को असाइन की जा सकने वाली वैल्यू को ट्रैक करता है:

enum class OnOffValue {
   On,
   Off,
}
enum class ThermostatValue {
  Heat,
  Cool,
  Off,
}

साथ ही, यह ऐप्लिकेशन और एपीआई के ज़रिए तय की गई वैल्यू के बीच मैपिंग को ट्रैक करता है:

val valuesOnOff: Map<OnOffValue, Boolean> = mapOf(
  OnOffValue.On to true,
  OnOffValue.Off to false,
)
val valuesThermostat: Map<ThermostatValue, ThermostatTrait.SystemModeEnum> = mapOf(
  ThermostatValue.Heat to ThermostatTrait.SystemModeEnum.Heat,
  ThermostatValue.Cool to ThermostatTrait.SystemModeEnum.Cool,
  ThermostatValue.Off to ThermostatTrait.SystemModeEnum.Off,
)

इसके बाद, ऐप्लिकेशन व्यू एलिमेंट का एक सेट दिखाता है. उपयोगकर्ता इनका इस्तेमाल करके, ज़रूरी फ़ील्ड चुन सकते हैं.

सभी स्टार्टर डिवाइसों को रेंडर करने और DropdownMenu में क्लिक कॉलबैक लागू करने के लिए, StarterView.kt फ़ाइल में चरण 4.1.1 से टिप्पणी हटाएं:

val deviceVMs: List<DeviceViewModel> = structureVM.deviceVMs.collectAsState().value
...
DropdownMenu(expanded = expandedDeviceSelection, onDismissRequest = { expandedDeviceSelection = false }) {
// TODO: 4.1.1 - Starter device selection dropdown
// for (deviceVM in deviceVMs) {
//     DropdownMenuItem(
//         text = { Text(deviceVM.name) },
//         onClick = {
//             scope.launch {
//                 starterDeviceVM.value = deviceVM
//                 starterType.value = deviceVM.type.value
//                 starterTrait.value = null
//                 starterOperation.value = null
//             }
//             expandedDeviceSelection = false
//         }
//     )
// }
}

स्टार्टर डिवाइस की सभी विशेषताओं को रेंडर करने के लिए, StarterView.kt फ़ाइल में चरण 4.1.2 से टिप्पणी हटाएं. साथ ही, DropdownMenu में क्लिक कॉलबैक लागू करें:

// Selected starter attributes for StarterView on screen:
val starterDeviceVM: MutableState<DeviceViewModel?> = remember {
mutableStateOf(starterVM.deviceVM.value) }
...
DropdownMenu(expanded = expandedTraitSelection, onDismissRequest = { expandedTraitSelection = false }) {
// TODO: 4.1.2 - Starter device traits selection dropdown
// val deviceTraits = starterDeviceVM.value?.traits?.collectAsState()?.value!!
// for (trait in deviceTraits) {
//     DropdownMenuItem(
//         text = { Text(trait.factory.toString()) },
//         onClick = {
//             scope.launch {
//                 starterTrait.value = trait.factory
//                 starterOperation.value = null
//             }
//             expandedTraitSelection = false
//         }
//     )
}
}

चुनी गई सभी विशेषताओं को रेंडर करने के लिए, StarterView.kt फ़ाइल में चरण 4.1.3 से टिप्पणी हटाएं. साथ ही, DropdownMenu में क्लिक कॉलबैक लागू करें:

val starterOperation: MutableState<StarterViewModel.Operation?> = remember {
  mutableStateOf(starterVM.operation.value) }
  ...
  DropdownMenu(expanded = expandedOperationSelection, onDismissRequest = { expandedOperationSelection = false }) {
    // ...
    if (!StarterViewModel.starterOperations.containsKey(starterTrait.value))
    return@DropdownMenu
    // TODO: 4.1.3 - Starter device trait operations selection dropdown
      // val operations: List<StarterViewModel.Operation> = StarterViewModel.starterOperations.get(starterTrait.value ?: OnOff)?.operations!!
    //  for (operation in operations) {
    //      DropdownMenuItem(
    //          text = { Text(operation.toString()) },
    //          onClick = {
    //              scope.launch {
    //                  starterOperation.value = operation
    //              }
    //              expandedOperationSelection = false
    //          }
    //      )
    //  }
}

चुनी गई सभी विशेषताओं की वैल्यू रेंडर करने के लिए, StarterView.kt फ़ाइल में चरण 4.1.4 से टिप्पणी हटाएं. साथ ही, DropdownMenu में क्लिक कॉलबैक लागू करें:

when (starterTrait.value) {
  OnOff -> {
        ...
    DropdownMenu(expanded = expandedBooleanSelection, onDismissRequest = { expandedBooleanSelection = false }) {
// TODO: 4.1.4 - Starter device trait values selection dropdown
//             for (value in StarterViewModel.valuesOnOff.keys) {
//                 DropdownMenuItem(
//                     text = { Text(value.toString()) },
//                     onClick = {
//                         scope.launch {
//                             starterValueOnOff.value = StarterViewModel.valuesOnOff.get(value)
//                         }
//                         expandedBooleanSelection = false
//                     }
//                 )
//             }
             }
              ...
          }
           LevelControl -> {
              ...
      }
   }

सभी स्टार्टर ViewModel वैरिएबल को ड्राफ़्ट ऑटोमेशन के स्टार्टर ViewModel (draftVM.starterVMs) में सेव करने के लिए, StarterView.kt फ़ाइल में मौजूद 4.1.5 चरण से टिप्पणी हटाएं.

val draftVM: DraftViewModel = homeAppVM.selectedDraftVM.collectAsState().value!!
// Save starter button:
Button(
enabled = isOptionsSelected && isValueProvided,
onClick = {
  scope.launch {
  // TODO: 4.1.5 - store all starter ViewModel variables into draft ViewModel
  // starterVM.deviceVM.emit(starterDeviceVM.value)
  // starterVM.trait.emit(starterTrait.value)
  // starterVM.operation.emit(starterOperation.value)
  // starterVM.valueOnOff.emit(starterValueOnOff.value!!)
  // starterVM.valueLevel.emit(starterValueLevel.value!!)
  // starterVM.valueBooleanState.emit(starterValueBooleanState.value!!)
  // starterVM.valueOccupancy.emit(starterValueOccupancy.value!!)
  // starterVM.valueThermostat.emit(starterValueThermostat.value!!)
  //
  // draftVM.starterVMs.value.add(starterVM)
  // draftVM.selectedStarterVM.emit(null)
  }
})
{ Text(stringResource(R.string.starter_button_create)) }

ऐप्लिकेशन चलाने और नया ऑटोमेशन और स्टार्टर चुनने पर, आपको इस तरह का व्यू दिखेगा:

79beb3b581ec71ec.png

Sample App, सिर्फ़ डिवाइस की विशेषताओं के आधार पर स्टार्टर के साथ काम करता है.

कार्रवाइयां सेट अप करना

ऑटोमेशन ऐक्शन से, ऑटोमेशन के मुख्य मकसद का पता चलता है. साथ ही, यह भी पता चलता है कि इससे असल दुनिया में क्या बदलाव होता है. सैंपल ऐप्लिकेशन में, हम ActionViewModel क्लास का इस्तेमाल करके ऑटोमेशन ऐक्शन कैप्चर करते हैं. साथ ही , ActionView क्लास का इस्तेमाल करके एडिटर व्यू दिखाते हैं.

सैंपल ऐप्लिकेशन, ऑटोमेशन ऐक्शन नोड तय करने के लिए, Home APIs की इन इकाइयों का इस्तेमाल करता है:

  • डिवाइस
  • विशेषता
  • निर्देश
  • वैल्यू (ज़रूरी नहीं)

हर डिवाइस कमांड ऐक्शन में एक कमांड का इस्तेमाल किया जाता है. हालांकि, कुछ कमांड के लिए उससे जुड़ी पैरामीटर वैल्यू की भी ज़रूरत होगी. जैसे, MoveToLevel() और टारगेट प्रतिशत.

डिवाइस और ट्रेट को Devices API से मिले ऑब्जेक्ट में से चुना जा सकता है.

ऐप्लिकेशन में, पहले से तय की गई कमांड की सूची होती है:

   // List of operations available when creating automation starters:
enum class Action {
  ON,
  OFF,
  MOVE_TO_LEVEL,
  MODE_HEAT,
  MODE_COOL,
  MODE_OFF,
}

यह ऐप्लिकेशन, हर सुविधा के लिए काम करने वाले ऑपरेशनों को ट्रैक करता है:

 // List of operations available when comparing booleans:
object OnOffActions : Actions(listOf(
    Action.ON,
    Action.OFF,
))
// List of operations available when comparing booleans:
object LevelActions : Actions(listOf(
    Action.MOVE_TO_LEVEL
))
// List of operations available when comparing booleans:
object ThermostatActions : Actions(listOf(
    Action.MODE_HEAT,
    Action.MODE_COOL,
    Action.MODE_OFF,
))
// Map traits and the comparison operations they support:
val actionActions: Map<TraitFactory<out Trait>, Actions> = mapOf(
    OnOff to OnOffActions,
    LevelControl to LevelActions,
 // BooleanState - No Actions
 // OccupancySensing - No Actions
    Thermostat to ThermostatActions,
)

एक या उससे ज़्यादा पैरामीटर लेने वाले निर्देशों के लिए, एक वैरिएबल भी होता है:

   val valueLevel: MutableStateFlow<UByte?>

एपीआई, व्यू एलिमेंट का एक सेट दिखाता है. उपयोगकर्ता इनका इस्तेमाल करके, ज़रूरी फ़ील्ड चुन सकते हैं.

सभी ऐक्शन डिवाइसों को रेंडर करने के लिए, ActionView.kt फ़ाइल में चरण 4.2.1 से अनकमेंट करें. साथ ही, actionDeviceVM सेट करने के लिए, DropdownMenu में क्लिक कॉलबैक लागू करें.

val deviceVMs = structureVM.deviceVMs.collectAsState().value
...
DropdownMenu(expanded = expandedDeviceSelection, onDismissRequest = { expandedDeviceSelection = false }) {
// TODO: 4.2.1 - Action device selection dropdown
// for (deviceVM in deviceVMs) {
//     DropdownMenuItem(
//         text = { Text(deviceVM.name) },
//         onClick = {
//             scope.launch {
//                 actionDeviceVM.value = deviceVM
//                 actionTrait.value = null
//                 actionAction.value = null
//             }
//             expandedDeviceSelection = false
//         }
//     )
// }
}

ActionView.kt फ़ाइल में, 4.2.2 चरण से टिप्पणी हटाएं, ताकि actionDeviceVM की सभी खासियतें रेंडर हो सकें. साथ ही, DropdownMenu में क्लिक कॉलबैक लागू करें, ताकि actionTrait सेट किया जा सके. यह actionTrait, उस खासियत को दिखाता है जिससे कमांड जुड़ी है.

val actionDeviceVM: MutableState<DeviceViewModel?> = remember {
mutableStateOf(actionVM.deviceVM.value) }
...
DropdownMenu(expanded = expandedTraitSelection, onDismissRequest = { expandedTraitSelection = false }) {
// TODO: 4.2.2 - Action device traits selection dropdown
// val deviceTraits: List<Trait> = actionDeviceVM.value?.traits?.collectAsState()?.value!!
// for (trait in deviceTraits) {
//     DropdownMenuItem(
//         text = { Text(trait.factory.toString()) },
//         onClick = {
//             scope.launch {
//                 actionTrait.value = trait
//                 actionAction.value = null
//             }
//             expandedTraitSelection = false
//         }
//     )
// }
}

ActionView.kt के सभी उपलब्ध ऐक्शन रेंडर करने के लिए, ActionView.kt फ़ाइल में मौजूद चरण 4.2.3 से टिप्पणी हटाएं. साथ ही, actionAction सेट करने के लिए, DropdownMenu में क्लिक कॉलबैक लागू करें. actionAction, चुने गए ऑटोमेशन ऐक्शन को दिखाता है.actionTrait

DropdownMenu(expanded = expandedActionSelection, onDismissRequest = { expandedActionSelection = false }) {
// ...
if (!ActionViewModel.actionActions.containsKey(actionTrait.value?.factory))
return@DropdownMenu
// TODO: 4.2.3 - Action device trait actions (commands) selection dropdown
// val actions: List<ActionViewModel.Action> = ActionViewModel.actionActions.get(actionTrait.value?.factory)?.actions!!
// for (action in actions) {
//     DropdownMenuItem(
//         text = { Text(action.toString()) },
//         onClick = {
//             scope.launch {
//                 actionAction.value = action
//             }
//             expandedActionSelection = false
//         }
//     )
// }
}

ActionView.kt फ़ाइल में, चरण 4.2.4 से टिप्पणी हटाएं, ताकि विशेषता कार्रवाई (कमांड) की उपलब्ध वैल्यू रेंडर की जा सकें. साथ ही, वैल्यू बदलने के कॉलबैक में वैल्यू को actionValueLevel में सेव किया जा सके:

when (actionTrait.value?.factory) {
LevelControl -> {
// TODO: 4.2.4 - Action device trait action(command) values selection widget
// Column (Modifier.padding(horizontal = 16.dp, vertical = 8.dp).fillMaxWidth()) {
//   Text(stringResource(R.string.action_title_value), fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
//  }
//
//  Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
//      LevelSlider(value = actionValueLevel.value?.toFloat()!!, low = 0f, high = 254f, steps = 0,
//          modifier = Modifier.padding(top = 16.dp),
//          onValueChange = { value : Float -> actionValueLevel.value = value.toUInt().toUByte() }
//          isEnabled = true
//      )
//  }
...
}

सभी ऐक्शन ViewModel के वैरिएबल को ड्राफ़्ट ऑटोमेशन के ऐक्शन ViewModel (draftVM.actionVMs) में सेव करने के लिए, ActionView.kt फ़ाइल में मौजूद चरण 4.2.5 से टिप्पणी हटाएं:

val draftVM: DraftViewModel = homeAppVM.selectedDraftVM.collectAsState().value!!
// Save action button:
Button(
  enabled = isOptionsSelected,
  onClick = {
  scope.launch {
  // TODO: 4.2.5 - store all action ViewModel variables into draft ViewModel
  // actionVM.deviceVM.emit(actionDeviceVM.value)
  // actionVM.trait.emit(actionTrait.value)
  // actionVM.action.emit(actionAction.value)
  // actionVM.valueLevel.emit(actionValueLevel.value)
  //
  // draftVM.actionVMs.value.add(actionVM)
  // draftVM.selectedActionVM.emit(null)
  }
})
{ Text(stringResource(R.string.action_button_create)) }

ऐप्लिकेशन चलाने और नई ऑटोमेशन और कार्रवाई चुनने पर, आपको कुछ ऐसा व्यू दिखेगा:

6efa3c7cafd3e595.png

हम सैंपल ऐप्लिकेशन में, सिर्फ़ डिवाइस की विशेषताओं के आधार पर कार्रवाइयों को सपोर्ट करते हैं.

ड्राफ़्ट ऑटोमेशन रेंडर करना

DraftViewModel पूरा होने के बाद, इसे HomeAppView.kt रेंडर कर सकता है:

fun HomeAppView (homeAppVM: HomeAppViewModel) {
  ...
  // If a draft automation is selected, show the draft editor:
  if (selectedDraftVM != null) {
    DraftView(homeAppVM)
  }
  ...
}

DraftView.kt में:

fun DraftView (homeAppVM: HomeAppViewModel) {
   val draftVM: DraftViewModel = homeAppVM.selectedDraftVM.collectAsState().value!!
    ...
// Draft Starters:
   DraftStarterList(draftVM)
// Draft Actions:
   DraftActionList(draftVM)
}

ऑटोमेशन बनाना

स्टार्टर और कार्रवाइयां बनाने का तरीका जानने के बाद, अब आपके पास ऑटोमेशन का ड्राफ़्ट बनाने और उसे Automation API को भेजने का विकल्प है. एपीआई में एक createAutomation() फ़ंक्शन होता है. यह ऑटोमेशन ड्राफ़्ट को आर्ग्युमेंट के तौर पर लेता है और एक नया ऑटोमेशन इंस्टेंस दिखाता है.

ऑटोमेशन के ड्राफ़्ट को तैयार करने का काम, सैंपल ऐप्लिकेशन में DraftViewModel क्लास में होता है. getDraftAutomation() फ़ंक्शन को देखें. इससे आपको इस बारे में ज़्यादा जानकारी मिलेगी कि हमने पिछले सेक्शन में स्टार्टर और ऐक्शन वैरिएबल का इस्तेमाल करके, ऑटोमेशन के ड्राफ़्ट को कैसे स्ट्रक्चर किया है.

स्टार्टर ट्रेट OnOff होने पर, ऑटोमेशन ग्राफ़ बनाने के लिए ज़रूरी "select" एक्सप्रेशन बनाने के लिए, DraftViewModel.kt फ़ाइल में चरण 4.4.1 से टिप्पणी हटाएं:

val starterVMs: List<StarterViewModel> = starterVMs.value
val actionVMs: List<ActionViewModel> = actionVMs.value
    ...
fun getDraftAutomation() : DraftAutomation {
    ...
  val starterVMs: List<StarterViewModel> = starterVMs.value
    ...
  return automation {
    this.name = name
    this.description = description
    this.isActive = true
    // The sequential block wrapping all nodes:
    sequential {
    // The select block wrapping all starters:
      select {
    // Iterate through the selected starters:
        for (starterVM in starterVMs) {
        // The sequential block for each starter (should wrap the Starter Expression!)
          sequential {
              ...
              val starterTrait: TraitFactory<out Trait> = starterVM.trait.value!!
              ...
              when (starterTrait) {
                  OnOff -> {
        // TODO: 4.4.1 - Set starter expressions according to trait type
        //   val onOffValue: Boolean = starterVM.valueOnOff.value
        //   val onOffExpression: TypedExpression<out OnOff> =
        //       starterExpression as TypedExpression<out OnOff>
        //   when (starterOperation) {
        //       StarterViewModel.Operation.EQUALS ->
        //           condition { expression = onOffExpression.onOff equals onOffValue }
        //       StarterViewModel.Operation.NOT_EQUALS ->
        //           condition { expression = onOffExpression.onOff notEquals onOffValue }
        //       else -> { MainActivity.showError(this, "Unexpected operation for OnOf
        //   }
        }
   LevelControl -> {
     ...
// Function to allow manual execution of the automation:
manualStarter()
     ...
}

चुनी गई ऐक्शन ट्रेट LevelControl और चुना गया ऐक्शन MOVE_TO_LEVEL होने पर, ऑटोमेशन ग्राफ़ बनाने के लिए ज़रूरी पैरलल एक्सप्रेशन बनाने के लिए, DraftViewModel.kt फ़ाइल में मौजूद चरण 4.4.2 से टिप्पणी हटाएं:

val starterVMs: List<StarterViewModel> = starterVMs.value
val actionVMs: List<ActionViewModel> = actionVMs.value
    ...
fun getDraftAutomation() : DraftAutomation {
      ...
  return automation {
    this.name = name
    this.description = description
    this.isActive = true
    // The sequential block wrapping all nodes:
    sequential {
          ...
    // Parallel block wrapping all actions:
      parallel {
        // Iterate through the selected actions:
        for (actionVM in actionVMs) {
          val actionDeviceVM: DeviceViewModel = actionVM.deviceVM.value!!
        // Action Expression that the DSL will check for:
          action(actionDeviceVM.device, actionDeviceVM.type.value.factory) {
            val actionCommand: Command = when (actionVM.action.value) {
                  ActionViewModel.Action.ON -> { OnOff.on() }
                  ActionViewModel.Action.OFF -> { OnOff.off() }
    // TODO: 4.4.2 - Set starter expressions according to trait type
    // ActionViewModel.Action.MOVE_TO_LEVEL -> {
    //     LevelControl.moveToLevelWithOnOff(
    //         actionVM.valueLevel.value!!,
    //         0u,
    //         LevelControlTrait.OptionsBitmap(),
    //         LevelControlTrait.OptionsBitmap()
    //     )
    // }
      ActionViewModel.Action.MODE_HEAT -> { SimplifiedThermostat
      .setSystemMode(SimplifiedThermostatTrait.SystemModeEnum.Heat) }
          ...
}

ऑटोमेशन को पूरा करने का आखिरी चरण, getDraftAutomation फ़ंक्शन को लागू करना है, ताकि AutomationDraft. बनाया जा सके

Home API को कॉल करके और अपवादों को मैनेज करके ऑटोमेशन बनाने के लिए, HomeAppViewModel.kt फ़ाइल में चरण 4.4.3 से टिप्पणी हटाएं:

fun createAutomation(isPending: MutableState<Boolean>) {
  viewModelScope.launch {
    val structure : Structure = selectedStructureVM.value?.structure!!
    val draft : DraftAutomation = selectedDraftVM.value?.getDraftAutomation()!!
    isPending.value = true
    // TODO: 4.4.3 - Call the Home API to create automation and handle exceptions
    // // Call Automation API to create an automation from a draft:
    // try {
    //     structure.createAutomation(draft)
    // }
    // catch (e: Exception) {
    //     MainActivity.showError(this, e.toString())
    //     isPending.value = false
    //     return@launch
    // }
    // Scrap the draft and automation candidates used in the process:
    selectedCandidateVMs.emit(null)
    selectedDraftVM.emit(null)
    isPending.value = false
  }
}

अब ऐप्लिकेशन चलाएं और अपने डिवाइस पर बदलाव देखें!

स्टार्टर और कार्रवाई चुनने के बाद, ऑटोमेशन बनाने के लिए यह तरीका अपनाएं:

ec551405f8b07b8e.png

पक्का करें कि आपने अपने ऑटोमेशन को कोई यूनीक नाम दिया हो. इसके बाद, ऑटोमेशन बनाएं बटन पर टैप करें. इससे एपीआई कॉल होने चाहिए और आपको ऑटोमेशन की सूची वाले व्यू पर वापस ले जाना चाहिए. यहां आपको अपना ऑटोमेशन दिखेगा:

8eebc32cd3755618.png

अभी बनाए गए ऑटोमेशन पर टैप करें और देखें कि एपीआई से यह कैसे वापस आता है.

931dba7c325d6ef7.png

ध्यान दें कि एपीआई, एक वैल्यू दिखाता है. इससे पता चलता है कि ऑटोमेशन मान्य है या नहीं और फ़िलहाल चालू है या नहीं. ऐसे ऑटोमेशन बनाए जा सकते हैं जो सर्वर साइड पर पार्स किए जाने पर, पुष्टि नहीं करते. अगर ऑटोमेशन पार्स करने के दौरान पुष्टि नहीं हो पाती है, तो isValid को false पर सेट कर दिया जाता है. इससे पता चलता है कि ऑटोमेशन अमान्य है और चालू नहीं है. अगर आपका ऑटोमेशन अमान्य है, तो ज़्यादा जानकारी के लिए automation.validationIssues फ़ील्ड देखें.

पक्का करें कि आपका ऑटोमेशन मान्य और चालू हो. इसके बाद, ऑटोमेशन को आज़माया जा सकता है.

ऑटोमेशन आज़माना

ऑटोमेशन को दो तरीकों से लागू किया जा सकता है:

  1. स्टार्टर इवेंट के साथ. अगर शर्तें पूरी होती हैं, तो इससे ऑटोमेशन में सेट की गई कार्रवाई ट्रिगर हो जाती है.
  2. मैन्युअल एक्ज़ीक्यूशन एपीआई कॉल की मदद से.

अगर किसी ड्राफ़्ट ऑटोमेशन में, ऑटोमेशन ड्राफ़्ट डीएसएल ब्लॉक में manualStarter() तय किया गया है, तो ऑटोमेशन इंजन उस ऑटोमेशन के लिए मैन्युअल तरीके से लागू करने की सुविधा देगा. यह जानकारी, सैंपल ऐप्लिकेशन में दिए गए कोड के उदाहरणों में पहले से मौजूद है.

अपने फ़ोन या टैबलेट पर, ऑटोमेशन व्यू स्क्रीन पर रहते हुए, मैन्युअल तरीके से लागू करें बटन पर टैप करें. इससे automation.execute() को कॉल करना चाहिए. यह आपके चुने गए डिवाइस पर, कार्रवाई का निर्देश चलाता है. आपने इस डिवाइस को ऑटोमेशन सेट अप करते समय चुना था.

एपीआई का इस्तेमाल करके, मैन्युअल तरीके से कार्रवाई की कमांड की पुष्टि करने के बाद, अब यह देखने का समय है कि क्या यह आपके तय किए गए स्टार्टर का इस्तेमाल करके भी लागू हो रही है.

डिवाइस टैब पर जाएं. इसके बाद, कार्रवाई करने वाला डिवाइस और उसकी विशेषता चुनें. इसके बाद, उसे किसी दूसरी वैल्यू पर सेट करें. उदाहरण के लिए, नीचे दिए गए स्क्रीनशॉट में दिखाए गए तरीके से, light2 की LevelControl (चमक) को 50% पर सेट करें:

d0357ec71325d1a8.png

अब हम स्टार्टर डिवाइस का इस्तेमाल करके, ऑटोमेशन को ट्रिगर करने की कोशिश करेंगे. ऑटोमेशन बनाते समय चुना गया स्टार्टर डिवाइस चुनें. चुनी गई विशेषता को टॉगल करें. उदाहरण के लिए, starter outlet1 को On पर सेट करें:OnOff

230c78cd71c95564.png

आपको दिखेगा कि इससे ऑटोमेशन भी लागू होता है और ऐक्शन डिवाइस light2 की LevelControl ट्रेट को मूल वैल्यू, 100% पर सेट किया जाता है:

1f00292128bde1c2.png

बधाई हो, आपने ऑटोमेशन बनाने के लिए Home API का इस्तेमाल कर लिया है!

Automation API के बारे में ज़्यादा जानने के लिए, Android Automation API देखें.

5. सुविधाओं के बारे में जानें

Home API में, Discovery API नाम का एक खास एपीआई शामिल होता है. डेवलपर इसका इस्तेमाल करके यह क्वेरी कर सकते हैं कि किसी डिवाइस में, ऑटोमेशन की सुविधा के साथ काम करने वाली कौनसी सुविधाएं उपलब्ध हैं. सैंपल ऐप्लिकेशन में एक उदाहरण दिया गया है. इसमें बताया गया है कि इस एपीआई का इस्तेमाल करके, यह कैसे पता लगाया जा सकता है कि कौनसी कमांड उपलब्ध हैं.

निर्देशों के बारे में जानें

इस सेक्शन में, हम यह जानेंगे कि काम करने वाले CommandCandidates का पता कैसे लगाया जाए. साथ ही, खोजे गए कैंडिडेट नोड के आधार पर ऑटोमेशन कैसे बनाया जाए.

सैंपल ऐप्लिकेशन में, उम्मीदवारों की सूची पाने के लिए हम device.candidates() को कॉल करते हैं. इसमें CommandCandidate, EventCandidate या TraitAttributesCandidate के उदाहरण शामिल हो सकते हैं.

HomeAppViewModel.kt फ़ाइल पर जाएं और उम्मीदवार की सूची पाने के लिए, चरण 5.1.1 से टिप्पणी हटाने के लिए, यह तरीका अपनाएं. साथ ही, Candidate टाइप का इस्तेमाल करके सूची को फ़िल्टर करें:

   fun showCandidates() {

   ...
// TODO: 5.1.1 - Retrieve automation candidates, filtering to include CommandCandidate types only
// // Retrieve a set of initial automation candidates from the device:
// val candidates: Set<NodeCandidate> = deviceVM.device.candidates().first()
//
// for (candidate in candidates) {
//     // Check whether the candidate trait is supported:
//     if(candidate.trait !in HomeApp.supportedTraits)
//         continue
//     // Check whether the candidate type is supported:
//     when (candidate) {
//         // Command candidate type:
//         is CommandCandidate -> {
//             // Check whether the command candidate has a supported command:
//             if (candidate.commandDescriptor !in ActionViewModel.commandMap)
//                 continue
//         }
//         // Other candidate types are currently unsupported:
//         else -> { continue }
//     }
//
//     candidateVMList.add(CandidateViewModel(candidate, deviceVM))
// }
...
           // Store the ViewModels:
selectedCandidateVMs.emit(candidateVMList)
}

देखें कि यह कैसे फ़िल्टर करता है, क्योंकि CommandCandidate. एपीआई से मिले उम्मीदवार अलग-अलग तरह के होते हैं. Sample App में CommandCandidate की सुविधा काम करती है. इन सुविधाओं को सेट करने के लिए, ActionViewModel.kt में तय किए गए commandMap में मौजूद, चरण 5.1.2 से टिप्पणी हटाएं:

    // Map of supported commands from Discovery API:
val commandMap: Map<CommandDescriptor, Action> = mapOf(
    // TODO: 5.1.2 - Set current supported commands
    // OnOffTrait.OnCommand to Action.ON,
    // OnOffTrait.OffCommand to Action.OFF,
    // LevelControlTrait.MoveToLevelWithOnOffCommand to Action.MOVE_TO_LEVEL
)

अब हम Discovery API को कॉल कर सकते हैं. साथ ही, सैंपल ऐप्लिकेशन में काम करने वाले नतीजों को फ़िल्टर कर सकते हैं. अब हम इस बारे में बात करेंगे कि इसे एडिटर में कैसे इंटिग्रेट किया जा सकता है.

8a2f0e8940f7056a.png

Discovery API के बारे में ज़्यादा जानने के लिए, Android पर डिवाइस ढूंढने की सुविधा का फ़ायदा उठाना पर जाएं.

एडिटर को इंटिग्रेट करना

खोजे गए ऐक्शन का इस्तेमाल करने का सबसे सामान्य तरीका यह है कि उन्हें असली उपयोगकर्ता को दिखाया जाए, ताकि वह उनमें से किसी एक को चुन सके. उपयोगकर्ता के ड्राफ़्ट ऑटोमेशन फ़ील्ड चुनने से ठीक पहले, हम उसे खोजे गए ऐक्शन की सूची दिखा सकते हैं. साथ ही, चुनी गई वैल्यू के आधार पर, हम ऑटोमेशन ड्राफ़्ट में ऐक्शन नोड को पहले से भर सकते हैं.

CandidatesView.kt फ़ाइल में व्यू क्लास होती है. यह क्लास, खोजे गए उम्मीदवारों को दिखाती है. CandidateListItem के .clickable{} फ़ंक्शन को चालू करने के लिए, चरण 5.2.1 से टिप्पणी हटाएं. यह फ़ंक्शन, homeAppVM.selectedDraftVM को candidateVM के तौर पर सेट करता है:

fun CandidateListItem (candidateVM: CandidateViewModel, homeAppVM: HomeAppViewModel) {
    val scope: CoroutineScope = rememberCoroutineScope()
    Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
        Column (Modifier.fillMaxWidth().clickable {
        // TODO: 5.2.1 - Set the selectedDraftVM to the selected candidate
        // scope.launch { homeAppVM.selectedDraftVM.emit(DraftViewModel(candidateVM)) }
        }) {
            ...
        }
    }
}

HomeAppView.kt में दिए गए चरण 4.3 की तरह, selectedDraftVM को सेट करने पर, यह DraftView(...) in DraftView.kt` को रेंडर करता है:

fun HomeAppView (homeAppVM: HomeAppViewModel) {
   ...
  val selectedDraftVM: DraftViewModel? by homeAppVM.selectedDraftVM.collectAsState()
...
  // If a draft automation is selected, show the draft editor:
  if (selectedDraftVM != null) {
  DraftView(homeAppVM)
  }
   ...
}

इसे फिर से आज़माएं. इसके लिए, पिछले सेक्शन में दिखाए गए light2 - MOVE_TO_LEVEL पर टैप करें. इससे आपको उम्मीदवार के निर्देश के आधार पर, नया ऑटोमेशन बनाने का अनुरोध मिलेगा:

15e67763a9241000.png

अब आपको सैंपल ऐप्लिकेशन में ऑटोमेशन बनाने के बारे में पता चल गया है. इसलिए, अपने ऐप्लिकेशन में ऑटोमेशन को इंटिग्रेट किया जा सकता है.

6. बेहतर ऑटोमेशन के उदाहरण

हमारा यह विषय खत्म होने से पहले, हम ऑटोमेशन डीएसएल के कुछ और उदाहरणों पर चर्चा करेंगे. इनसे, एपीआई की कुछ ऐडवांस सुविधाओं के बारे में पता चलता है.

दिन के किस समय Starter प्लान का इस्तेमाल किया गया

डिवाइस की विशेषताओं के अलावा, Google Home API, स्ट्रक्चर पर आधारित विशेषताएं भी उपलब्ध कराते हैं. जैसे, Time. आपके पास ऐसा ऑटोमेशन बनाने का विकल्प होता है जिसमें समय के हिसाब से काम करने वाला स्टार्टर हो. जैसे:

automation {
  name = "AutomationName"
  description = "An example automation description."
  isActive = true
  description = "Do ... actions when time is up."
  sequential {
    // starter
    val starter = starter<_>(structure, Time.ScheduledTimeEvent) {
      parameter(
        Time.ScheduledTimeEvent.clockTime(
          LocalTime.of(hour, min, sec, 0)
        )
      )
    }
        // action
  ...
  }
}

Assistant की कार्रवाई के तौर पर ब्रॉडकास्ट करना

AssistantBroadcast ट्रेट, डिवाइस-लेवल की ट्रेट के तौर पर SpeakerDevice में उपलब्ध होती है. हालांकि, यह सिर्फ़ तब उपलब्ध होती है, जब स्पीकर इस सुविधा के साथ काम करता हो. इसके अलावा, यह स्ट्रक्चर-लेवल की ट्रेट के तौर पर भी उपलब्ध होती है, क्योंकि Google स्पीकर और Android मोबाइल डिवाइसों पर Assistant के ब्रॉडकास्ट चलाए जा सकते हैं. उदाहरण के लिए:

automation {
  name = "AutomationName"
  description = "An example automation description."
  isActive = true
  description = "Broadcast in Speaker when ..."
  sequential {
    // starter
      ...
    // action
    action(structure) {
      command(
      AssistantBroadcast.broadcast("Time is up!!")
      )
    }
  }
}

DelayFor और suppressFor का इस्तेमाल करना

ऑटोमेशन एपीआई, delayFor का इस्तेमाल, कमांड में देरी करने के लिए किया जाता है. वहीं, suppressFor का इस्तेमाल, किसी तय समय में एक ही इवेंट से ऑटोमेशन को ट्रिगर होने से रोकने के लिए किया जा सकता है. इन ऑपरेटर का इस्तेमाल करके बनाए गए कुछ उदाहरण यहां दिए गए हैं:

sequential {
  val starterNode = starter<_>(device, OccupancySensorDevice, MotionDetection)
  // only proceed if there is currently motion taking place
  condition { starterNode.motionDetectionEventInProgress equals true }
   // ignore the starter for one minute after it was last triggered
    suppressFor(Duration.ofMinutes(1))
  
    // make announcements three seconds apart
    action(device, SpeakerDevice) {
      command(AssistantBroadcast.broadcast("Intruder detected!"))
    }
    delayFor(Duration.ofSeconds(3))
    action(device, SpeakerDevice) {
    command(AssistantBroadcast.broadcast("Intruder detected!"))
  }
    ...
}

स्टार्टर में AreaPresenceState का इस्तेमाल करना

AreaPresenceState एक स्ट्रक्चर-लेवल की विशेषता है. इससे यह पता चलता है कि घर पर कोई है या नहीं.

उदाहरण के लिए, यहां दिए गए उदाहरण में बताया गया है कि रात 10 बजे के बाद, किसी के घर में होने पर दरवाज़े अपने-आप लॉक हो जाते हैं:

automation {
  name = "Lock the doors when someone is home after 10pm"
  description = "1 starter, 2 actions"
  sequential {
    val unused =
      starter(structure, event = Time.ScheduledTimeEvent) {
        parameter(Time.ScheduledTimeEvent.clockTime(LocalTime.of(22, 0, 0, 0)))
      }
    val stateReaderNode = stateReader<_>(structure, AreaPresenceState)
    condition {
      expression =
        stateReaderNode.presenceState equals
          AreaPresenceStateTrait.PresenceState.PresenceStateOccupied
    }
    action(structure) { command(AssistantBroadcast.broadcast("Locks are being applied")) }
    for (lockDevice in lockDevices) {
      action(lockDevice, DoorLockDevice) {
        command(Command(DoorLock, DoorLockTrait.LockDoorCommand.requestId.toString(), mapOf()))
      }
    }
  }

अब जब आपको ऑटोमेशन की इन बेहतर सुविधाओं के बारे में पता चल गया है, तो जाकर शानदार ऐप्लिकेशन बनाएं!

7. बधाई हो!

बधाई हो! आपने Google Home API का इस्तेमाल करके, Android ऐप्लिकेशन बनाने का दूसरा हिस्सा पूरा कर लिया है. इस कोडलैब में, आपने ऑटोमेशन और डिस्कवरी एपीआई के बारे में जाना.

हमें उम्मीद है कि आपको Google Home के नेटवर्क में शामिल डिवाइसों को क्रिएटिव तरीके से कंट्रोल करने वाले ऐप्लिकेशन बनाने में मज़ा आएगा. साथ ही, Home API का इस्तेमाल करके, ऑटोमेशन से जुड़े दिलचस्प उदाहरण बनाने में भी आपको आनंद आएगा!

अगले चरण

  • ऐप्लिकेशन को असरदार तरीके से डीबग करने और Home API से जुड़ी समस्याओं को हल करने का तरीका जानने के लिए, समस्या हल करना लेख पढ़ें.
  • अगर आपको कोई सुझाव देना है या किसी समस्या की शिकायत करनी है, तो समस्या ट्रैकर में जाकर हमसे संपर्क करें. इसके लिए, स्मार्ट होम से जुड़े सहायता विषय पर जाएं.