מדריך למכשיר פעמון לדלת ב-Android

סוג המכשיר 'פעמון לדלת' מיושם באמצעות שלוש תכונות: ‫PushAvStreamTransport, שמטפלת בהעברת סטרימינג של אודיו ווידאו באמצעות פרוטוקולים מבוססי-push, ‫WebRtcLiveView, שמספקת את היכולת לשלוט בשידורים חיים ובדיבור חוזר, ו-CameraSnapshot, שמספקת תמונות ממוזערות של תצוגה מקדימה שנשמרו במטמון וצילום תמונות בזמן אמת.

לפני שמשתמשים בתכונות או מנסים לעדכן מאפיינים, תמיד צריך לבדוק אם המכשיר תומך במאפיינים ובפקודות. מידע נוסף זמין במאמר שליטה במכשירים ב-Android.

Home APIs Device Type מאפיינים אפליקציה לדוגמה ב-Kotlin תרחיש לדוגמה

פעמון דלת

GoogleDoorbellDevice

home.matter.6006.types.0113

מכשיר שמפעילים באמצעות לחצן מחוץ לדלת, שמשמיע אות קולי או מציג אות חזותי, ומשמש לבקשת תשומת הלב של אדם שנמצא בצד השני של הדלת. יכול להיות שבפעמוני דלת יהיו תכונות נגישות כמו שידורים חיים, תקשורת דו-כיוונית או אירועי זיהוי.

Required Traits
     google PushAvStreamTransport
     google WebRtcLiveView

Doorbell

קבלת מידע בסיסי על מכשיר

   הטמעה באפליקציה לדוגמה ל-Android   

מאפיין 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}")
    }

קבלת מספר סידורי

כדי לקבל את המספר הסידורי של המכשיר, משתמשים בפקודה GetSerialNumber של מאפיין ExtendedBasicInformation. בדוגמה הבאה מוצגת שמירה של המספר הסידורי במשתנה בשם serialNumber:

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

תגובות מהירות אוטומטיות

התכונה 'תשובות מהירות' מאפשרת למשתמש לשלוח הודעה מוגדרת מראש למכשיר פעמון לדלת.

התכונה הזו זמינה רק במכשירי פעמון לדלת. רשימת ההודעות המוגדרות מראש זמינה לאפליקציית השותף, והיא יכולה להציג אותן למשתמש כדי שיבחר מתוכן. אי אפשר לערוך הודעות מוגדרות מראש.

התכונה 'תגובות מהירות' מיושמת באמצעות מאפיין PresetMessage.

איך משמיעים הודעה מוגדרת מראש

כדי להשמיע הודעה מוגדרת מראש, צריך להפעיל את method‏ playPresetMessage ולהעביר לה אחד מערכי המחרוזת שמופיעים במאפיין availablePhraseTypes.

import com.google.home.HomeDevice
import com.google.home.HomeException
import com.google.home.google.GoogleDoorbellDevice
import com.google.home.google.PresetMessage
import kotlinx.coroutines.flow.first

suspend fun playDoorbellPresetMessage(device: HomeDevice, phraseTypeString: String) {
    try {
        // 1. Retrieve the first snapshot of the doorbell device type
        val doorbellDevice = device.type(GoogleDoorbellDevice).first()

        // 2. Extract the PresetMessage trait
        val presetMessageTrait = doorbellDevice.trait(PresetMessage)
        if (presetMessageTrait == null) {
            println("PresetMessage trait is not supported on this doorbell device.")
            return
        }

        // 3. (Optional) Check available phrase types supported by the device
        val availablePhrases = presetMessageTrait.availablePhraseTypes
        if (availablePhrases != null) {
            val phraseTypesList = availablePhrases.map { it.phraseType }
            println("Supported quick response phrases: $phraseTypesList")
        }

        // 4. Send the playPresetMessage command to the doorbell
        presetMessageTrait.playPresetMessage(phraseType = phraseTypeString)
        println("Preset message command sent successfully.")

    } catch (e: HomeException) {
        println("Home API error occurred: ${e.message}")
    } catch (e: Exception) {
        println("Unexpected failure: ${e.message}")
    }
}

