סוג המכשיר Camera מיושם באמצעות שלוש תכונות:
PushAvStreamTransport,
שמטפלת בהעברת סטרימינג של אודיו ווידאו באמצעות פרוטוקולים מבוססי-push,
WebRtcLiveView,
שמספקת את היכולת לשלוט בשידורים חיים וב-TalkBack, ו-CameraSnapshot,
שמספקת תמונות ממוזערות של תצוגה מקדימה שנשמרו במטמון וצילום תמונות בשידור חי.
לפני שמשתמשים בתכונות או מנסים לעדכן מאפיינים, תמיד צריך לבדוק אם המכשיר תומך במאפיינים ובפקודות. מידע נוסף זמין במאמר שליטה במכשירים ב-Android.
| Home APIs Device Type | מאפיינים | אפליקציה לדוגמה ב-Kotlin | תרחיש לדוגמה |
|---|---|---|---|
|
מצלמה
מכשיר שמצלם תמונות סטילס או סרטונים. יכול להיות שבמצלמות יש שידורים חיים נגישים, אפשרות לשיחה משני צידי הדלת או זיהוי אירועים. |
מאפיינים נדרשים google PushAvStreamTransport google WebRtcLiveView |
מצלמה |
קבלת מידע בסיסי על מכשיר
הטמעה באפליקציה לדוגמה ל-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
איך מקבלים את הזמן האחרון שבו המכשיר יצר קשר עם הענן
כדי למצוא את הפעם האחרונה שבה המכשיר יצר קשר עם הענן, משתמשים במאפיין 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) }
בדיקת החיבור של מכשיר
הקישוריות של מכשיר נבדקת ברמת סוג המכשיר, כי חלק מהמכשירים תומכים בכמה סוגים של מכשירים. הסטטוס שמוחזר הוא שילוב של סטטוסי הקישוריות של כל המאפיינים במכשיר הזה.
val cameraConnectivity = cameraDevice.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(GoogleCameraDevice).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) } }
ניהול שידור חי
התאמת האיכות של השידור החי עוזרת לבצע אופטימיזציה של השימוש ברוחב הפס בהתאם להקשר הצפייה של הלקוח (לדוגמה, מעבר לרזולוציה נמוכה יותר כשמוצגת משבצת קטנה יותר של תצוגה מקדימה, תצוגת רשת או מצב תמונה בתוך תמונה).
שינוי האיכות באופן דינמי באמצעות המאפיין
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(GoogleCameraDevice) .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(GoogleCameraDevice).trait(WebRtcLiveView).first() ?: return try { trait.changeLiveViewQuality(mediaSessionId, qualityHint) } catch (e: Exception) { // Handle error } }
הפעלה והשבתה של יכולת ההקלטה
כדי להפעיל את יכולת ההקלטה של המצלמה, צריך להעביר את הערך
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() } }
הגדרות הסוללה
אפשר לשלוט בהגדרות שונות של הסוללה באמצעות ממשקי ה-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:
-
supportedRecordingModes– כל המצבים האפשריים -
availableRecordingModes– מצבים שאפשר לבחור -
selectedRecordingMode– המצב הפעיל
// 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.
שינוי כיוון התמונה
אפשר לסובב את הכיוון של התמונה מהמצלמה (הווידאו). אפשר לסובב את הסרטון רק ב-180 מעלות.
כדי לשנות את כיוון התמונה של המצלמה, מעדכנים את המאפיין imageRotation של מאפיין CameraAvStreamManagement באמצעות הפונקציה המובנית setImageRotation Kotlin:
// Change the camera's image orientation val isRotated = false cameraAvStreamManagement.update { setImageRotation(if (isRotated) 180.toUShort() else 0.toUShort()) }
הפעלה או השבתה של ראיית לילה
כדי להפעיל או להשבית את ראיית הלילה במצלמה, משתמשים ב-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
הוצאה משימוש של מכשיר
כדי להסיר מצלמה ממבנה, קוראים לפונקציה
device.decommissionDevice(). במהלך הוצאה משימוש, מוצג למשתמש מסך אישור שמנוהל על ידי Google, עם אזהרה שכל היסטוריית הווידאו שהוקלטה מסביב לשעון, היסטוריית האירועים, הקליפים והנתונים של ספריית הפנים המוכרות יימחקו באופן סופי בכל המבנה.
הוראות מפורטות ודוגמאות קוד מופיעות במאמר בנושא הסרת מכשיר.