অ্যান্ড্রয়েডের জন্য ডোরবেল ডিভাইস গাইড

ডোরবেল ডিভাইস টাইপটি দুটি ট্রেইট ব্যবহার করে প্রয়োগ করা হয়েছে: PushAvStreamTransport , যা পুশ-ভিত্তিক প্রোটোকল ব্যবহার করে অডিও এবং ভিডিও স্ট্রিম পরিবহন পরিচালনা করে, এবং WebRtcLiveView , যা লাইভস্ট্রিম এবং টকব্যাক নিয়ন্ত্রণ করার ক্ষমতা প্রদান করে।

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

হোম এপিআই ডিভাইসের ধরন বৈশিষ্ট্য কোটলিন নমুনা অ্যাপ ব্যবহারের ক্ষেত্র

ডোরবেল

Google Doorbell Device

home.matter.6006.types.0113

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

প্রয়োজনীয় বৈশিষ্ট্য
গুগল পুশএভিস্ট্রিমট্রান্সপোর্ট
গুগল ওয়েবআরটিসিলাইভভিউ

ডোরবেল

একটি ডিভাইস সম্পর্কে প্রাথমিক তথ্য জানুন

BasicInformation ট্রেইটটিতে একটি ডিভাইসের জন্য ভেন্ডরের নাম, ভেন্ডর আইডি, প্রোডাক্ট আইডি, প্রোডাক্টের নাম (মডেলের তথ্য সহ), এবং সফটওয়্যার ভার্সনের মতো তথ্য অন্তর্ভুক্ত থাকে:

// Get device basic information. All general information traits are on the RootNodeDevice type.
    device.type(RootNodeDevice).first().standardTraits.basicInformation?.let { basicInformation ->
        println("vendorName ${basicInformation.vendorName}")
        println("vendorId ${basicInformation.vendorId}")
        println("productId ${basicInformation.productId}")
        println("productName ${basicInformation.productName}")
        println("softwareVersion ${basicInformation.softwareVersion}")
    }

ক্রমিক নম্বরটি নিন

ডিভাইসের সিরিয়াল নম্বর পেতে, ExtendedBasicInformation ট্রেইটের GetSerialNumber কমান্ডটি ব্যবহার করুন। উদাহরণটিতে serialNumber নামের একটি ভেরিয়েবলে সিরিয়াল নম্বরটি সংরক্ষণ করা দেখানো হয়েছে:

val basicInfo: ExtendedBasicInformation = device.getTrait(ExtendedBasicInformation)
val serialNumber = basicInfo.getSerialNumber().serialNumber

নির্ধারিত কথ্য ভাষা

LocalizationConfiguration ট্রেইটের setActiveLocale মেথড ব্যবহার করে ডিভাইসের সক্রিয় কথ্য ভাষা একটি নির্দিষ্ট লোকেলে (যেমন, "en_US") সেট করুন।

import java.util.Locale

// Convert underscore format (en_US) to Java Locale
fun String.toLocale(): Locale = Locale.forLanguageTag(this.replace('_', '-'))

// Setting the active language
val trait: LocalizationConfiguration = device.getTrait(LocalizationConfiguration)
val selectedLocale = "en_US" // Target locale string
trait.update {
    setActiveLocale(selectedLocale)
}

ডিভাইস ক্লাউড যোগাযোগের সর্বশেষ সময় পান

ডিভাইসটি সর্বশেষ কখন ক্লাউডের সাথে সংযোগ স্থাপন করেছিল তা জানতে, ExtendedGeneralDiagnostics ট্রেইটের lastContactTimestamp অ্যাট্রিবিউটটি ব্যবহার করুন:

fun getLastContactTimeStamp(trait: ExtendedGeneralDiagnostics): java.time.Instant {
  val timestamp = trait.lastContactTimestamp
  return Instant.ofEpochSecond(timestamp.toLong())
}

একটি ডিভাইসের সংযোগ পরীক্ষা করুন

একটি ডিভাইসের কানেক্টিভিটি আসলে ডিভাইস টাইপ লেভেলে চেক করা হয়, কারণ কিছু ডিভাইস একাধিক ডিভাইস টাইপ সাপোর্ট করে। যে স্টেটটি রিটার্ন করা হয়, তা হলো সেই ডিভাইসের সমস্ত ট্রেইটের কানেক্টিভিটি স্টেটগুলোর একটি সমন্বয়।

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

ইন্টারনেট সংযোগ না থাকলে, বিভিন্ন ধরনের ডিভাইসের ক্ষেত্রে PARTIALLY_ONLINE অবস্থা দেখা যেতে পারে। লোকাল রাউটিংয়ের কারণে Matter স্ট্যান্ডার্ড ট্রেইটগুলো অনলাইন থাকতে পারে, কিন্তু ক্লাউড-ভিত্তিক ট্রেইটগুলো অফলাইন থাকবে।

ডিভাইসটির আইপি অ্যাড্রেসটি নিন

ডিভাইসটির আইপি অ্যাড্রেস খুঁজে বের করতে, GeneralDiagnostics ট্রেইটের networkInterfaces অ্যাট্রিবিউটটি ব্যবহার করুন। অ্যাড্রেসগুলো বাইট অ্যারে হিসেবে ফেরত আসে, যেগুলোকে আপনি স্ট্যান্ডার্ড IPv4 বা IPv6 স্ট্রিং-এ ফরম্যাট করতে পারেন:

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

একটি লাইভস্ট্রিম শুরু করুন

একটি লাইভস্ট্রিম শুরু করতে, WebRtcLiveView ট্রেইটের startLiveView() মেথডে সেশন ডেসক্রিপশন প্রোটোকল (SDP) স্ট্রিংটি পাঠান, যা তিনটি মান সম্বলিত একটি WebRtcLiveViewTrait.StartLiveViewCommand.Response রিটার্ন করে:

  • অধিবেশনের জন্য এসডিপি।
  • সেশনের সময়কাল সেকেন্ডে।
  • সেশন আইডি, যা সেশনটির মেয়াদ বাড়াতে বা শেষ করতে ব্যবহার করা যেতে পারে।
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) {
 return cameraDevice.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first {
    it?.metadata?.sourceConnectivity?.connectivityState == ConnectivityState.ONLINE
  }

}