הגדרת שפת הדיבור

מגדירים את השפה הפעילה המדוברת של המכשיר ללוקאל ספציפי (לדוגמה, en_US) באמצעות השיטה setActiveLocale של המאפיין LocalizationConfiguration.

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)
}

איך מקבלים את הזמן האחרון שבו המכשיר יצר קשר עם הענן

כדי למצוא את הפעם האחרונה שבה המכשיר יצר קשר עם הענן, משתמשים במאפיין lastContactTimestamp של מאפיין ExtendedGeneralDiagnostics:

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

הגדרות של סוג התושבת של המצלמה

מאפיין Mount מכיל הגדרות של תושבת המצלמה ופרטי סטטוס. אפשר לקרוא מאפיינים כמו מצב ההרכבה, סוג הזיהוי ושם סוג ההרכבה. בנוסף, אפשר להשתמש במאפיין Mount כדי לשנות את הגדרת ברירת המחדל של סוג ההרכבה.

// Get the Mount trait
val mountTrait: Mount = device.getTrait(Mount)

// Read the current mount state and detection type
val mountState = mountTrait.mountState
val mountDetectionType = mountTrait.mountDetectionType

// Read the current mount type name
val mountTypeName = mountTrait.mountTypeName

// Update the mount type override
mountTrait.update {
  setMountTypeOverride(MountTrait.MountTypeOverrideEnum.Official)
}

בדיקת החיבור של מכשיר

הקישוריות של מכשיר נבדקת ברמת סוג המכשיר, כי חלק מהמכשירים תומכים בכמה סוגים של מכשירים. המצב שמוחזר הוא שילוב של מצבי הקישוריות של כל המאפיינים במכשיר הזה.

   הטמעה באפליקציה לדוגמה ל-Android   
val doorbellConnectivity = doorbellDevice.metadata.sourceConnectivity.connectivityState

המצב PARTIALLY_ONLINE עשוי להופיע במקרה של סוגי מכשירים מעורבים כשאין קישוריות לאינטרנט. Matter יכול להיות שמאפיינים רגילים עדיין יהיו אונליין בגלל ניתוב מקומי, אבל מאפיינים מבוססי-ענן יהיו אופליין.

איך מוצאים את כתובת ה-IP של המכשיר

כדי למצוא את כתובת ה-IP של המכשיר, משתמשים במאפיין networkInterfaces של מאפיין המאפיינים GeneralDiagnostics. הכתובות מוחזרות כמערכי בייטים, שאפשר לעצב אותם כמחרוזות 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()

איך מתחילים שידור חי

   הטמעה באפליקציה לדוגמה ל-Android   

כדי להתחיל שידור חי, שולחים את המחרוזת של Session Description Protocol ‏ (SDP) אל ה-method‏ startLiveView() של מאפיין WebRtcLiveView, שמחזיר את WebRtcLiveViewTrait.StartLiveViewCommand.Response עם שלושה ערכים:

  • נתוני ה-SDP של הסשן.
  • משך הסשן בשניות.
  • מזהה הסשן, שאפשר להשתמש בו כדי להאריך את הסשן או לסיים אותו.
‫
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)

הארכת שידור חי

   הטמעה באפליקציה לדוגמה ל-Android   

לשידורים חיים יש משך זמן מוגדר מראש, ולאחר מכן הם מסתיימים. כדי להאריך את משך הזמן של שידור פעיל, צריך לשלוח בקשת הארכה באמצעות השיטה 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
}

הפעלה והפסקה של TalkBack

   הטמעה באפליקציה לדוגמה ל-Android   

כדי להפעיל את TalkBack, קוראים למתודה startTalkback() של מאפיין WebRtcLiveView. כדי להפסיק את הפעולה, משתמשים בפקודה 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)
  }
}

הפעלה והשבתה של יכולת ההקלטה

כדי להפעיל את יכולת ההקלטה של המצלמה, צריך להעביר את הערך TransportStatusEnum.Active לשיטה setTransportStatus() של המאפיין PushAvStreamTransport. כדי להשבית את האפשרות להקלטה, מעבירים את הערך 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
    }
}

