কোনো ট্রেইট কমান্ড সমর্থন করে কিনা তা পরীক্ষা করুন
একটি ট্রেইট কমান্ডের জন্য সমর্থনও পরীক্ষা করা যেতে পারে। এছাড়াও, কোনো কমান্ড একটি নির্দিষ্ট ডিভাইসের জন্য সমর্থিত কিনা তা পরীক্ষা করতে ট্রেইট-লেভেল 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") }
একটি ডিভাইসে কমান্ড পাঠান
একটি কমান্ড পাঠানো একটি ট্রেইট থেকে স্টেট অ্যাট্রিবিউট পড়ার মতোই। ডিভাইসটি চালু বা বন্ধ করতে, OnOff ট্রেইটের Toggle কমান্ডটি ব্যবহার করুন, যা Google Home ইকোসিস্টেম ডেটা মডেলে toggle() হিসেবে সংজ্ঞায়িত করা আছে। এই মেথডটি 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 ট্রেইটগুলিতে থাকা প্যারামিটারগুলো:
অফউইথইফেক্ট
// Turn off the light using the DyingLight effect. onOffTrait.offWithEffect( effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight, effectVariant = 0u, )
স্তরে সরান
// Change the brightness of the light to 50% levelControlTrait.moveToLevel( level = 127u.toUByte(), transitionTime = null, optionsMask = LevelControlTrait.OptionsBitmap(), optionsOverride = LevelControlTrait.OptionsBitmap(), )
কিছু কমান্ডের ঐচ্ছিক আর্গুমেন্ট থাকে, যেগুলো আবশ্যক আর্গুমেন্টগুলোর পরে আসে।
উদাহরণস্বরূপ, FanControl ট্রেইটের step কমান্ডটির দুটি ঐচ্ছিক আর্গুমেন্ট রয়েছে:
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 ট্রেইট সমর্থন করলেও, কোনো নির্দিষ্ট অ্যাট্রিবিউট সমর্থন নাও করতে পারে। উদাহরণস্বরূপ, Matter -এ ম্যাপ করা একটি Cloud-to-cloud ডিভাইস হয়তো সব 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) হতে পারে। এই অ্যাট্রিবিউটগুলোর ক্ষেত্রে, অ্যাট্রিবিউট দ্বারা ফেরত আসা নাল (null) মানটি ডিভাইসটি সেই মানটি রিপোর্ট না করার কারণে এসেছে, নাকি অ্যাট্রিবিউটটির মান আসলেই null , তা আপনি isNullable ব্যবহার করে supports করতে পারেন।
// 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!") }
বৈশিষ্ট্যের গুণাবলী আপডেট করুন
যদি আপনি কোনো নির্দিষ্ট অ্যাট্রিবিউটের মান পরিবর্তন করতে চান এবং ট্রেইটের কোনো কমান্ডেই তা করার সুবিধা না থাকে, তবে অ্যাট্রিবিউটটিতে সুস্পষ্টভাবে মান নির্ধারণ করার সুবিধা থাকতে পারে।
কোনো অ্যাট্রিবিউটের মান পরিবর্তন করা যাবে কিনা তা দুটি বিষয়ের উপর নির্ভর করে:
- অ্যাট্রিবিউটটি কি লেখযোগ্য?
- ট্রেইট কমান্ড পাঠানোর সাইড এফেক্ট হিসেবে কি অ্যাট্রিবিউটের মান পরিবর্তিত হতে পারে?
ট্রেইট এবং তাদের অ্যাট্রিবিউটসমূহের রেফারেন্স ডকুমেন্টেশনে এই তথ্য প্রদান করা হয়।
সুতরাং, বৈশিষ্ট্যগুলির যে সংমিশ্রণগুলি নির্ধারণ করে যে একটি অ্যাট্রিবিউটের মান কীভাবে পরিবর্তন করা যেতে পারে, সেগুলি হলো:
শুধুমাত্র পঠনযোগ্য এবং অন্যান্য কমান্ড দ্বারা প্রভাবিত হয় না । এর মানে হলো, অ্যাট্রিবিউটের মান পরিবর্তন হয় না। উদাহরণস্বরূপ,
Switchট্রেইটেরcurrentPositionঅ্যাট্রিবিউট ।শুধুমাত্র পঠনযোগ্য এবং অন্যান্য কমান্ড দ্বারা প্রভাবিত হয় । এর মানে হলো, অ্যাট্রিবিউটের মান শুধুমাত্র কোনো কমান্ড পাঠানোর মাধ্যমেই পরিবর্তিত হতে পারে। উদাহরণস্বরূপ,
LevelControlMatter ট্রেইটেরcurrentLevelঅ্যাট্রিবিউটটি শুধুমাত্র পঠনযোগ্য, কিন্তুmoveToLevelএর মতো কমান্ডের মাধ্যমে এর মান পরিবর্তন করা যায়।এটি লেখা যায় এবং অন্য কোনো কমান্ড দ্বারা প্রভাবিত হয় না । এর মানে হলো, আপনি ট্রেইটের
updateফাংশন ব্যবহার করে সরাসরি অ্যাট্রিবিউটের মান পরিবর্তন করতে পারেন, কিন্তু এমন কোনো কমান্ড নেই যা অ্যাট্রিবিউটের মানকে প্রভাবিত করবে। উদাহরণস্বরূপ,DoorLockট্রেইটেরWrongCodeEntryLimitঅ্যাট্রিবিউটটি ।এটি লেখা যায় এবং অন্যান্য কমান্ড দ্বারা প্রভাবিত হয় । এর মানে হলো, আপনি ট্রেইটের
updateফাংশন ব্যবহার করে সরাসরি অ্যাট্রিবিউটের মান পরিবর্তন করতে পারেন, এবং কোনো কমান্ড পাঠানোর ফলেও অ্যাট্রিবিউটের মান পরিবর্তিত হতে পারে। উদাহরণস্বরূপ,FanControlTraitএরspeedSettingঅ্যাট্রিবিউটে সরাসরি লেখা যায়, কিন্তু এটিstepকমান্ড ব্যবহার করে পরিবর্তনযোগ্যও।
কোনো অ্যাট্রিবিউটের মান পরিবর্তন করতে আপডেট ফাংশন ব্যবহারের উদাহরণ।
এই উদাহরণটি দেখায় কিভাবে 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.sendBatchedCommands()মেথডটি কল করুন। -
sendBatchedCommands()ব্লকের বডির মধ্যে, ব্যাচে অন্তর্ভুক্ত করার জন্য কমান্ডগুলো নির্দিষ্ট করুন। - প্রেরিত কমান্ডগুলো সফল হয়েছে নাকি ব্যর্থ হয়েছে, তা দেখতে ফলাফল যাচাই করুন।
sendBatchedCommands() পদ্ধতিটি কল করুন
Home.sendBatchedCommands() মেথডটি কল করুন। নেপথ্যে, এই মেথডটি একটি বিশেষ ব্যাচ কনটেক্সটে একটি ল্যাম্বডা এক্সপ্রেশন সেট আপ করে।
home.sendBatchedCommands() {
ব্যাচ কমান্ড নির্দিষ্ট করুন
sendBatchedCommands() ব্লকের বডির মধ্যে ব্যাচেবল কমান্ডগুলো যুক্ত করুন। ব্যাচেবল কমান্ডগুলো হলো বিদ্যমান ডিভাইস এপিআই (Device API) কমান্ডগুলোর "ছায়া" সংস্করণ, যা একটি ব্যাচ প্রেক্ষাপটে ব্যবহার করা যায় এবং এগুলোর নামের শেষে Batchable প্রত্যয়টি যুক্ত থাকে। উদাহরণস্বরূপ, LevelControl ট্রেইটের moveToLevel() কমান্ডের একটি প্রতিরূপ রয়েছে যার নাম moveToLevelBatchable() ।
উদাহরণ:
val response1 = add(command1)
val response2 = add(command2)
ব্যাচ কনটেক্সটে সমস্ত কমান্ড যুক্ত হয়ে গেলে এবং এক্সিকিউশন কনটেক্সট থেকে বেরিয়ে গেলেই ব্যাচটি স্বয়ংক্রিয়ভাবে পাঠানো হয়।
প্রতিক্রিয়াগুলো DeferredResponse<T> অবজেক্টে ধারণ করা হয়।
DeferredResponse<T> ইনস্ট্যান্সগুলোকে যেকোনো ধরনের অবজেক্টে একত্রিত করা যেতে পারে, যেমন একটি Collection বা আপনার সংজ্ঞায়িত কোনো ডেটা ক্লাস। প্রতিক্রিয়াগুলো একত্রিত করার জন্য আপনি যে ধরনের অবজেক্ট বেছে নেন, sendBatchedCommands() সেটিই ফেরত দেয়। উদাহরণস্বরূপ, ব্যাচ কনটেক্সট একটি Pair এ দুটি DeferredResponse ইনস্ট্যান্স ফেরত দিতে পারে:
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() কল করা হয়, যা হয়: - সম্পাদিত কমান্ডের ফলাফল ফেরত দেয়, - অথবা, যদি ব্যাচ স্কোপটি সম্পূর্ণ না হয়ে থাকে বা কমান্ডটি অসফল হয়, তবে একটি ত্রুটি (error) দেখায়।
আপনার শুধুমাত্র sendBatchedCommands() ল্যাম্বডা স্কোপের বাইরেই ফলাফলগুলো যাচাই করা উচিত।
উদাহরণ
ধরুন, আপনি এমন একটি অ্যাপ তৈরি করতে চান যা ব্যাচিং এপিআই (Batching API) ব্যবহার করে একটি 'গুড নাইট' সিন সেট আপ করবে। এই সিনটি বাড়ির সমস্ত ডিভাইসকে রাতের জন্য, অর্থাৎ সবাই ঘুমিয়ে পড়ার পর, প্রস্তুত করে দেবে। এই অ্যাপটি বাতি নিভিয়ে দেবে এবং সামনের ও পেছনের দরজা লক করে দেবে।
কাজটি করার একটি উপায় হলো:
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()
}