// Start the live view
suspend fun startCameraStream(trait: WebRtcLiveView, offerSdp: String) {
  val response = trait.startLiveView(offerSdp)
  // Response contains three fields (see below)
  return response
}
  ...

// This is used to manage the WebRTC connection
val peerConnection: RTCPeerConnection = ...

   ...

val startResponse = startCameraStream(sdp)
val answerSdp = startResponse?.answerSdp
val sessionDuration = startResponse?.liveSessionDurationSeconds
val mediaSessionId = startResponse?.mediaSessionId

peerConnection.setRemoteDescription(SessionDescription.Type.ANSWER,
                                    answerSdp)

একটি লাইভস্ট্রিম প্রসারিত করুন

লাইভস্ট্রিমের একটি পূর্বনির্ধারিত সময়কাল থাকে, যার পরে তা শেষ হয়ে যায়। একটি সক্রিয় স্ট্রিমের সময়কাল বাড়ানোর জন্য, WebRtcLiveView.extendLiveView() পদ্ধতিটি ব্যবহার করে একটি এক্সটেনশন অনুরোধ পাঠান:

// Assuming camera stream has just been started
suspend fun scheduleExtension(trait: WebRtcLiveView, mediaSessionId: String, liveSessionDurationSeconds: UShort ) {
  delay(liveSessionDurationSeconds - BUFFER_SECONDS * 1000)
  val response = trait.extendLiveView(mediaSessionId)
  // returns how long the session will be live for
  return response.liveSessionDurationSeconds
}

টকব্যাক শুরু এবং বন্ধ করুন

টকব্যাক শুরু করতে, WebRtcLiveView ট্রেইটের startTalkback() মেথডটি কল করুন। বন্ধ করতে, stopTalkback() ব্যবহার করুন।

// Make sure camera stream is on
suspend fun setTalkback(isOn: Boolean, trait: WebRtcLiveView, mediaSessionId: String) {
  if(isOn) {
    trait.startTalkback(mediaSessionId)
  } else {
    trait.stopTalkback(mediaSessionId)
  }
}

রেকর্ডিং ক্ষমতা চালু এবং বন্ধ করুন

ক্যামেরার রেকর্ডিং ক্ষমতা চালু করতে, PushAvStreamTransport ট্রেইটের setTransportStatus() মেথডে TransportStatusEnum.Active পাস করুন। রেকর্ডিং ক্ষমতা বন্ধ করতে, এতে TransportStatusEnum.Inactive পাস করুন। নিম্নলিখিত উদাহরণে, আমরা এই কলগুলোকে একটি একক কলে একত্রিত করেছি যা রেকর্ডিং ক্ষমতা টগল করতে একটি Boolean ব্যবহার করে:

// Start or stop recording for all connections.
suspend fun setCameraRecording(trait: PushAvStreamTransport, isOn: Boolean) {
  if(isOn) {
    trait.setTransportStatus(TransportStatusEnum.Active)
  } else {
    trait.setTransportStatus(TransportStatusEnum.Inactive)
  }
}

ক্যামেরার রেকর্ডিং ক্ষমতা চালু বা বন্ধ করা আর ক্যামেরার ভিডিও চালু বা বন্ধ করা একই জিনিস। যখন ক্যামেরার ভিডিও চালু থাকে, তখন এটি রেকর্ডিং করতে থাকে (বিভিন্ন ঘটনা এবং সংশ্লিষ্ট ক্লিপের উদ্দেশ্যে)।

যখন রেকর্ডিং ক্ষমতা নিষ্ক্রিয় থাকে (ক্যামেরার ভিডিও বন্ধ থাকে):

  • ডিভাইস টাইপের connectivityState অনুযায়ী ক্যামেরাটি তখনও অনলাইন হিসেবে দেখাতে পারে।
  • লাইভস্ট্রিমটি অ্যাক্সেস করা যাচ্ছে না, এবং ক্যামেরাও কোনো ক্লাউড ইভেন্ট শনাক্ত করতে পারছে না।

রেকর্ডিং ক্ষমতা সক্রিয় আছে কিনা তা পরীক্ষা করুন।

ক্যামেরার রেকর্ডিং ক্ষমতা চালু আছে কিনা তা নির্ধারণ করতে, কোনো সংযোগ সক্রিয় আছে কিনা তা পরীক্ষা করুন। নিম্নলিখিত উদাহরণটি এই কাজটি করার জন্য দুটি ফাংশন সংজ্ঞায়িত করে:

// Get the on/off state
suspend fun onOffState(pushAvStreamTransport: PushAvStreamTransport) {
  return pushAvStreamTransport
    .currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}

// Check if the camera's recording capability is enabled
fun PushAvStreamTransport.recordModeActive(): Boolean {
  return currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}

যাচাই করার আরেকটি উপায় হলো প্রেডিকেট সহ findTransport() ফাংশন ব্যবহার করা:

// Fetch the current connections
suspend fun queryRecordModeState(trait: PushAvStreamTransport) {
  return trait.findTransport().let {
      it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active
    }
}

ব্যাটারি সেটিংস

হোম এপিআই-এর মাধ্যমে ব্যাটারির বিভিন্ন সেটিংস নিয়ন্ত্রণ করা যায়।

ব্যাটারি ব্যবহারের পছন্দ সেট করুন