שליפת תמונות מצב מהמצלמה

   הטמעה באפליקציה לדוגמה ל-Android   

אפשר להשתמש במאפיין CameraSnapshot כדי לאחזר תמונות סטטיות מהמצלמה. קובצי ה-snapshot האלה שימושיים בכמה תרחישים:

  • כמשבצת placeholder בממשק המשתמש בזמן ששידור חי ב-WebRTC נטען.
  • כתמונה סטטית לתצוגה מקדימה שמשתדרגת לשידור חי אחרי שהמשתמש מקיים אינטראקציה.
  • כבד ציור ברקע כדי לצייר ולהגדיר אזורי פעילות מותאמים אישית.

המאפיין CameraSnapshot מציע שתי דרכים לאחזור תמונות מצב, בהתאם לצורך בתמונת מצב שנשמרה במטמון לצורך רינדור מהיר, או בתמונת מצב חיה על פי דרישה.

קבלת תמונה של תצוגה מקדימה שנשמרה במטמון

תמונת מצב של תצוגה מקדימה היא תמונה שנשמרת במטמון, וערכת ה-SDK יכולה לאחזר אותה בלי להפעיל את המצלמה. זו השיטה הכי מהירה לאחזור תמונה סטטית, והיא אידיאלית לדפי סקירה כללית של מצלמות או לרשתות של לוחות בקרה.

כדי לקבל את תמונת המצב של התצוגה המקדימה, קוראים את מאפיין המאפיין preview_image_url:

// Get a flow of the CameraSnapshot trait
val cameraSnapshotFlow: Flow<CameraSnapshot?> = cameraDevice
  .type(GoogleCameraDevice)
  .trait(CameraSnapshot)

// Get the current trait state
val cameraSnapshot = cameraSnapshotFlow.firstOrNull()
if (cameraSnapshot != null) {
  val previewImageUrl = cameraSnapshot.previewImageUrl
  // Load the preview image from the URL
} else {
  // CameraSnapshot trait not supported on this device
}

בהתאם להגדרות המצלמה ולפעילות שלה, כתובת ה-URL של התצוגה המקדימה מפנה לתמונה במטמון שנוצרה מתוך צילומי וידאו מהזמן האחרון (המסגרת הראשונה מסוג I של קטע הווידאו האחרון) או לתמונת מצב שמועלית על ידי המצלמה באופן תקופתי.

כדי לציין את עדכניות התמונה, ענן Google Home מטמיע כותרת X-Home-Image-Captured-At בתמונה בפורמט JPEG/PNG שמוצגת, בפורמט UTC. אפשר לנתח את הכותרת הזו בצד הלקוח כדי להציג את הגיל של התמונה באפליקציה.

קבלת תמונה עדכנית של השידור החי על פי דרישה

אם אתם רוצים לראות את התצוגה החיה הנוכחית של המצלמה כדי לבצע פעולות מסוימות, כמו הגדרת אזורי פעילות, אתם יכולים לבקש תמונה חיה. הפעלת צילום תמונה בשידור חי גורמת למצלמה להתעורר, לצלם פריים חדש ולהעלות אותו לענן.

כדי לבקש תמונה בזמן אמת, משתמשים בפקודה getLiveSnapshot():

try {
  val response = cameraSnapshot.getLiveSnapshot()
  val snapshotUrl = response.snapshotUrl
  // Load the live snapshot image from the URL
} catch (e: Exception) {
  Log.e("CameraSnapshot", "Failed to get live snapshot: ${e.message}")
}
.

אימות בקשות של תמונות מצב

   הטמעה באפליקציה לדוגמה ל-Android   

כל כתובות ה-URL של התמונות מצביעות על מדיה מאובטחת ונדרש אסימון OAuth 2.0 עבור היקף Home APIs v2. כדי להוריד את התמונות ולעבד אותן, צריך להוסיף את טוקן ה-OAuth כטוקן Bearer בכותרת Authorization של בקשת ה-HTTP.

