यह देखना कि कोई ट्रेट, कमांड के साथ काम करता है या नहीं
किसी ट्रेट की कमांड के साथ काम करने की क्षमता भी देखी जा सकती है. यह देखने के लिए कि किसी खास डिवाइस के लिए कोई कमांड काम करती है या नहीं, ट्रेट-लेवल के supports फ़ंक्शन का भी इस्तेमाल करें.
उदाहरण के लिए, यह देखने के लिए कि कोई डिवाइस, On/Off ट्रेट की
toggle
कमांड के साथ काम करता है या नहीं:
// Check if the OnOff trait supports the toggle command. if (onOffTrait.supports(OnOff.Command.Toggle)) { println("onOffTrait supports toggle command") } else { println("onOffTrait does not support stateful toggle command") }
किसी डिवाइस को कमांड भेजना
कमांड भेजना, किसी ट्रेट से स्टेट एट्रिब्यूट को पढ़ने जैसा है. डिवाइस को चालू या बंद करने के लिए,
ट्रेट की Toggle कमांड का इस्तेमाल करें. इसे Google Home इकोसिस्टम के डेटा
मॉडल में toggle() के तौर पर तय किया गया है.OnOff यह तरीका, onOff की वैल्यू को true होने पर false में या false होने पर true में बदल देता है:
// Calling a command on a trait. try { onOffTrait.toggle() } catch (e: HomeException) { // Code for handling the exception }
ट्रेट की सभी कमांड, suspend फ़ंक्शन होती हैं. ये सिर्फ़ तब पूरी होती हैं, जब एपीआई से कोई जवाब
मिलता है. जैसे, डिवाइस की स्टेट में बदलाव की पुष्टि करना.
अगर एक्ज़ीक्यूशन फ़्लो में कोई समस्या पाई जाती है, तो कमांड से कोई अपवाद मिल सकता है. डेवलपर के तौर पर, आपको इन अपवादों को सही तरीके से मैनेज करने के लिए, try-catch ब्लॉक का इस्तेमाल करना चाहिए. साथ ही, उन मामलों में लोगों को पूरी जानकारी देनी चाहिए जहां गड़बड़ियों को ठीक किया जा सकता है. मैनेज न किए गए अपवादों की वजह से, ऐप्लिकेशन का रनटाइम बंद हो जाएगा और आपका ऐप्लिकेशन क्रैश हो सकता है.
इसके अलावा, स्टेट को साफ़ तौर पर सेट करने के लिए, off() या on() कमांड का इस्तेमाल करें:
onOffTrait.off() onOffTrait.on()
स्टेट में बदलाव करने के लिए कमांड भेजने के बाद, जब यह पूरी हो जाती है, तब स्टेट को पढ़ा जा सकता है. इसके लिए, अपने ऐप्लिकेशन में डिवाइस की स्टेट को मैनेज करने के लिए, डिवाइस की स्टेट पढ़ना में बताया गया तरीका अपनाएं. इसके अलावा, फ़्लो का इस्तेमाल करें. इसके लिए, स्टेट को मॉर्टिनर करना में बताया गया तरीका अपनाएं. यह तरीका बेहतर है.
पैरामीटर के साथ कमांड भेजना
कुछ कमांड में पैरामीटर इस्तेमाल किए जा सकते हैं. जैसे, OnOff या
LevelControl
ट्रेट की कमांड में:
offWithEffect
// Turn off the light using the DyingLight effect. onOffTrait.offWithEffect( effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight, effectVariant = 0u, )
moveToLevel
// Change the brightness of the light to 50% levelControlTrait.moveToLevel( level = 127u.toUByte(), transitionTime = null, optionsMask = LevelControlTrait.OptionsBitmap(), optionsOverride = LevelControlTrait.OptionsBitmap(), )
कुछ कमांड में ज़रूरी आर्ग्युमेंट के बाद, वैकल्पिक आर्ग्युमेंट होते हैं.
उदाहरण के लिए, step कमांड के लिए FanControl
ट्रेट
में दो वैकल्पिक आर्ग्युमेंट होते हैं:
val fanControlTraitFlow: Flow<FanControl?> = device.type(FanDevice).map { it.standardTraits.fanControl }.distinctUntilChanged() val fanControl = fanControlTraitFlow.firstOrNull() // Calling a command with optional parameters not set. fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) // Calling a command with optional parameters. fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) { wrap = true }
यह देखना कि कोई ट्रेट, एट्रिब्यूट के साथ काम करता है या नहीं
ऐसा हो सकता है कि कुछ डिवाइस, Matter ट्रेट के साथ काम करें, लेकिन किसी
खास एट्रिब्यूट के साथ नहीं. उदाहरण के लिए, Cloud-to-cloud डिवाइस को Matter पर मैप करने पर, ऐसा हो सकता है कि वह Matter के हर एट्रिब्यूट के साथ काम न करे. ऐसी स्थितियों को मैनेज करने के लिए, ट्रेट-लेवल के supports फ़ंक्शन और ट्रेट के Attribute enum का इस्तेमाल करके, यह देखा जा सकता है कि किसी खास डिवाइस के लिए एट्रिब्यूट काम करता है या नहीं.
उदाहरण के लिए, यह देखने के लिए कि कोई डिवाइस, On/Off ट्रेट के
onOff
एट्रिब्यूट के साथ काम करता है या नहीं:
// Check if the OnOff trait supports the onOff attribute. if (onOffTrait.supports(OnOff.Attribute.onOff)) { println("onOffTrait supports onOff state") } else { println("onOffTrait is for a command only device!") }
कुछ एट्रिब्यूट की वैल्यू को Matter स्पेसिफ़िकेशन या
Cloud-to-cloud smart home स्कीमा में 'शून्य' पर सेट किया जा सकता है. इन एट्रिब्यूट के लिए, यह पता लगाया जा सकता है कि एट्रिब्यूट से मिली शून्य वैल्यू, डिवाइस के उस वैल्यू की रिपोर्ट न करने की वजह से मिली है या एट्रिब्यूट की वैल्यू असल में null है. इसके लिए, supports के अलावा isNullable का इस्तेमाल करें:
// Check if a nullable attribute is set or is not supported. if (onOffTrait.supports(OnOff.Attribute.startUpOnOff)) { // The device supports startupOnOff, it is safe to expect this value in the trait. if (OnOff.Attribute.startUpOnOff.isNullable && onOffTrait.startUpOnOff == null) { // This value is nullable and set to null. Check the specification as to // what null in this case means println("onOffTrait supports startUpOnOff and it is null") } else { // This value is nullable and set to a value. println("onOffTrait supports startUpOnOff and it is set to ${onOffTrait.startUpOnOff}") } } else { println("onOffTrait does not support startUpOnOff!") }
ट्रेट के एट्रिब्यूट अपडेट करना
अगर आपको किसी एट्रिब्यूट की वैल्यू बदलनी है और ट्रेट की कोई भी कमांड ऐसा नहीं करती है, तो हो सकता है कि एट्रिब्यूट की वैल्यू को साफ़ तौर पर सेट किया जा सके.
किसी एट्रिब्यूट की वैल्यू बदली जा सकती है या नहीं, यह इन दो फ़ैक्टर पर निर्भर करता है:
- क्या एट्रिब्यूट में बदलाव किया जा सकता है?
- क्या ट्रेट की कमांड भेजने पर, एट्रिब्यूट की वैल्यू में बदलाव हो सकता है?
ट्रेट और उनके एट्रिब्यूट के रेफ़रंस दस्तावेज़ में यह जानकारी दी गई है.
इसलिए, प्रॉपर्टी के वे कॉम्बिनेशन जिनसे यह तय होता है कि किसी एट्रिब्यूट की वैल्यू कैसे बदली जा सकती है, ये हैं:
सिर्फ़ पढ़ी जा सकती है और अन्य कमांड से असर नहीं पड़ता. इसका मतलब है कि एट्रिब्यूट की वैल्यू नहीं बदलती. उदाहरण के लिए,
currentPositionएट्रिब्यूटSwitchट्रेट का.सिर्फ़ पढ़ी जा सकती है और अन्य कमांड से असर पड़ता है. इसका मतलब है कि एट्रिब्यूट की वैल्यू में बदलाव सिर्फ़ कमांड भेजने पर हो सकता है. उदाहरण के लिए,
currentLevelएट्रिब्यूट सिर्फ़ पढ़ा जा सकता है. हालांकि, इसकी वैल्यू कोLevelControlMatter ट्रेट जैसी कमांड से बदला जा सकता है.moveToLevelबदली जा सकती है और अन्य कमांड से असर नहीं पड़ता. इसका मतलब है कि ट्रेट के
updateफ़ंक्शन का इस्तेमाल करके, एट्रिब्यूट की वैल्यू को सीधे तौर पर बदला जा सकता है. हालांकि, ऐसी कोई कमांड नहीं है जिससे एट्रिब्यूट की वैल्यू पर असर पड़ेगा. उदाहरण के लिए,WrongCodeEntryLimitएट्रिब्यूट काDoorLockट्रेट.बदली जा सकती है और अन्य कमांड से असर पड़ता है. इसका मतलब है कि ट्रेट के
updateफ़ंक्शन का इस्तेमाल करके, एट्रिब्यूट की वैल्यू को सीधे तौर पर बदला जा सकता है. साथ ही, कमांड भेजने पर एट्रिब्यूट की वैल्यू में बदलाव हो सकता है. उदाहरण के लिए,speedSettingएट्रिब्यूट कोFanControlTraitसीधे तौर पर लिखा जा सकता है. हालांकि,stepकमांड का इस्तेमाल करके भी इसे बदला जा सकता है.
किसी एट्रिब्यूट की वैल्यू बदलने के लिए, update फ़ंक्शन का इस्तेमाल करने का उदाहरण
इस उदाहरण में,
DoorLockTrait.WrongCodeEntryLimit एट्रिब्यूट की वैल्यू को साफ़ तौर पर सेट करने का तरीका दिखाया गया है.
किसी एट्रिब्यूट की वैल्यू सेट करने के लिए, ट्रेट के update फ़ंक्शन को कॉल करें और उसे एक ऐसा म्यूटेटर फ़ंक्शन पास करें जो नई वैल्यू सेट करता है.
यह पक्का करना ज़रूरी है कि ट्रेट, एट्रिब्यूट के साथ काम करता हो
.
उदाहरण के लिए:
val doorLockDevice = home.devices().list().first { device -> device.has(DoorLock) } val traitFlow: Flow<DoorLock?> = doorLockDevice.type(DoorLockDevice).map { it.standardTraits.doorLock }.distinctUntilChanged() val doorLockTrait: DoorLock = traitFlow.first()!! if (doorLockTrait.supports(DoorLock.Attribute.wrongCodeEntryLimit)) { val unused = doorLockTrait.update { setWrongCodeEntryLimit(3u) } }
एक साथ कई कमांड भेजना
बैचिंग एपीआई की मदद से, क्लाइंट एक पेलोड में, Home API के डिवाइस की कई कमांड भेज सकता है. कमांड को एक पेलोड में बैच किया जाता है और उन्हें एक साथ एक्ज़ीक्यूट किया जाता है. यह ठीक वैसा ही है जैसे कोई व्यक्ति, Home API का ऑटोमेशन बनाने के लिए पैरलल नोड का इस्तेमाल करता है, जैसे कि सूर्योदय से पहले ब्लाइंड खोलना का उदाहरण. हालांकि, बैचिंग एपीआई, Automation API की तुलना में ज़्यादा जटिल और बेहतर तरीके से काम करता है. जैसे, किसी भी मानदंड के मुताबिक, रनटाइम में डिवाइसों को डाइनैमिक तरीके से चुनने की सुविधा.
एक बैच में मौजूद कमांड, कई डिवाइसों, कई कमरों, और कई स्ट्रक्चर में मौजूद कई ट्रेट को टारगेट कर सकती हैं.
बैच में कमांड भेजने से, डिवाइस एक साथ कार्रवाइयां कर सकते हैं. अलग-अलग अनुरोधों में क्रम से कमांड भेजने पर ऐसा नहीं किया जा सकता. बैच की गई कमांड का इस्तेमाल करके, डेवलपर डिवाइसों के ग्रुप की स्टेट को, पहले से तय की गई कुल स्टेट के हिसाब से सेट कर सकता है.
बैचिंग एपीआई का इस्तेमाल करना
बैचिंग एपीआई के ज़रिए कमांड लागू करने के तीन बुनियादी चरण हैं:
Home.sendBatchedCommands()तरीके को लागू करना.sendBatchedCommands()ब्लॉक के मुख्य हिस्से में, बैच में शामिल की जाने वाली कमांड तय करना.- भेजी गई कमांड के नतीजे देखना, ताकि यह पता चल सके कि वे पूरी हुईं या नहीं.
sendBatchedCommands() तरीके को लागू करना
तरीके को कॉल करें.Home.sendBatchedCommands() बैकग्राउंड में, यह तरीका बैच के खास कॉन्टेक्स्ट में लैम्डा एक्सप्रेशन सेट अप करता है.
home.sendBatchedCommands() {
बैच कमांड तय करना
sendBatchedCommands() ब्लॉक के मुख्य हिस्से में, बैच की जा सकने वाली कमांड जोड़ें. बैच की जा सकने वाली कमांड, मौजूदा डिवाइस एपीआई कमांड के "शैडो" वर्शन होते हैं. इनका इस्तेमाल बैच के कॉन्टेक्स्ट में किया जा सकता है. इनके नाम में Batchable सफ़िक्स जोड़ा जाता है. उदाहरण के लिए,
LevelControl
ट्रेट की
moveToLevel()
कमांड का एक काउंटरपार्ट है, जिसका नाम
moveToLevelBatchable() है.
उदाहरण:
val response1 = add(command1)
val response2 = add(command2)
बैच के कॉन्टेक्स्ट में सभी कमांड जोड़ने और कॉन्टेक्स्ट से बाहर निकलने के बाद, बैच अपने-आप भेज दिया जाता है.
जवाब,
DeferredResponse<T>
ऑब्जेक्ट में कैप्चर किए जाते हैं.
DeferredResponse<T>
इंस्टेंस को किसी भी टाइप के ऑब्जेक्ट में इकट्ठा किया जा सकता है. जैसे, Collection, या आपके तय किए गए डेटा क्लास में. जवाबों को इकट्ठा करने के लिए, जिस भी टाइप का ऑब्जेक्ट चुना जाता है, उसे
sendBatchedCommands() से लौटाया जाता है. उदाहरण के लिए, बैच का कॉन्टेक्स्ट, दो
DeferredResponse इंस्टेंस Pair में लौटा सकता है:
val (response1, response2) = homeClient.sendBatchedComamnds {
val response1 = add(someCommandBatched(...))
val response2 = add(someOtherCommandBatched(...))
Pair(response1, response2)
}
इसके अलावा, बैच का कॉन्टेक्स्ट, DeferredResponse
इंस्टेंस को कस्टम डेटा क्लास में लौटा सकता है:
// Custom data class
data class SpecialResponseHolder(
val response1: DeferredResponse<String>,
val response2: DeferredResponse<Int>,
val other: OtherResponses
)
data class OtherResponses(...)
हर जवाब की जांच करना
sendBatchedCommands() ब्लॉक के बाहर, जवाबों की जांच करके यह पता लगाएं कि संबंधित कमांड पूरी हुई या नहीं. इसके लिए, DeferredResponse.getOrThrow() को कॉल करें. इससे:
- एक्ज़ीक्यूट की गई कमांड का नतीजा मिलता है,
- या, अगर बैच का स्कोप पूरा नहीं हुआ है या कमांड पूरी नहीं हुई है, तो गड़बड़ी मिलती है.
आपको नतीजों की जांच सिर्फ़ sendBatchedCommands() लैम्डा स्कोप के बाहर करनी चाहिए.
उदाहरण
मान लें कि आपको एक ऐसा ऐप्लिकेशन बनाना है जो बैचिंग एपीआई का इस्तेमाल करके, 'शुभ रात्रि' सीन सेट अप करता है. यह सीन, रात के समय घर के सभी डिवाइसों को कॉन्फ़िगर करता है, जब सभी लोग सो रहे होते हैं. इस ऐप्लिकेशन को लाइटें बंद करनी चाहिए और सामने और पीछे के दरवाज़े लॉक करने चाहिए.
इस टास्क को पूरा करने का एक तरीका यहां बताया गया है:
val lightDevices: List<OnOffLightDevice>
val doorlockDevices: List<DoorLockDevice>
// Send all the commands
val responses: List<DeferredResponse<Unit>> = home.sendBatchedCommands {
// For each light device, send a Batchable command to turn it on
val lightResponses: List<DeferredResponse<Unit>> = lightDevices.map { lightDevice ->
add(lightDevice.standardTraits.onOff.onBatchable())
}
// For each doorlock device, send a Batchable command to lock it
val doorLockResponse: List<DeferredResponse<Unit>> = doorlockDevices.map { doorlockDevice ->
add(doorlockDevice.standardTraits.doorLock.lockDoorBatchable())
}
lightResponses + doorLockResponses
}
// Check that all responses were successful
for (response in responses) {
response.getOrThrow()
}