এনার্জি ব্যালেন্স সেট করার মাধ্যমে আপনি একটি ডিভাইসের জন্য ব্যাটারি লাইফ এবং পারফরম্যান্সের মধ্যে ভারসাম্য নির্ধারণ করতে পারেন। আপনি "এক্সটেন্ডেড," "ব্যালেন্সড," এবং "পারফরম্যান্স"-এর মতো বিভিন্ন ব্যাটারি প্রোফাইল তৈরি করতে এবং সেগুলোর মধ্যে পরিবর্তন করতে পারেন।

এই ফিচারটি EnergyPreference ট্রেইটের currentEnergyBalance অ্যাট্রিবিউট আপডেট করার মাধ্যমে প্রয়োগ করা হয়। অ্যাট্রিবিউটটি একটি পূর্ণসংখ্যা ইনডেক্স গ্রহণ করে, যা ডিভাইসের energyBalances তালিকায় সংজ্ঞায়িত একটি নির্দিষ্ট প্রোফাইলের সাথে সঙ্গতিপূর্ণ (উদাহরণস্বরূপ, EXTENDED এর জন্য 0 , BALANCED এর জন্য 1 , এবং PERFORMANCE জন্য 2 )।

currentEnergyBalance এর মান null বোঝা যায় যে ডিভাইসটি একটি কাস্টম প্রোফাইল ব্যবহার করছে। এটি একটি পঠন-যোগ্য অবস্থা।

নিচে currentEnergyBalance অ্যাট্রিবিউটটি যে ধরনের স্ট্রাকচার ব্যবহার করবে তার একটি উদাহরণ দেখানো হলো, এবং এর পরে অ্যাট্রিবিউটটি ব্যবহার করা প্রকৃত কোড স্নিপেটটি দেওয়া হলো।

// Example energyBalances list
energy_balances: [
  {
    step: 0,
    label: "EXTENDED"
  },
  {
    step: 50,
    label: "BALANCED"
  },
  {
    step: 100,
    label: "PERFORMANCE"
  }
]
// The index parameter must be within the UByte range (0-255).
suspend fun setEnergyBalance(trait: EnergyPreference, index: Int) {
  trait.update { setCurrentEnergyBalance(index.toUByte()) }
}

// Setting the battery usage to more recording ie performance
setEnergyBalance(energyPreference, 2)

স্বয়ংক্রিয় ব্যাটারি সেভার চালু করুন

এই ফিচারটি কনফিগার করতে, EnergyPreference ট্রেইটের currentLowPowerModeSensitivity অ্যাট্রিবিউটটি আপডেট করুন। এই অ্যাট্রিবিউটটি একটি সেনসিটিভিটি লেভেল নির্বাচন করার জন্য একটি ইনডেক্স ব্যবহার করে, যেখানে 0 সাধারণত Disabled এবং 1 Enabled বা Automatic বোঝায়।

suspend fun setAutomaticBatterySaver(enable: Boolean, trait: EnergyPreference) {
  // 0 is Disabled, 1 is Enabled
  val value = if (enable) 1.toUByte() else 0.toUByte()
  trait.update { setCurrentLowPowerModeSensitivity(value) }
}

ব্যাটারি চার্জিং অবস্থা জানুন

ডিভাইসটির বর্তমান চার্জিং অবস্থা (চার্জ হচ্ছে, সম্পূর্ণ চার্জ হয়েছে, বা চার্জ হচ্ছে না) জানতে, PowerSource ট্রেইটের batChargeState অ্যাট্রিবিউটটি ব্যবহার করুন।

// Get the battery charging state
val batteryChargeState = powerSource.batChargeState

when (batteryChargeState) {
    PowerSourceTrait.BatChargeStateEnum.IsCharging -> "Charging"
    PowerSourceTrait.BatChargeStateEnum.IsAtFullCharge -> "Full"
    PowerSourceTrait.BatChargeStateEnum.IsNotCharging -> "Not Charging"
    else -> "Unknown"
}

ব্যাটারির লেভেল জানুন

বর্তমান ব্যাটারি লেভেল জানতে, PowerSource ট্রেইটের batChargeLevel অ্যাট্রিবিউটটি ব্যবহার করুন। লেভেলটি হয় OK , Warning (নিম্ন), অথবা Critical

// Get the battery charge level
val batteryLevel = powerSourceTrait.batChargeLevel

when (batteryLevel) {
    PowerSourceTrait.BatChargeLevelEnum.OK -> "OK"
    PowerSourceTrait.BatChargeLevelEnum.Warning -> "Warning"
    PowerSourceTrait.BatChargeLevelEnum.Critical -> "Critical"
    else -> "Unknown"
}

শক্তির উৎসটি নিন

ডিভাইসটি কোন পাওয়ার সোর্স ব্যবহার করছে তা নির্ধারণ করতে, PowerSource ট্রেইটের BatPresent এবং wiredPresent অ্যাট্রিবিউটগুলো ব্যবহার করুন।

  val trait: PowerSource
  val isWired = trait.wiredPresent
  val hasBattery = trait.batPresent

অডিও সেটিংস

হোম এপিআই-এর মাধ্যমে বিভিন্ন অডিও সেটিংস নিয়ন্ত্রণ করা যায়।

মাইক্রোফোন চালু বা বন্ধ করুন

ডিভাইসের মাইক্রোফোন চালু বা বন্ধ করতে, বিল্ট-ইন setMicrophoneMuted Kotlin ফাংশনটি ব্যবহার করে CameraAvStreamManagement ট্রেইটের microphoneMuted অ্যাট্রিবিউটটি আপডেট করুন:

// Turn the device's microphone on or off
suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setMicrophoneMuted(disableMicrophone) }
}

অডিও রেকর্ডিং চালু বা বন্ধ করুন

ডিভাইসটির জন্য অডিও রেকর্ডিং চালু বা বন্ধ করতে, বিল্ট-ইন setRecordingMicrophoneMuted Kotlin ফাংশনটি ব্যবহার করে CameraAvStreamManagement ট্রেইটের recordingMicrophoneMuted অ্যাট্রিবিউটটি আপডেট করুন:

// Turn audio recording on or off for the device
suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setRecordingMicrophoneMuted(disableAudioRecording) }
}

স্পিকারের ভলিউম সামঞ্জস্য করুন।

ডিভাইসের স্পিকার ভলিউম অ্যাডজাস্ট করতে, বিল্ট-ইন setSpeakerVolumeLevel Kotlin ফাংশনটি ব্যবহার করে CameraAvStreamManagement ট্রেইটের speakerVolumeLevel অ্যাট্রিবিউটটি আপডেট করুন:

// Adjust the camera speaker volume
suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) {
  trait.update { setSpeakerVolumeLevel(volume.toUbyte()) }
}

কার্যকলাপ অঞ্চলের সেটিংস

ZoneManagement ট্রেইটটি ক্যামেরা এবং ডোরবেল ডিভাইসে কাস্টম রিজিওন অফ ইন্টারেস্ট (অ্যাক্টিভিটি জোন) পরিচালনার জন্য একটি ইন্টারফেস প্রদান করে। এই জোনগুলি ডিভাইসের ফিল্ড অফ ভিউ-এর মধ্যে নির্দিষ্ট এলাকায় ইভেন্ট ডিটেকশন (যেমন ব্যক্তি বা যানবাহনের গতি) ফিল্টার করতে ব্যবহৃত হয়।

অ্যাক্টিভিটি জোনগুলি ব্যবহারকারী একটি পার্টনার অ্যাপ্লিকেশনের মধ্যে কনফিগার করেন, যা তাদের ক্যামেরার ফিল্ড অফ ভিউ-এর নির্দিষ্ট এলাকার উপর জোন আঁকতে দেয়। এই ব্যবহারকারী-সংজ্ঞায়িত জোনগুলি পরবর্তীতে এই ট্রেইট দ্বারা ব্যবহৃত স্ট্রাকচারগুলিতে রূপান্তরিত হয়। অ্যাক্টিভিটি জোনগুলি কীভাবে কাজ করে সে সম্পর্কে আরও তথ্যের জন্য, "অ্যাক্টিভিটি জোন সেট আপ এবং ব্যবহার করুন" দেখুন।

অ্যাক্টিভিটি জোন সাধারণত 2D কার্টেসিয়ান স্থানাঙ্ক ব্যবহার করে সংজ্ঞায়িত করা হয়। এই ট্রেইটটি ভার্টেক্সগুলোর জন্য TwoDCartesianVertexStruct এবং জোন সংজ্ঞার (নাম, ভার্টেক্সসমূহ, রঙ এবং ব্যবহার) জন্য TwoDCartesianZoneStruct প্রদান করে।

কার্যকলাপ অঞ্চলগুলি পরীক্ষা করুন

অ্যাক্টিভিটি জোনগুলো প্রদর্শন করতে, ZoneManagement ট্রেইটের zones অ্যাট্রিবিউটটি চেক করুন।

// 1. Obtain the trait flow from the device
private val zoneManagementFlow: Flow =
  device.type(CAMERA_TYPE).flatMapLatest { it.trait(ZoneManagement) }

// 2. Map the flow to the list of zone structures
val activityZones: Flow<List<ZoneManagementTrait.ZoneInformationStruct>> =
  zoneManagementFlow.map { trait ->
    trait.zones ?: emptyList()
  }

একটি কার্যকলাপ অঞ্চল যোগ করুন

একটি নতুন জোন তৈরি করতে, createTwoDCartesianZone কমান্ডটি ব্যবহার করুন। এই কমান্ডটি একটি TwoDCartesianZoneStruct গ্রহণ করে, যা জোনটির নাম, ভার্টেক্স, রঙ এবং ব্যবহার নির্ধারণ করে।

নিম্নলিখিত উদাহরণে দেখানো হয়েছে কিভাবে গতি শনাক্তকরণের জন্য ব্যবহৃত, স্যামন (#F439A0) রঙের চারটি ভার্টেক্স সহ 'ফ্রন্ট পোর্চ' নামের একটি জোন তৈরি করতে হয়।

import com.google.home.google.ZoneManagement
import com.google.home.google.ZoneManagementTrait
import com.google.home.matter.serialization.OptionalValue

/**
 * Creates a custom activity zone named "Front Porch" with a salmon color
 * configured for motion detection.
 */
suspend fun createFrontPorchZone(zoneManagement: ZoneManagement) {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are typically scaled to a maximum defined by the device's twoDCartesianMax attribute.
  val vertices =
    listOf(
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260u, y = 422u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049u, y = 0u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 0u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048u, y = 950u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630u, y = 1349u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880u, y = 2048u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0u, y = 2048u),
      ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638u, y = 1090u)
    )

  // 2. Define the zone structure
  val newZone =
    ZoneManagementTrait.TwoDCartesianZoneStruct(
      name = "Front Porch",
      vertices = vertices,
      // Usage defines what the zone filters (for example, Motion, Person, Vehicle)
      use = listOf(ZoneManagementTrait.ZoneUseEnum.Motion),
      // Color is typically a hex string (for example, Salmon/Pink)
      color = OptionalValue.present("#F439A0")
    )

  try {
    // 3. Execute the command to add the zone to the device
    zoneManagement.createTwoDCartesianZone(newZone)
    println("Successfully created activity zone.")
  } catch (e: Exception) {
    // Handle potential HomeException or Timeout
    println("Failed to create activity zone: ${e.message}")
  }
}

একটি কার্যকলাপ অঞ্চল আপডেট করুন

বিদ্যমান কোনো জোন আপডেট করতে, updateTwoDCartesianZone কমান্ডটি ব্যবহার করুন। এই কমান্ডটির জন্য zoneId এবং আপডেট করা TwoDCartesianZoneStruct প্রয়োজন।

private suspend fun ZoneManagement.updateZone(
  zoneId: UShort,
  zone: ZoneManagementTrait.TwoDCartesianZoneStruct
) {
  // Execute the command to update the zone
  this.updateTwoDCartesianZone(zoneId = zoneId, zone = zone)
}