הדוגמה הבאה מראה איך להגדיר בקשה לאחזור מהרשת מאובטחת להורדת קובץ snapshot:

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * Downloads a snapshot from a URL using an OAuth access token.
 */
suspend fun loadSnapshotImage(urlString: String, oauthToken: String): Bitmap? =
  withContext(Dispatchers.IO) {
    var connection: HttpURLConnection? = null
    try {
      val url = URL(urlString)
      connection = url.openConnection() as HttpURLConnection
      // 1. Configure the HTTP GET request with the Bearer token
      connection.setRequestProperty("Authorization", "Bearer $oauthToken")

      // 2. Fetch the image data
      if (connection.responseCode == HttpURLConnection.HTTP_OK) {
        connection.inputStream.use { inputStream ->
          BitmapFactory.decodeStream(inputStream)
        }
      } else {
        null
      }
    } catch (e: IOException) {
      e.printStackTrace()
      null
    } finally {
      connection?.disconnect()
    }
  }

ניהול שידור חי

התאמת האיכות של השידור החי עוזרת לבצע אופטימיזציה של השימוש ברוחב הפס בהתאם להקשר הצפייה של הלקוח (לדוגמה, מעבר לרזולוציה נמוכה יותר כשמוצגת משבצת קטנה יותר של תצוגה מקדימה, תצוגת רשת או מצב תמונה בתוך תמונה).

שינוי האיכות באופן דינמי באמצעות המאפיין WebRtcLiveView מנהל באופן ספציפי את הרזולוציה של סשן השידור החי הפעיל בלקוח מסוים. ההגדרה הזו לא זהה להגדרה של שימוש ברוחב פס במכשיר ישירות במכשיר, שתשפיע על כל הצופים בו-זמנית ועל האיכות של הקלטות וידאו היסטוריות שנשמרו בענן.

בדוגמה הבאה אפשר לראות איך מאחזרים ומעדכנים את איכות השידור החי במכשיר:

  • אחזור אפשרויות האיכות הנתמכות: קבלת הרזולוציות הזמינות להזרמה שנתמכות במכשיר. הקוד שולח שאילתה למאפיין supportedQualityHints של התכונה WebRtcLiveView בתהליך של סוג המכשיר, ומציג את האיכויות הנתמכות כ-StateFlow שמכיל רשימה של ערכים QualityHint (כמו QUALITY_HINT_SD, ‏ QUALITY_HINT_HD,‏ QUALITY_HINT_FHD, ‏ QUALITY_HINT_QHD או QUALITY_HINT_UHD).

  • שינוי האיכות של השידור החי: בוחרים באפשרות QualityHint כדי לשנות את רזולוציית הסטרימינג של השידור החי הפעיל (לדוגמה, מעבר מאיכות רגילה לאיכות גבוהה). הפונקציה changeQuality פותרת את מאפיין השידור החי של המכשיר וקוראת לפונקציה changeLiveViewQuality עם ההגדרה הפעילה mediaSessionId וההגדרה שנבחרה QualityHint.

// Assuming you have a HomeDevice instance 'device'
val availableQualityHints: StateFlow<List> =
    device.type(GoogleDoorbellDevice)
        .trait(WebRtcLiveView)
        .map { trait -> 
            trait?.supportedQualityHints ?: emptyList() 
        }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

// Assuming you have a HomeDevice instance 'device'
suspend fun changeQuality(mediaSessionId: String, qualityHint: QualityHint) {
    // Get the trait from the device
    val trait = device.type(GoogleDoorbellDevice).trait(WebRtcLiveView).first() ?: return
    try {
        trait.changeLiveViewQuality(mediaSessionId, qualityHint)
    } catch (e: Exception) {
        // Handle error
    }
}

הגדרות הסוללה

אפשר לשלוט בהגדרות שונות של הסוללה באמצעות ממשקי ה-API של Home.

הגדרת העדפה לשימוש בסוללה

