লিভারেজ ডিভাইস আবিষ্কার

ডিসকভারি এপিআই এমন অ্যাপের দ্বারা ব্যবহার করার উদ্দেশ্যে করা হয়েছে যা ব্যবহারকারীর বাড়িতে উপস্থিত ডিভাইসগুলির উপর ভিত্তি করে অটোমেশন তৈরি করতে পারে। এটি রানটাইমে একটি অ্যাপের কাছে প্রকাশ করতে পারে যে অটোমেশনে ব্যবহারের জন্য প্রদত্ত কাঠামোতে কী বৈশিষ্ট্য এবং ডিভাইস উপস্থিত রয়েছে। উপরন্তু, এটি সংশ্লিষ্ট কমান্ড, গুণাবলী এবং ইভেন্টগুলি প্রকাশ করে, সেইসাথে মানগুলির পরিসীমা যা প্যারামিটার এবং ক্ষেত্রগুলির জন্য অনুমোদিত।

ডিসকভারি এপিআই অটোমেশন এপিআই দ্বারা সমর্থিত নয় এমন একটি কাঠামোতে বিদ্যমান যেকোন ডিভাইস বা বৈশিষ্ট্যকে উপেক্ষা করে, সেইসাথে FactoryRegistry নিবন্ধিত হয়নি এমন কোনো ডিভাইস বা বৈশিষ্ট্যকে উপেক্ষা করে। FactoryRegistry ব্যবহার করার বিষয়ে আরও তথ্যের জন্য একটি হোম ইন্সট্যান্স তৈরি করুন দেখুন।

API ব্যবহার করুন

ডিসকভারি এপিআই-এর মূলে রয়েছে HasCandidates ইন্টারফেস, যা একটি টাইপ হায়ারার্কির মূল যার মধ্যে রয়েছে Structure , Room এবং HomeDevice

HasCandidates ইন্টারফেস দুটি পদ্ধতি সংজ্ঞায়িত করে, candidates() এবং allCandidates() যা উভয়ই Flow অবজেক্ট প্রদান করে।

  • candidates() সত্তার জন্য অটোমেশন প্রার্থীদের একটি তালিকা তৈরি করে ( Structure , Room , HomeDevice )।

  • allCandidates() সত্তা এবং এর সমস্ত সন্তানদের জন্য অটোমেশন প্রার্থীদের একটি তালিকা তৈরি করে। এই পদ্ধতিটি Room দ্বারা সমর্থিত নয়।

হোম এপিআই দ্বারা প্রত্যাবর্তিত অন্যান্য Flow অবজেক্টের বিপরীতে, এগুলিতে একটি এককালীন স্ন্যাপশট থাকে।

উপলব্ধ প্রার্থীদের সর্বাধিক আপ-টু-ডেট তালিকা পেতে, বিকাশকারীকে প্রতিবার candidates() বা allCandidates() কে কল করতে হবে এবং Flow অবজেক্টে শুধুমাত্র collect() কল করতে পারবেন না। তদ্ব্যতীত, যেহেতু এই দুটি পদ্ধতি বিশেষভাবে সম্পদ-নিবিড়, সেগুলিকে প্রতি মিনিটে একাধিকবার কল করার ফলে ক্যাশে করা ডেটা ফেরত দেওয়া হবে, যা সেই মুহূর্তে প্রকৃত বর্তমান অবস্থাকে প্রতিফলিত নাও করতে পারে।

NodeCandidate ইন্টারফেস এই দুটি পদ্ধতি দ্বারা পাওয়া একটি প্রার্থী নোড প্রতিনিধিত্ব করে, এবং একটি শ্রেণীবিন্যাস মূল যা নিম্নলিখিত ইন্টারফেসগুলি অন্তর্ভুক্ত করে:

এবং নিম্নলিখিত ক্লাস:

অটোমেশন প্রার্থীদের সাথে কাজ করুন

বলুন আপনি একটি অ্যাপ লিখছেন যা ব্যবহারকারী-নির্দিষ্ট সময়ে স্মার্ট ব্লাইন্ডের সেট বন্ধ করার জন্য একটি অটোমেশন তৈরি করে। যাইহোক, আপনি জানেন না যে ব্যবহারকারীর এমন একটি ডিভাইস আছে যা WindowCovering বৈশিষ্ট্য সমর্থন করে এবং WindowCovering বা এর কোনো বৈশিষ্ট্য বা কমান্ড অটোমেশনে ব্যবহার করা যেতে পারে কিনা।