একটি কার্যকলাপ অঞ্চল মুছে ফেলুন

কোনো জোন অপসারণ করতে, নির্দিষ্ট zoneId সহ removeZone কমান্ডটি ব্যবহার করুন।

private suspend fun ZoneManagement.deleteZone(zoneId: UShort) {
  // Execute the command to remove the zone
  this.removeZone(zoneId = zoneId)
}

শব্দ ইভেন্ট ট্রিগার

AvStreamAnalysis ট্রেইটটি ক্যামেরা এবং ডোরবেল ডিভাইসে ইভেন্ট ডিটেকশন ট্রিগারগুলো পরিচালনা করার জন্য একটি ইন্টারফেস প্রদান করে। দৃষ্টি-ভিত্তিক ট্রিগারগুলো (যেমন মানুষ বা যানবাহন) জোন-নির্দিষ্ট হতে পারলেও, শব্দ-সম্পর্কিত ট্রিগারগুলো সাধারণত ডিভাইস-স্তরের কনফিগারেশন হয়ে থাকে।

EventTriggerTypeEnum এর সাথে শব্দ শনাক্তকরণের জন্য নিম্নলিখিত ট্রিগার প্রকারগুলি উপলব্ধ রয়েছে:

মোড Enum মান বর্ণনা
শব্দ Sound সাধারণ শব্দ সনাক্তকরণ।
কথা বলা ব্যক্তি PersonTalking বক্তৃতা শনাক্ত করে।
কুকুরের ঘেউ ঘেউ DogBark কুকুরের ডাক শনাক্ত করে।
কাঁচ ভাঙা GlassBreak কাচ ভাঙার শব্দ শনাক্ত করে।
ধোঁয়া অ্যালার্ম SmokeAlarm ধোঁয়ার অ্যালার্ম শনাক্ত করে, যা প্রায়শই T3 শ্রবণযোগ্য প্যাটার্ন (তিনটি ছোট বিপের পর একটি বিরতি) দ্বারা চেনা যায়।
CO অ্যালার্ম CoAlarm কার্বন মনোক্সাইড (CO) অ্যালার্ম শনাক্ত করে, যা সাধারণত T4 শ্রবণযোগ্য প্যাটার্ন (চারটি ছোট বীপের পর একটি বিরতি) দ্বারা চেনা যায়।

শব্দ সনাক্তকরণের অবস্থা পরীক্ষা করুন

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

Kotlin Flows ব্যবহার করে Android ডেভেলপমেন্টের ক্ষেত্রে, আপনি সাধারণত HomeDevice এর AvStreamAnalysis ট্রেইটটি দেখতে পাবেন।

// Example structure to store the
data class EventTriggerAttribute(val type: EventTriggerTypeEnum, val enabled: Boolean)

// 1. Obtain the trait flow from the device
private val avStreamAnalysisFlow: Flow<AvStreamAnalysis> =
  device.traitFromType(AvStreamAnalysis, CAMERA_TYPES.first { device.has(it) })

// 2. Map the flow to a list of sound event attributes
val soundEventTriggersState: Flow<List<EventTriggerAttribute>> =
  avStreamAnalysisFlow.map { trait ->
    // Get raw lists from the trait attributes
    val supported = trait.supportedEventTriggers ?: emptyList()
    val enabled = trait.enabledEventTriggers ?: emptyList()

    // Define sound-specific triggers to filter for
    val soundTypes = setOf(
      EventTriggerTypeEnum.Sound,
      EventTriggerTypeEnum.PersonTalking,
      EventTriggerTypeEnum.DogBark,
      EventTriggerTypeEnum.GlassBreak,
      EventTriggerTypeEnum.SmokeAlarm,
      EventTriggerTypeEnum.CoAlarm,
    )

    // Filter and associate status
    supported
      .filter { soundTypes.contains(it) }
      .map { type ->
        EventTriggerAttribute(
          type = type,
          enabled = enabled.contains(type)
        )
      }
  }

সক্রিয় ট্রিগারগুলির সেট আপডেট করুন

সক্রিয় ট্রিগারগুলির সেট আপডেট করতে, SetOrUpdateEventDetectionTriggers কমান্ডটি ব্যবহার করুন, যা EventTriggerEnablement স্ট্রাকচারগুলির একটি তালিকা গ্রহণ করে।

private suspend fun AvStreamAnalysis.updateEventTriggers(
  eventTriggers: List<EventTriggerAttribute>
) {
  val toUpdate = eventTriggers.map {
    EventTriggerEnablement(
      eventTriggerType = it.type,
      enablementStatus = if (it.enabled) {
        EnablementStatusEnum.Enabled
      } else {
        EnablementStatusEnum.Disabled
      },
    )
  }

  // Execute the command on the device
  setOrUpdateEventDetectionTriggers(toUpdate)
}

রেকর্ডিং মোড

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

RecordingModeEnum উপলব্ধ রেকর্ডিং কৌশলগুলি নির্ধারণ করে:

মোড Enum মান বর্ণনা
প্রতিবন্ধী Disabled রেকর্ডিং সম্পূর্ণরূপে নিষ্ক্রিয় করা হয়েছে। এটি মূলত পুরোনো ডিভাইসগুলোতে ব্যবহৃত হয়।
সিভিআর (ধারাবাহিক ভিডিও রেকর্ডিং) Cvr ভিডিও ২৪x৭ রেকর্ড করা হয়। এর জন্য সাবস্ক্রিপশন প্রয়োজন (যেমন, Google Home Premium )।
ইবিআর (ইভেন্ট ভিত্তিক রেকর্ডিং) Ebr কোনো ঘটনা (ব্যক্তি, গতি) ঘটলে রেকর্ডিং শুরু হয়। ভিডিওর দৈর্ঘ্য ঘটনার সময়কাল এবং সাবস্ক্রিপশনের উপর নির্ভর করে।
ETR (ইভেন্ট ট্রিগারড রেকর্ডিং) Etr ইভেন্টের দ্বারা চালু হওয়া সংক্ষিপ্ত প্রিভিউ রেকর্ডিং (উদাহরণস্বরূপ, ১০ সেকেন্ড)।
সরাসরি দেখুন LiveView রেকর্ডিং বন্ধ করা হয়েছে, কিন্তু ব্যবহারকারীরা এখনও লাইভস্ট্রিমটি দেখতে পারবেন।
স্থির চিত্র Images কোনো ঘটনা ঘটলে ভিডিওর পরিবর্তে স্ন্যাপশট রেকর্ড করা হয়।