הגדרת מאזן האנרגיה מאפשרת לכם לקבוע את האיזון בין חיי הסוללה לבין הביצועים של המכשיר. אפשר ליצור פרופילים שונים של סוללה, כמו 'מורחב', 'מאוזן' ו'ביצועים', ולעבור ביניהם.

כדי להטמיע את התכונה הזו, צריך לעדכן את המאפיין currentEnergyBalance של מאפיין המאפיינים EnergyPreference. המאפיין מקבל אינדקס של מספר שלם שמתאים לפרופיל ספציפי שמוגדר ברשימת energyBalances של המכשיר (לדוגמה, 0 עבור EXTENDED,‏ 1 עבור BALANCED ו-2 עבור PERFORMANCE).

ערך של null במאפיין currentEnergyBalance מציין שהמכשיר משתמש בפרופיל מותאם אישית. זהו מצב קריאה בלבד.

בדוגמה הבאה מוצג מבנה שבו ישתמש המאפיין 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)

הפעלה אוטומטית של מצב החיסכון בסוללה

כדי להגדיר את התכונה הזו, צריך לעדכן את המאפיין currentLowPowerModeSensitivity של המאפיין EnergyPreference. במאפיין הזה משתמשים באינדקס כדי לבחור רמת רגישות. בדרך כלל 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) }
}

קבלת מצב הטעינה של הסוללה

כדי לקבל את מצב הטעינה הנוכחי של המכשיר (טעינה, טעינה מלאה או לא בטעינה), משתמשים במאפיין batChargeState של מאפיין PowerSource.

// 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"
}

קבלת רמת הטעינה

כדי לקבל את רמת הטעינה הנוכחית של הסוללה, משתמשים במאפיין batChargeLevel של מאפיין המשנה PowerSource. הרמה היא 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"
}

איך מקבלים את ספק הכוח

כדי לקבוע את מקור הכוח שבו המכשיר משתמש, צריך להשתמש במאפיינים BatPresent ו-wiredPresent של מאפיין PowerSource.

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

בדיקה אם צריך להחליף את הסוללה

מאפיין batReplaceability מציין אם הסוללה לא ניתנת להחלפה, ניתנת להחלפה על ידי המשתמש או ניתנת להחלפה במפעל.

המאפיין batReplacementNeeded של המאפיין PowerSource מציין אם צריך להחליף את הסוללה.

// Get the battery replacement status
val batteryStatus = powerSourceTrait.batReplacementNeeded

if (batteryStatus) {
  println("Replace the battery.")
}

אם המשתמש יכול להחליף את הסוללה, צריך להשתמש במאפיין batReplacementDescription כדי לתאר את הסוללה, כולל מידע כמו גורם צורה, הרכב כימי ויצרן מומלץ.

הגדרות אודיו

אפשר לשלוט בהגדרות שונות של אודיו באמצעות ממשקי ה-API של Home.

הפעלה או השבתה של המיקרופון

כדי להפעיל או להשבית את המיקרופון של המכשיר, מעדכנים את מאפיין microphoneMuted של מאפיין CameraAvStreamManagement באמצעות פונקציית setMicrophoneMuted Kotlin המובנית:

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

איך מפעילים או משביתים את הקלטת האודיו

כדי להפעיל או להשבית את הקלטת האודיו במכשיר, מעדכנים את המאפיין recordingMicrophoneMuted של מאפיין � באמצעות הפונקציה המובנית setRecordingMicrophoneMuted Kotlin:CameraAvStreamManagement

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

שינוי עוצמת הקול של הרמקול

כדי לשנות את עוצמת הקול של הרמקול במכשיר, מעדכנים את מאפיין speakerVolumeLevel של מאפיין המאפיינים CameraAvStreamManagement באמצעות הפונקציה המובנית setSpeakerVolumeLevel Kotlin:

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

הגדרות של אזור הפעילות

   הטמעה באפליקציה לדוגמה ל-Android   

מאפיין ZoneManagement מספק ממשק לניהול אזורים מותאמים אישית שמעוררים עניין (אזורי פעילות) במצלמות ובמכשירי פעמון לדלת. האזורים האלה משמשים לסינון זיהוי האירועים (כמו תנועה של אנשים או כלי רכב) לאזורים ספציפיים בשדה הראייה של המכשיר.