নিম্নলিখিত কোডটি ব্যাখ্যা করে কিভাবে ডিসকভারি এপিআই ব্যবহার করে candidates() পদ্ধতির আউটপুট ফিল্টার করে ফলাফল সংকুচিত করা যায় এবং নির্দিষ্ট ধরণের উপাদান (কাঠামো, ইভেন্ট, কমান্ড) চাওয়া হচ্ছে। শেষে, এটি সংগৃহীত উপাদানগুলির মধ্যে একটি অটোমেশন তৈরি করে।

import com.google.home.Structure
import com.google.home.automation.CommandCandidate
import com.google.home.automation.EventCandidate
import com.google.home.automation.Automation
import com.google.home.automation.DraftAutomation
import com.google.home.platform.Time
import java.time.LocalTime
import com.google.home.matter.standard.WindowCoveringTrait
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

fun createAutomationWithDiscoveryApiTimeStarter(
  structureName: String,
  scheduledTimeInSecond: Int,
): String = runBlocking {

  // get the Structure
  val structure = homeClient.structures().findStructureByName(structureName)

  // get an event candidate
  val clockTimeStarter =
    structure
      .allCandidates().first().firstOrNull {candidate ->
        candidate is EventCandidate && candidate.eventFactory == Time.ScheduledTimeEvent
      } as EventCandidate

  // retrieve the first 'DownOrClose' command encountered
  val downOrCloseCommand =
    structure.allCandidates().first().firstOrNull {
        candidate ->
      candidate is CommandCandidate
        && candidate.commandDescriptor == WindowCoveringTrait.DownOrCloseCommand
    } as CommandCandidate

  val blinds = ...

  // prompt user to select the WindowCoveringDevice
  ...

if (clockTimeStarter && downOrCloseCommand && blinds) {
  // Create the draft automation
  val draftAutomation: DraftAutomation = automation {
    name = ""
    description = ""
    isActive = true
    sequential {
      val mainStarter = starter<_>(structure, Time.ScheduledTimeEvent) {
          parameter(
            Time.ScheduledTimeEvent.clockTime(
              LocalTime.ofSecondOfDay(scheduledTimeInSecond.toLong())
            )
          )
        }
      action(blinds, WindowCoveringDevice) { command(WindowCoveringTrait.downOrClose())
    }
  }

  // Create the automation in the structure
  val automation = structure.createAutomation(draftAutomation)
  return@runBlocking automation.id.id
} else  ... //the automation cannot be created

নিচের উদাহরণটি একটি আলোর উজ্জ্বলতা স্তর সেট করার জন্য একটি অটোমেশন তৈরি করে যখন এটি চালু করা হয়।

import com.google.home.Structure
import com.google.home.automation.CommandCandidate
import com.google.home.automation.TraitAttributesCandidate
import com.google.home.automation.Automation
import com.google.home.automation.DraftAutomation
import com.google.home.matter.standard.LevelControl
import com.google.home.matter.standard.LevelControlTrait.MoveToLevelCommand
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOff.Companion.onOff
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import com.google.home.automation.equals

fun createAutomationWithDiscoveryApiDimLight(
  structureName: String,
): String = runBlocking {

  // get the Structure
  val structure: Structure = homeClient.structures().findStructureByName(structureName)

  /**
   * When I turn on the light, move the brightness level to 55
   */
  val allCandidates = structure.allCandidates().first()
  val dimmableLightDevice = structure.devices().list().first {it.has(OnOff) && it.has(LevelControl)}
  val starterCandidate =
    allCandidates
      .filterIsInstance<TraitAttributesCandidate>()
      .first { it.entity == dimmableLightDevice && it.trait == OnOff }

  val actionCandidate =
    allCandidates
      .filterIsInstance<CommandCandidate>()
      .first {it.entity == dimmableLightDevice && it.commandDescriptor == MoveToLevelCommand }

  if (starterCandidate && actionCandidate) {
    // Create the draft automation
    val draftAutomation: DraftAutomation = automation {
      sequential {
        val starter =  starter<_>(dimmableLightDevice, OnOffLightDevice, OnOff)
        condition { expression = starter.onOff equals true }
        action(dimmableLightDevice,DimmableLightDevice) {
          mapOf(MoveToLevelCommand.Request.CommandFields.level to 55u.toUByte())
        )
      }
    }

    // Create the automation in the structure
    val automation = structure.createAutomation(draftAutomation)
    return@runBlocking automation.id.id
    }
} else ... //the automation cannot be created

পূর্বশর্ত জন্য পরীক্ষা করুন

ডিসকভারি API আপনাকে জানতে দেয় যে একটি বৈশিষ্ট্য ব্যবহারের জন্য একটি পূর্বশর্ত অনুপস্থিত, যেমন একটি সদস্যতা বা একটি কাঠামোর ঠিকানা। এটি Candidate শ্রেণীর unsupportedReasons বৈশিষ্ট্য ব্যবহার করে এটি করে। এই অ্যাট্রিবিউটটি candidates() কলের সময় একটি UnsupportedCandidateReason রিজন দিয়ে তৈরি করা হয়। এবং যখন createAutomation() কল করা হয় তখন বৈধকরণ ত্রুটি বার্তাগুলিতে একই তথ্য উপস্থিত হয়।

উদাহরণ কারণ:

  • MissingStructureAddressSetup ব্যবহারকারীকে জানাতে দেয় যে Time বৈশিষ্ট্য ব্যবহার করার জন্য ঠিকানা সেটআপ প্রয়োজন। Google বাড়ির ঠিকানা পরিবর্তন ব্যাখ্যা করে যে কীভাবে একজন ব্যবহারকারী Google Home app (GHA) ব্যবহার করে কাঠামোর ঠিকানা লিখতে পারেন।
  • MissingPresenceSensingSetup ব্যবহারকারীকে জানাতে দেয় যে AreaPresenceState এবং AreaAttendanceState বৈশিষ্ট্যগুলি ব্যবহার করার জন্য উপস্থিতি সেটআপ প্রয়োজন৷
  • MissingSubscription ব্যবহারকারীকে জানাতে দেয় যে ObjectDetection বৈশিষ্ট্য ব্যবহার করার জন্য একটি Nest Aware সাবস্ক্রিপশন প্রয়োজন।

উদাহরণস্বরূপ, MissingStructureAddressSetup UnsupportedCandidateReason পরিচালনা করতে, আপনি আপনার অ্যাপে একটি টোস্ট দেখাতে চাইতে পারেন এবং ব্যবহারকারীকে কাঠামোর ঠিকানা প্রদান করার অনুমতি দেওয়ার জন্য GHA খুলতে পারেন:

val structure = homeManager.structures().list().single()
val allCandidates = structure.allCandidates().list().single()
val scheduledStarterCandidate = allCandidates.first { it is EventCandidate && it.eventFactory == ScheduledTimeEvent }
if (scheduledStarterCandidate.unsupportedReasons.any { it is MissingStructureAddressSetup }) {
  showToast("No Structure Address setup. Redirecting to GHA to set up an address.")
  launchChangeAddress(...)
}

পরামিতি যাচাই করুন

ডিসকভারি এপিআই সেই মানগুলি প্রদান করে যা একটি অ্যাট্রিবিউট, প্যারামিটার বা ইভেন্ট ফিল্ডের জন্য অনুমোদিত একটি Constraint ইনস্ট্যান্স আকারে। এই তথ্যটি অ্যাপ বিকাশকারীকে ব্যবহারকারীদের অবৈধ মান সেট করা থেকে আটকাতে দেয়৷

Constraint প্রতিটি উপশ্রেণীর স্বীকৃত মানগুলিকে উপস্থাপন করার নিজস্ব উপায় রয়েছে।

সারণী: Constraint প্রকার
সীমাবদ্ধতা ক্লাস স্বীকৃত মান প্রতিনিধিত্বকারী বৈশিষ্ট্য
বিটম্যাপ কন্সট্রেন্ট combinedBits
বুলিয়ান কনস্ট্রেন্ট
বাইট কন্সট্রেন্ট maxLength এবং minLength
Enum Constraint allowedSet
নম্বর রেঞ্জ কন্সট্রেন্ট lowerBound , upperBound , step এবং unit
NumberSet Constraint allowedSet এবং unit
স্ট্রিং কন্সট্রেন্ট allowedSet , disallowedSet , isCaseSensitive , maxLength , minLength , এবং regex
Struct Constraint fieldConstraints
তালিকার সীমাবদ্ধতা elementConstraint

সীমাবদ্ধতা ব্যবহার করুন

বলুন আপনি এমন একটি অ্যাপ লিখছেন যা একটি অটোমেশন তৈরি করে যা LevelControl বৈশিষ্ট্য সহ একটি ডিভাইসের স্তর সেট করে। নিম্নলিখিত উদাহরণটি দেখায় যে আপনি কীভাবে নিশ্চিত করবেন যে LevelControl বৈশিষ্ট্যের currentLevel অ্যাট্রিবিউট সেট করতে ব্যবহৃত মানটি স্বীকৃত সীমার মধ্যে রয়েছে।


import android.content.Context
import com.google.home.Home
import com.google.home.Structure
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.CommandCandidate
import com.google.home.automation.Condition
import com.google.home.automation.Constraint
import com.google.home.automation.Equals
import com.google.home.automation.EventCandidate
import com.google.home.automation.HasCandidates
import com.google.home.automation.Node
import com.google.home.automation.NodeCandidate
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.matter.standard.LevelControlTrait

// Filter the output of candidates() to find the TraitAttributesCandidate
// for the LevelControl trait.

val levelCommand =
        structure
          .allCandidates()
          .first()
          .firstOrNull { candidate ->
            candidate is CommandCandidate && candidate.command == LevelControlTrait.MoveToLevelCommand
 } as? CommandCandidate

var levelConstraint = null

// Get the NodeCandidate instance's fieldDetailsMap and
// retrieve the Constraint associated with the level parameter.
// In this case, it is a NumberRangeConstraint.
if (levelCommand != null) {
    levelConstraint =
      levelCommand.fieldDetailsMap[
        LevelControlTrait.MoveToLevelCommand.Request.CommandFields.level
        ]!!.constraint
}

...

// Test the value against the Constraint (ignoring step and unit)
if ( value in levelConstraint.lowerBound..levelConstraint.upperBound) {
   // ok to use the value
}

ডিভাইস API এবং আবিষ্কার API তুলনা করুন

আপনি Discovery API ব্যবহার না করেই ডিভাইসের ধরন, বৈশিষ্ট্য এবং তাদের বৈশিষ্ট্যগুলি আবিষ্কার করতে পারেন। ডিভাইস API ব্যবহার করে, আপনি আবিষ্কার করতে পারেন:

  1. DeviceType.Metadata.isPrimaryType() পদ্ধতি ব্যবহার করে প্রাথমিক ডিভাইসের ধরন ব্যবহারকারী ডেভেলপারকে নিয়ন্ত্রণের জন্য অনুমতি দিয়েছেন।
  2. HasTraits.has() পদ্ধতি ব্যবহার করে প্রতিটি ডিভাইস অটোমেশনের জন্য প্রয়োজনীয় সমস্ত বৈশিষ্ট্য সমর্থন করে কিনা।
  3. supports() পদ্ধতি ব্যবহার করে প্রতিটি বৈশিষ্ট্য অটোমেশনের প্রয়োজনীয় সমস্ত বৈশিষ্ট্য এবং কমান্ড সমর্থন করে কিনা।

এটা মনে রাখা গুরুত্বপূর্ণ যে আপনি যদি আবিষ্কার করতে ডিভাইস API ব্যবহার করেন, তাহলে আপনি নিম্নলিখিত ডিসকভারি API ক্ষমতাগুলি থেকে উপকৃত হবেন না:

  • অটোমেশন API দ্বারা সমর্থিত নয় এমন বৈশিষ্ট্যগুলি থেকে স্বয়ংক্রিয় ফিল্টারিং।
  • সীমাবদ্ধতা ব্যবহার করে এমন বৈশিষ্ট্য এবং পরামিতিগুলির জন্য একটি বৈধ মান নির্বাচন করার জন্য ব্যবহারকারীদের একটি বিকল্প প্রদান করার ক্ষমতা।