রেকর্ডিং মোডগুলি পরীক্ষা করুন

বর্তমান রেকর্ডিং কনফিগারেশন দেখতে, RecordingMode ট্রেইটের অ্যাট্রিবিউটগুলো পরীক্ষা করুন:

// 1. Obtain the trait flow from the device
private val recordingModeTraitFlow: Flow =
    device.traitFromType(RecordingMode, CAMERA_TYPES.first { device.has(it) })

// 2. Map the flow to recording mode options
data class RecordingModeOptions(
    val recordingMode: RecordingModeTrait.RecordingModeEnum,
    val index: Int,
    val available: Boolean,
    val readableString: String,
)

private val recordingModeOptions: Flow<List> =
    recordingModeTraitFlow.map { trait ->
        val supported = trait.supportedRecordingModes?.map { it.recordingMode } ?: emptyList()
        val available = trait.availableRecordingModes?.map { it.toInt() } ?: emptyList()

        supported.withIndex().map { (index, mode) ->
            RecordingModeOptions(
                recordingMode = mode,
                index = index,
                available = available.contains(index),
                readableString = mode.toReadableString(),
            )
        }
    }

রেকর্ডিং মোড পরিবর্তন করুন

আপডেট করার আগে নিশ্চিত করুন যে, supportedRecordingModes অ্যাট্রিবিউট থেকে নির্বাচিত ইনডেক্সটি availableRecordingModes অ্যাট্রিবিউটে উপস্থিত আছে।

নির্বাচিত মোড আপডেট করতে, setSelectedRecordingMode ফাংশনটি ব্যবহার করুন এবং নির্বাচিত মোডের ইন্ডেক্সটি পাস করুন:

private suspend fun RecordingMode.updateRecordingMode(index: Int) {
    // Execute the command to update the selected mode
    this.setSelectedRecordingMode(index.toUByte())
}

অন্যান্য সেটিংস

হোম এপিআই-এর মাধ্যমে আরও বিভিন্ন সেটিংস নিয়ন্ত্রণ করা যায়।

নাইট ভিশন চালু বা বন্ধ করুন

ক্যামেরার জন্য নাইট ভিশন চালু বা বন্ধ করতে, TriStateAutoEnum ব্যবহার করে বিল্ট-ইন setNightVision Kotlin ফাংশনটির মাধ্যমে CameraAvStreamManagement ট্রেইটের nightVision অ্যাট্রিবিউটটি আপডেট করুন:

// Turn night vision on
cameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On)
}

// Turn night vision off
CameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off)
}

স্ট্যাটাস এলইডি-র উজ্জ্বলতা পরিবর্তন করুন

স্ট্যাটাস LED-এর উজ্জ্বলতা পরিবর্তন করতে, ThreeLevelAutoEnum ব্যবহার করে বিল্ট-ইন setStatusLightBrightness Kotlin ফাংশনটির মাধ্যমে CameraAvStreamManagement ট্রেইটের statusLightBrightness অ্যাট্রিবিউটটি আপডেট করুন:

// Set the LED brightness to high
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High)
}

// Set the LED brightness to low
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low)
}

ক্যামেরা ভিউপোর্ট পরিবর্তন করুন

ক্যামেরা ভিউপোর্টটি "জুম এবং নেস্ট ক্যামেরা ভিডিও সাপোর্ট উন্নত করুন" আর্টিকেলে বর্ণিত জুম এবং ক্রপ ফিচারের মতোই।

ভিউপোর্টটি একটি ViewportStruct মধ্যে সংজ্ঞায়িত করা হয়েছে, যেটিতে চারটি মান রয়েছে, যা ভিউপোর্টের স্থানাঙ্ক হিসেবে ব্যবহৃত হয়। স্থানাঙ্কগুলো নিম্নরূপে সংজ্ঞায়িত করা হয়েছে:

(x1,y1) -- (x2,y1)
   |          |
(x1,y2) -- (x2,y2)

ViewportStruct এর মান নির্ধারণ করা একটি অ্যাপের UI এবং ক্যামেরা বাস্তবায়নের উপর নির্ভর করে। একেবারে প্রাথমিক স্তরে, ক্যামেরা ভিডিওর ভিউপোর্ট সেট করতে, বিল্ট-ইন setViewport Kotlin ফাংশনটি ব্যবহার করে CameraAvStreamManagement ট্রেইটের viewport অ্যাট্রিবিউটকে একটি ViewportStruct দিয়ে আপডেট করুন:

cameraAvStreamManagement
  .update { setViewport(
    CameraAvStreamManagementTrait.ViewportStruct(
      x1 = horizontalRange.rangeStart.roundToInt().toUShort(),
      x2 = horizontalRange.rangeEnd.roundToInt().toUShort(),
      y1 = verticalRange.rangeStart.roundToInt().toUShort(),
      y2 = verticalRange.rangeEnd.roundToInt().toUShort(),
    )
) }

অ্যানালিটিক্স চালু বা বন্ধ করুন

প্রতিটি ডিভাইস স্বতন্ত্রভাবে গুগল হোম ক্লাউডে বিস্তারিত অ্যানালিটিক্স ডেটা পাঠানোর জন্য সম্মতি জানাতে পারে ( হোম এপিআই-এর জন্য ক্লাউড মনিটরিং দেখুন)।