המשתמש מגדיר אזורי פעילות באפליקציית שותף, וכך יכול לצייר אזורים מעל אזורים ספציפיים בשדה הראייה של המצלמה. אזורי הזמן שהמשתמש מגדיר מתורגמים למבנים שבהם נעשה שימוש בתכונה הזו. מידע נוסף על אזורי פעילות זמין במאמר בנושא הגדרה ושימוש באזורי פעילות.

אזורי פעילות מוגדרים בדרך כלל באמצעות קואורדינטות קרטזיות דו-ממדיות. מאפיין המאפיינים מספק את TwoDCartesianVertexStruct לקודקודים ואת TwoDCartesianZoneStruct להגדרת האזור (שם, קודקודים, צבע ושימוש).

בדיקת אזורי הפעילות

כדי להציג אזורי פעילות, מסמנים את התיבה zones של מאפיין ZoneManagement.

// 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, שכוללת את השם, הקודקודים, הצבע והשימוש של האזור.

בדוגמה הבאה מוצג איך ליצור אזור בשם Front Porch עם ארבע נקודות קודקוד, בצבע סלמון (‎#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)
}

מחיקת אזור פעילות

כדי להסיר אזור, משתמשים בפקודה removeZone עם zoneId ספציפי.

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 (שלוש צפצופים קצרים ואז הפסקה).
התראה של גלאי פחמן חד-חמצני CoAlarm מזהה אזעקות של פחמן חד-חמצני (CO), שבדרך כלל מזוהות לפי דפוס הצליל T4 (ארבעה צפצופים קצרים ואחריהם הפסקה).

בדיקת הסטטוס של זיהוי הצלילים

כדי להציג למשתמש את המצב הנוכחי של זיהוי הקול, צריך לבדוק מה המכשיר תומך ומה מופעל על ידי רכיבי החומרה של המכשיר. שני המאפיינים שצריך לבדוק הם:

בפיתוח ל-Android באמצעות Kotlin Flows, בדרך כלל מתבצעת תצפית על המאפיין AvStreamAnalysis מתוך HomeDevice.

// 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)
}

מצבי הקלטה

   הטמעה באפליקציה לדוגמה ל-Android   

מאפיין RecordingMode מספק ממשק לניהול התנהגות ההקלטה של וידאו ותמונות במצלמות ובמכשירי פעמון לדלת. האפשרות הזו מאפשרת למשתמשים לבחור בין הקלטה רציפה, הקלטה בזמן אירוע (EBR) או השבתה מלאה של ההקלטה (רק בתצוגה בשידור חי).

ההגדרה RecordingModeEnum מגדירה את שיטות ההקלטה הזמינות:

מצב ערך enum תיאור
מושבת Disabled ההקלטה מושבתת לחלוטין. משמש בעיקר במכשירים מדור קודם.
CVR (הקלטת וידאו רציפה) Cvr הווידאו מוקלט 24 שעות ביממה, 7 ימים בשבוע. נדרש מינוי (לדוגמה, Google Home Premium.
EBR (תיעוד מבוסס-אירוע) Ebr ההקלטה מופעלת על ידי אירועים (אדם, תנועה). אורך הסרטון תלוי במשך האירוע ובמינוי.
ETR (הקלטה שמופעלת על ידי אירוע) Etr הקלטה קצרה של תצוגה מקדימה (לדוגמה, 10 שניות) מופעלת על ידי אירועים.
תצוגה חיה 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())
}

הגדרות אחרות

אפשר לשלוט בהגדרות שונות אחרות באמצעות ממשקי ה-API של Home.

הפעלה או השבתה של ראיית לילה

כדי להפעיל או להשבית את ראיית הלילה במצלמה, משתמשים ב-TriStateAutoEnum כדי לעדכן את מאפיין nightVision של מאפיין CameraAvStreamManagement באמצעות פונקציית Kotlin המובנית setNightVision:

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

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