কোনো ডিভাইসের জন্য অ্যানালিটিক্স চালু করতে, ExtendedGeneralDiagnosticsTrait এর analyticsEnabled প্রপার্টিটি true তে সেট করুন। আপনি যখন analyticsEnabled সেট করেন, তখন logUploadEnabled নামক আরেকটি প্রপার্টি স্বয়ংক্রিয়ভাবে true তে সেট হয়ে যায়, যা অ্যানালিটিক্স লগ ফাইলগুলোকে গুগল হোম ক্লাউডে আপলোড করার সুযোগ দেয়।

// Enable analytics
extendedGeneralDiagnostics.update {
  setAnalyticsEnabled(true)
}

// Disable analytics
extendedGeneralDiagnostics.update {
  setAnalyticsEnabled(false)
}

পরিবহন এবং রেকর্ডিং কনফিগারেশন

এই বিভাগে ক্যামেরা স্ট্রিমিংয়ের মান এবং ইভেন্ট ট্রিগারিং সম্পর্কিত সেটিংস আলোচনা করা হয়েছে। এই সেটিংসগুলো PushAvStreamTransport ট্রেইট দ্বারা পরিচালিত হয়।

পরিবহন সেটিংস পড়ুন

এই অংশে দেখানো হয়েছে কীভাবে একটি ক্যামেরা বা ডোরবেল ডিভাইস থেকে বর্তমান কনফিগারেশন পুনরুদ্ধার করতে হয়। এটি PushAvStreamTransport ট্রেইটটি ফেচ করে, রেকর্ডিংয়ের জন্য ব্যবহৃত নির্দিষ্ট কানেকশনটি খুঁজে বের করে এবং তারপর ব্যান্ডউইথ কোয়ালিটি, ওয়েক-আপ সেনসিটিভিটি ও ম্যাক্সিমাম ইভেন্ট লেংথের বর্তমান মানগুলো এক্সট্র্যাক্ট করে।

val trait: PushAvStreamTransport = device.getTrait(PushAvStreamTransport)
val connections = trait.findTransport().transportConfigurations

// Locate the connection designated for recording
val recordingConnection = connections.firstOrNull {
    it.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording
}

val options = recordingConnection?.transportOptions?.getOrNull()

// 1. Bandwidth Quality (Video Stream ID)
val videoStreamId = options?.videoStreamId?.getOrNull()

// 2. Wake-up Sensitivity (Motion Sensitivity)
val wakeUpSensitivity = options?.triggerOptions?.motionSensitivity?.getOrNull()

// 3. Max Event Length (Motion Trigger Time Control)
val maxEventLength = options?.triggerOptions?.motionTimeControl?.getOrNull()?.maxDuration

পরিবহন সেটিংস আপডেট করুন

এই অংশে দেখানো হয়েছে কীভাবে ট্রান্সপোর্ট সেটিংস পরিবর্তন করতে হয়। এটি নতুন মানগুলো সহ একটি নতুন TransportOptionsStruct তৈরি করে এবং তারপর modifyPushTransport কমান্ড ব্যবহার করে এই আপডেট করা সেটিংসগুলো ডিভাইসে ফেরত পাঠায়, যা পূর্ববর্তী ধাপে পাওয়া রেকর্ডিং সংযোগে প্রয়োগ করা হয়।

এই সেটিংস পরিবর্তন করতে, TransportOptionsStruct সহ modifyPushTransport কমান্ডটি ব্যবহার করুন।

val toUpdate = TransportOptionsStruct(
    videoStreamId = OptionalValue.present(2u), // e.g., Max Quality
    triggerOptions = TransportTriggerOptionsStruct(
        motionSensitivity = OptionalValue.present(5u), // e.g., Medium
        motionTimeControl = OptionalValue.present(
            TransportMotionTriggerTimeControlStruct(maxDuration = 30u)
        )
    )
)

if (recordingConnection != null) {
    trait.modifyPushTransport(
        connectionId = recordingConnection.connectionId,
        transportOptions = toUpdate
    )
}

ব্যান্ডউইথের গুণমান নির্ধারণ করুন

TransportOptionsStruct এর videoStreamId প্রপার্টিটি একটি নির্দিষ্ট ভিডিও স্ট্রিম কনফিগারেশনকে নির্দেশ করে।

সমর্থিত ভিডিও স্ট্রিমগুলো পেতে, ডিভাইসটির CameraAvStreamManagement ট্রেইট থেকে allocatedVideoStreams অ্যাট্রিবিউটটি দেখুন, যা VideoStreamStructs এর একটি তালিকা।

ডিভাইস জেগে ওঠার সংবেদনশীলতা সামঞ্জস্য করুন

TransportTriggerOptionsStruct এর motionSensitivity প্রপার্টিটি নিম্নলিখিত মানগুলির সাথে সঙ্গতিপূর্ণ:

লেবেল মান (ইউবাইট)
নিম্ন ১ইউ
মাঝারি ৫ইউ
উচ্চ ১০ইউ

সর্বোচ্চ ইভেন্টের দৈর্ঘ্য সামঞ্জস্য করুন

TransportMotionTriggerTimeControlStruct এর maxDuration প্রপার্টিটি নিম্নলিখিত সময়কালগুলোকে (সেকেন্ডে) নির্দেশ করে:

  • ১০ইউ , ১৫ইউ , ৩০ইউ , ৬০ইউ , ১২০ইউ , ১৮০ইউ

ঘণ্টার শব্দ সেটিংস

হোম এপিআই-এর মাধ্যমে ডোরবেল চিমের বিভিন্ন সেটিংস নিয়ন্ত্রণ করা যায়।

ঘণ্টার ধ্বনি পরিবর্তন করুন

ডোরবেলের চিম সাউন্ড পরিবর্তন করতে, প্রথমে Chime ট্রেইটের installedChimeSounds অ্যাট্রিবিউট ব্যবহার করে ডিভাইসটিতে ইনস্টল করা চিম সাউন্ডগুলির তালিকা নিন:

// Get a list of chimes and identify the currently selected one
private val doorbellChimeTraitFlow: Flow =
    device.traitFromType(Chime, GoogleDoorbellDevice)
val chimeSounds = doorbellChimeTraitFlow.first().installedChimeSounds ?: emptyList()

তারপর, বিল্ট-ইন setSelectedChime Kotlin ফাংশনটি ব্যবহার করে Chime ট্রেইটের selectedChime অ্যাট্রিবিউটটি আপডেট করুন:

// Set the chime using the chimeId from the installed list
chimeSounds.firstOrNull { it.name == name }?.let { setSelectedChime(it.chimeId) }

বাহ্যিক ঘণ্টা ব্যবহার করুন

ডোরবেলটি বাড়ির ভেতরে ইনস্টল করা কোনো যান্ত্রিক ঘণ্টার মতো একটি বাহ্যিক ঘণ্টা ব্যবহার করার জন্য কনফিগার করা যেতে পারে। বাহ্যিক ঘণ্টাটির সম্ভাব্য ক্ষতি এড়াতে ডোরবেল ইনস্টলেশনের সময়ই এটি কনফিগার করা উচিত।

কী ধরনের এক্সটার্নাল চাইম ইনস্টল করা আছে তা নির্দেশ করতে, বিল্ট-ইন setExternalChime Kotlin ফাংশনটি ব্যবহার করে Chime ট্রেইটের externalChime অ্যাট্রিবিউটটি ExternalChimeType দ্বারা আপডেট করুন:

// Indicate the external chime is mechanical
chime.update {
  setExternalChime(ChimeTrait.ExternalChimeType.Mechanical)
}

বাহ্যিক ঘণ্টার শব্দের সময়কাল পরিবর্তন করুন

একটি এক্সটার্নাল চাইম কতক্ষণ (সেকেন্ডে) বাজবে, তা হোম এপিআই (Home APIs)-এর মাধ্যমে কনফিগার করা যেতে পারে। যদি এক্সটার্নাল চাইমটি একটি নির্দিষ্ট সময়কাল (chime duration) সমর্থন করে, তবে একজন ব্যবহারকারী এটি কনফিগার করতে চাইতে পারেন।

এখানে নির্ধারিত মানটি বাহ্যিক চাইমটির নিজস্ব বৈশিষ্ট্য এবং এর প্রস্তাবিত শব্দকালের উপর নির্ভর করে।

এক্সটার্নাল চাইমের সময়কাল পরিবর্তন করতে, বিল্ট-ইন setExternalChimeDurationSeconds Kotlin ফাংশনটি ব্যবহার করে Chime ট্রেইটের externalChimeDurationSeconds অ্যাট্রিবিউটটি আপডেট করুন:

// Change the external chime duration
chime.update {
  setExternalChimeDurationSeconds(newDuration.toUShort())
}

একটি চিম থিম সক্রিয় করুন

কিছু ডোরবেলে এমন সুর থাকতে পারে যা ব্যবহারকারীরা কেবল সীমিত সময়ের জন্য ব্যবহার করতে পারেন। উদাহরণস্বরূপ, ছুটির দিন উপলক্ষে নির্দিষ্ট সুর। এগুলোকে চাইম থিম বলা হয়।

কোনো ব্যবহারকারীর জন্য কোন কোন চাইম থিম উপলব্ধ আছে তা দেখতে, একটি টাইমবক্স ফিল্টার তৈরি করুন এবং ChimeThemes ট্রেইট থেকে getAvailableThemes() কমান্ডের ফলাফল ফিল্টার করতে এটি ব্যবহার করুন। এটি থিমের নাম সহ উপলব্ধ থিমগুলির একটি তালিকা ফেরত দেয়।

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে তালিকাটি ফিল্টার করতে হয়। একটি থিমকে সক্রিয় বলে মনে করা হয় যদি বর্তমান সময়টি তার শুরু এবং শেষের সময়ের (যথাক্রমে startTimeSeconds এবং endTimeSeconds মান) মধ্যে থাকে। যদি শুরুর সময় সেট করা না থাকে, তবে এটি একেবারে শুরু থেকে সক্রিয় বলে গণ্য হয়। যদি শেষের সময় সেট করা না থাকে, তবে এটি অনির্দিষ্টকালের জন্য সক্রিয় থাকে। যদি উভয়ই অনুপস্থিত থাকে, তবে থিমটি সর্বদা সক্রিয় থাকে।

// Get themes from the ChimeThemes trait
fun List<ChimeThemesTrait.ThemeStruct>.filterTimeboxedThemes():
    List<ChimeThemesTrait.ThemeStruct> {
  val now = timeSource.instant().epochSecond.toULong()
  return filter { chimeStruct: ChimeThemesTrait.ThemeStruct ->
    val startTime: ULong = chimeStruct.startTimeSeconds.getOrNull() ?: 0UL
    val endTime: ULong = chimeStruct.endTimeSeconds.getOrNull() ?: MAX_VALUE
    startTime <= now && now <= endTime
  }
}

val availableThemes =
  doorbellChimeThemesTraitFlow
    .first()
    .getAvailableThemes()
    .themes
    .filterTimeboxedThemes()

একবার আপনার পছন্দের থিমের নাম, যেমন Christmas , ঠিক হয়ে গেলে, আপনি ChimeThemes ট্রেইটের setSelectedTimeboxedThemeName() ফাংশনটি ব্যবহার করে সেটি নির্বাচন করতে পারেন:

// Select a theme using the ChimeThemes trait
val themeToSelect = "Christmas"
if (themeToSelect in availableThemeNames) {
  doorbellChimeThemesTraitFlow.first().setSelectedTimeboxedThemeName(themeToSelect)
}