שינוי הבהירות של נורית הסטטוס

כדי לשנות את הבהירות של נורית הסטטוס, משתמשים ב-ThreeLevelAutoEnum כדי לעדכן את מאפיין statusLightBrightness של מאפיין CameraAvStreamManagement באמצעות פונקציית Kotlin המובנית setStatusLightBrightness:

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

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

שינוי מרחק התצוגה של המצלמה

אזור התצוגה של המצלמה זהה לתכונה 'התקרבות וחיתוך' שמתוארת במאמר התמיכה בנושא התקרבות וחיתוך של סרטונים ממצלמת Nest.

ה-viewport מוגדר בתג ViewportStruct שמכיל ארבעה ערכים, שמשמשים כקואורדינטות של ה-viewport. הקואורדינטות מוגדרות כך:

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

הערכים של ViewportStruct תלויים בממשק המשתמש של האפליקציה ובהטמעה של המצלמה. ברמה הבסיסית ביותר, כדי להגדיר את אזור התצוגה של סרטון המצלמה, צריך לעדכן את מאפיין viewport של מאפיין CameraAvStreamManagement באמצעות ViewportStruct, באמצעות פונקציית setViewport Kotlin המובנית:

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(),
    )
) }

הפעלה או השבתה של ניתוח נתונים

כל מכשיר יכול להצטרף בנפרד לשליחת נתוני ניתוח מפורטים אל ענן Google Home (ראו Cloud Monitoring for Home APIs).

כדי להפעיל את האנליטיקה במכשיר, מגדירים את המאפיין analyticsEnabled של ExtendedGeneralDiagnosticsTrait לערך true. כשמגדירים את analyticsEnabled, נכס אחר, logUploadEnabled, מוגדר אוטומטית ל-true, מה שמאפשר להעלות את קובצי יומן הניתוח לענן של Google Home.

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

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

הגדרות של שידור והקלטה

בקטע הזה מוסבר על הגדרות שקשורות לאיכות הסטרימינג מהמצלמה ולהפעלת אירועים. ההגדרות האלה מנוהלות על ידי מאפיין PushAvStreamTransport.

קריאת הגדרות התעבורה

בקטע הזה נסביר איך לאחזר את ההגדרה הנוכחית ממצלמה או ממכשיר Nest Doorbell. הוא מאחזר את מאפיין 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 כדי לשלוח את ההגדרות המעודכנות האלה בחזרה למכשיר, ומחיל אותן על חיבור ההקלטה שנמצא בשלב הקודם.

כדי לשנות את ההגדרות האלה, משתמשים בפקודה modifyPushTransport עם TransportOptionsStruct.

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
    )
}

קביעת איכות רוחב הפס

המאפיין videoStreamId של TransportOptionsStruct תואם להגדרה ספציפית של סטרימינג של וידאו.

כדי לקבל את זרמי הווידאו הנתמכים, צריך לעיין במאפיין allocatedVideoStreams, שהוא רשימה של VideoStreamStructs. מה-trait‏ CameraAvStreamManagement של המכשיר.

שינוי הרגישות של היציאה ממצב שינה במכשיר

המאפיין motionSensitivity של TransportTriggerOptionsStruct תואם לערכים הבאים:

תווית ערך (UByte)
נמוכה ‫1u
בינונית ‫5u
גבוהה ‫10u

שינוי האורך המקסימלי של אירוע

המאפיין maxDuration של TransportMotionTriggerTimeControlStruct מתאים למשכי הזמן הבאים (בשניות):

  • ‫10u, ‏ 15u, ‏ 30u, ‏ 60u, ‏ 120u, ‏ 180u

הגדרות של Chime

אפשר לשלוט בהגדרות שונות של צלצול בדלת דרך ממשקי ה-API של Home.

שינוי הצליל של מנגנון הצלצול

כדי לשנות את צליל הפעמון בדלת, קודם צריך לקבל את רשימת הצלילים שמותקנים במכשיר באמצעות המאפיין installedChimeSounds של מאפיין התכונה Chime:

// 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()

לאחר מכן, מעדכנים את מאפיין selectedChime של מאפיין Chime באמצעות הפונקציה המובנית setSelectedChime Kotlin:

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

שימוש במנגנון צלצול חיצוני

   הטמעה באפליקציה לדוגמה ל-Android   

אפשר להגדיר את פעמון הדלת כך שישתמש במנגנון צלצול חיצוני, כמו פעמון מכני שמורכב בתוך הבית. צריך להגדיר את זה במהלך ההתקנה של פעמון הדלת כדי למנוע נזק פוטנציאלי לפעמון החיצוני.

כדי לציין איזה סוג של מנגנון צלצול חיצוני מותקן, צריך להשתמש ב-ExternalChimeType כדי לעדכן את מאפיין externalChime של מאפיין Chime באמצעות פונקציית Kotlin המובנית setExternalChime:

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

שינוי משך הצלצול החיצוני

אפשר להגדיר את משך הצלצול בשניות של פעמון חיצוני באמצעות ממשקי ה-API של Home. אם מנגנון הצלצול החיצוני תומך בהגדרת משך הצליל, המשתמש יכול להגדיר אותו.

הערך שמוגדר כאן תלוי במפרט של מנגנון הצלצול החיצוני עצמו, ובמשך הצלצול המומלץ שלו.

כדי לשנות את משך הצלצול החיצוני, מעדכנים את המאפיין externalChimeDurationSeconds של מאפיין Chime באמצעות הפונקציה המובנית setExternalChimeDurationSeconds Kotlin:

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

הפעלת עיצוב של צליל התראה

   הטמעה באפליקציה לדוגמה ל-Android   

יכול להיות שלחלק ממצלמות הפעמון יש צלילים שזמינים למשתמשים רק לזמן מוגבל. לדוגמה, צלצולים שמתאימים לחגים ספציפיים. הצלילים האלה נקראים ערכות נושא של צלצול.

כדי לראות אילו ערכות נושא של צלצול זמינות למשתמש, יוצרים מסנן של תיבת זמן ומשתמשים בו כדי לסנן את התוצאות של הפקודה getAvailableThemes() מהמאפיין ChimeThemes. הפעולה הזו מחזירה רשימה של ערכות נושא זמינות, כולל שמות ערכות הנושא.

בדוגמה הבאה אפשר לראות איך מסננים את הרשימה. עיצוב נחשב פעיל אם השעה הנוכחית חלה בין שעת ההתחלה לשעת הסיום שלו (הערכים 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, אפשר לבחור אותו באמצעות הפונקציה setSelectedTimeboxedThemeName() במאפיין ChimeThemes:

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

הגדרות של הכרזה על הגעת אורחים

אפשר לשלוח שאילתות ולנהל את ההגדרות של ההודעות על הגעת אורחים בפעמוני דלת באמצעות מאפיין VisitorAnnouncement של Home APIs. התכונה הזו קובעת אם הנוכחות של מבקר תוכרז ברמקולים או במסכים חכמים של Google כשמישהו מצלצל בפעמון הדלת.

בדוגמה הבאה אפשר לראות איך בודקים אם ההגדרה 'הכרזה על הגעת אורחים' מופעלת, ואיך מעדכנים את ההגדרה הזו:

// Read the current visitor announcements state
val isEnabled = visitorAnnouncementTrait.visitorAnnouncementsEnabled

// Toggle the visitor announcements setting
visitorAnnouncementTrait.update {
    setVisitorAnnouncementsEnabled(true)
}

הוצאה משימוש של מכשיר

כדי להסיר פעמון דלת ממבנה, מתקשרים אל device.decommissionDevice(). במהלך הוצאה משימוש, מוצג למשתמש מסך אישור שמנוהל על ידי Google, עם אזהרה שכל היסטוריית הווידאו שהוקלטה מסביב לשעון, היסטוריית האירועים, הקליפים והנתונים של ספריית הפנים המוכרות יימחקו באופן סופי בכל המבנה.

הוראות מפורטות ודוגמאות קוד מופיעות במאמר בנושא הסרת מכשיר.